StackWatcher
décembre 29th, 2006 at 05:41 admin
Plop, c’est les vacances et IvanleMad ne peut s’arrêter de coder, toujours en
quête de satisfation personnelle, la masturbation ne lui suffit plus il doit
coder, toujours plus vite, toujours plus loin, toujours plus profond.
Ainsi dans ces pérégrinations il jouait avec le fameux tools de Mark
Russinovitch, Process Explorer, et tombe sur une fonction permettant de voir la
pile d’appel d’un Thread, son esprit commenca à entré en éruption. « Comment ce
put1 de b4t@rd de ca race de programme fonctionne ffs ?! ». Cet ainsi qu’il
décida à reverse l’irréversible (O_o).
Effectivement après cette superbe intro réalisée par mon Dr Hide, je vous
propose un tool, codé par mes soins. Son objectif ! Etre capable de lire la
mémoire d’un autre process afin de parcourir la pile de chaque thread et d’y
retrouver les fonctions utilisées. Cela paraît dingue mais c’est faisable, si le
tool du ruskoff est capable de le faire alors pourquoir pas le mien :]
Bon en lisant la doc des API d’aide au débuggage je suis tombé sur
StackWalk64(), une API permettant de retrouver les appels à partir de la pile,
il suffit de lui donner un HANDLE sur le process, un autre sur le Thread stopé
au préalable, quelques infos sur l’état du Thread et hop (burp!) elle se
débrouille pour nous retrouver les saved eip, W00t.
Comme c’est nowel je me suis que c’etait bien joli d’avoir les addr d’appel,
mais que ca serait encore mieux d’avoir les noms de ces fonctions. Le programme
utilise donc les symbols, fournit par MS, qui doivent être downloader sur son
site avec les debugings tools, ici :
http://www.microsoft.com/whdc/devtools/debugging/default.mspx
Je peux vous dire que cela ma pas prit la tête pour faire marcher ce petit bout
de code, la doc sur le net n’étant pas foisonnante ….
————CUT HERE——————–
#include <windows.h> #include <tlhelp32.h> #include <dbghelp.h> #include <stdio.h> #pragma comment (lib, "advapi32.lib") #pragma comment (lib, "dbghelp.lib") int NameToPid(char *ProcessName) { HANDLE hProcessSnap; PROCESSENTRY32 pe32; hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); if(hProcessSnap==INVALID_HANDLE_VALUE) { printf("Error with CreateToolhelp32Snapshot: 0x%xn",GetLastError() ); } pe32.dwSize = sizeof(PROCESSENTRY32); if( !Process32First(hProcessSnap, &pe32 )) { printf("Error with Process32First: %dn",GetLastError()); CloseHandle(hProcessSnap); } while(Process32Next(hProcessSnap,&pe32)!=0) { if(_stricmp(pe32.szExeFile,ProcessName)==0) //_stricmp fuck la case sensitive { CloseHandle(hProcessSnap); return pe32.th32ProcessID; } } CloseHandle(hProcessSnap); return 0; } DWORD EnablePrivilege(char *Privilege) { HANDLE hToken; DWORD Ret=1; TOKEN_PRIVILEGES TP; LUID Luid; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { printf("Error with OpenProcessToken: %dn", GetLastError()); Ret=0; goto bye; } if(!LookupPrivilegeValue(NULL, Privilege, &TP.Privileges[0].Luid)) { printf("Error with LookupPrivilegeValue: %dn", GetLastError()); Ret=0; goto bye; } TP.PrivilegeCount=1; TP.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges(hToken, false, &TP, NULL, NULL, NULL)) { printf("Error with AdjustTokenPrivileges: %dn", GetLastError()); Ret=0; goto bye; } bye: if(hToken) CloseHandle(hToken); return Ret; } int main(int argc, char * argv[]) { HANDLE hProcess, hThread, hThreadSnap; DWORD PID, TID; DWORD64 Displacement; THREADENTRY32 Th32; STACKFRAME64 StackFrame; IMAGEHLP_MODULE64 IM; CONTEXT Context; PSYMBOL_INFO pSI; SymSetOptions(SYMOPT_UNDNAME|SYMOPT_DEFERRED_LOADS); RtlSecureZeroMemory(&Th32, sizeof(THREADENTRY32)); RtlSecureZeroMemory(&IM, sizeof(IMAGEHLP_MODULE64)); IM.SizeOfStruct=sizeof(IMAGEHLP_MODULE64); if(argc!=2) return 0; PID=NameToPid(argv[1]); if(!PID) { printf("Error with NameToPid : %dn", GetLastError()); return 0; } //pour les process system EnablePrivilege("SeDebugPrivilege"); hProcess=OpenProcess(PROCESS_VM_OPERATION| PROCESS_VM_WRITE| PROCESS_VM_READ| PROCESS_CREATE_THREAD| PROCESS_QUERY_INFORMATION, FALSE, PID); if(!hProcess) { printf("Error with OpenProcess : %dn", GetLastError()); goto cleanup; } /* fInvadeProcess [in] If this value is TRUE, enumerates the loaded modules for the process and effectively calls the SymLoadModule64 function for each module. */ if(!SymInitialize(hProcess, NULL, true)) { printf("Error with SymInitialize : %xn", GetLastError()); goto cleanup; } hThreadSnap=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0); Th32.dwSize=sizeof(THREADENTRY32); if(!Thread32First(hThreadSnap,&Th32)) { printf("Error with Thread32First : %dn", GetLastError()); goto cleanup; } //on se place sur le 1er thread de notre process while(Th32.th32OwnerProcessID!=PID) Thread32Next(hThreadSnap,&Th32); pSI=(PSYMBOL_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SYMBOL_INFO)+MAX_SYM_NAME); if(!pSI) goto cleanup; //tant que le thread appartient au process while(Th32.th32OwnerProcessID==PID) { TID=Th32.th32ThreadID; printf("nThread ID : %dn", TID); RtlSecureZeroMemory(pSI, sizeof(SYMBOL_INFO)+MAX_SYM_NAME); pSI->SizeOfStruct=sizeof(SYMBOL_INFO); pSI->MaxNameLen=MAX_SYM_NAME; RtlSecureZeroMemory(&Context, sizeof(CONTEXT)); //EIP, EBP, ESP Context.ContextFlags=CONTEXT_CONTROL; RtlSecureZeroMemory(&StackFrame, sizeof(STACKFRAME64)); hThread=OpenThread(THREAD_QUERY_INFORMATION|THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, false, TID); if(!hThread) { printf("Error with OpenThread : %dn", GetLastError()); goto cleanup; } //met en pause le thread SuspendThread(hThread); if(!GetThreadContext(hThread, &Context)) { printf("Error with GetThreadContext : %dn", GetLastError()); goto cleanup; } StackFrame.AddrPC.Offset=Context.Eip; StackFrame.AddrPC.Mode=AddrModeFlat; StackFrame.AddrFrame.Offset=Context.Ebp; StackFrame.AddrFrame.Mode=AddrModeFlat; StackFrame.AddrStack.Offset=Context.Esp; StackFrame.AddrStack.Mode=AddrModeFlat; StackFrame.AddrReturn.Mode=AddrModeFlat; /* printf("Eip : 0x%xn", Context.Eip); printf("Esp : 0x%xn", Context.Esp); printf("Ebp : 0x%xn", Context.Ebp); */ //parcourt la pile do { //printf("AddrReturn : 0x%xn", StackFrame.AddrReturn.Offset); //va fouiller la stack if(!StackWalk64(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, &Context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { // Note that StackWalk64 generally does not set the last error code. printf("Error with StackWalk"); //return 0; } if(SymFromAddr(hProcess, (DWORD)StackFrame.AddrReturn.Offset, &Displacement, pSI)) { if(SymGetModuleInfo64(hProcess, pSI->ModBase, &IM)) printf("0x%x : %s!%s+0x%xn",(DWORD)pSI->Address, IM.ModuleName, pSI->Name, Displacement); } //else //printf("Error with SymFromAddr : %dn", GetLastError()); }while(StackFrame.AddrReturn.Offset!=0); //relance le thread ResumeThread(hThread); CloseHandle(hThread); Thread32Next(hThreadSnap,&Th32); } cleanup: if(hProcess) CloseHandle(hProcess); SymCleanup(hProcess); return 0; }
————CUT HERE——————–
A l’utilisation ca donne :
C:ProgHackc>StackWatcher cmd.exe Thread ID : 392 0x7c91e9b4 : ntdll!ZwWaitForSingleObject+0xc 0x7c802540 : kernel32!WaitForSingleObjectEx+0xa8 0x7c802520 : kernel32!WaitForSingleObject+0x12 0x4ad02cf4 : CMD!WaitProc+0x18 0x4ad02ff8 : CMD!ExecPgm+0x3fa 0x4ad02d42 : CMD!ECWork+0x84 0x4ad02dcb : CMD!ExtCom+0x40 0x4ad0145d : CMD!FindFixAndRun+0xcf 0x4ad01375 : CMD!Dispatch+0x137 0x4ad03ff1 : CMD!main+0x216 0x4ad05056 : CMD!mainCRTStartup+0x125 0x7c816fb4 : kernel32!BaseProcessStart+0x23
Impressive n’est-il pas ? :}
L’intéret ca peut être de savoir par ou est passé un code pour éxecuté une
action. Dans l’exemple suivant j’ai mit un BP sur l’API native ZwCreateProcessEx
qui vous vous en doutez sert a crée à process, je l’ai mit dans explorer.exe,
donc quand je vais lancer un process le programme va être stopé par le
breakpoint et si on lance StackWatcher on peut voir :
[...] Breakpoint sur ZwCreateProcessEx de ntdll.dll l'api native qui call le noyau pour lancer un process Thread ID : 2008 0x7c819513 : kernel32!CreateProcessInternalW+0x1327 0x7c802332 : kernel32!CreateProcessW+0x2c 0x7ca11f93 : SHELL32!_SHCreateProcess+0x387 0x7ca11e7a : SHELL32!CShellExecute::_DoExecCommand+0xb4 0x7ca11e21 : SHELL32!CShellExecute::_TryInvokeApplication+0x49 0x7ca118b9 : SHELL32!CShellExecute::ExecuteNormal+0xb1 0x7ca11866 : SHELL32!ShellExecuteNormal+0x30 0x7ca117cb : SHELL32!ShellExecuteExW+0x8d 0x7ca1e4e4 : SHELL32!_InvokePidl+0x9f 0x7ca1e421 : SHELL32!CShellExecMenu::_InvokeOne+0xa0 0x7ca1e347 : SHELL32!CShellExecMenu::InvokeCommand+0xa7 0x7ca1e2ad : SHELL32!HDXA_LetHandlerProcessCommandEx+0xa5 0x7ca1e1b5 : SHELL32!CDefFolderMenu::InvokeCommand+0x17f 0x7ca300b2 : SHELL32!CShellLink::TargetContextMenu::InvokeCommand+0x22 0x7ca2fe91 : SHELL32!CShellLink::_InvokeCommandAsync+0x337 0x7ca2fe57 : SHELL32!CShellLink::InvokeCommand+0x259 0x7ca1e2ad : SHELL32!HDXA_LetHandlerProcessCommandEx+0xa5 0x7ca1e1b5 : SHELL32!CDefFolderMenu::InvokeCommand+0x17f 0x77f98355 : SHLWAPI!SHInvokeCommandsOnContextMenu+0x174 0x77f9926d : SHLWAPI!SHInvokeCommand+0x63 0x77f9932d : SHLWAPI!SHInvokeDefaultCommand+0x15 0x102c9a0 : explorer!CStartMenuHost::ExecItem+0x17 0x7cb6d9d7 : SHELL32!CStartMenuCallback::_ExecItem+0x17 0x7cb6f32e : SHELL32!CStartMenuCallback::CallbackSM+0xe0 0x7ca23edd : SHELL32!CMenuSFToolbar::CallCB+0xd9 0x7cba7520 : SHELL32!CMenuSFToolbar::v_ExecItem+0x8e 0x7cba40bf : SHELL32!CMenuToolbarBase::_DropDownOrExec+0xa6 0x7ca24a04 : SHELL32!CMenuToolbarBase::_OnNotify+0x2bf 0x7ca24401 : SHELL32!CMenuSFToolbar::_OnNotify+0x109 0x7ca2439a : SHELL32!CMenuToolbarBase::OnWinEvent+0x60 0x7ca2435a : SHELL32!CMenuSFToolbar::OnWinEvent+0x6b 0x7ca2428f : SHELL32!CMenuBand::OnWinEvent+0x1f8 0x7ca24159 : SHELL32!CMenuSite::v_WndProc+0xd9 0x7ca30e35 : SHELL32!CImpWndProc::s_WndProc+0x65 0x77d1870c : USER32!InternalCallWinProc+0x28 0x77d1875f : USER32!UserCallWinProcCheckWow+0x150 0x77d1b7d3 : USER32!SendMessageWorker+0x4a5 0x77d1b8ba : USER32!SendMessageW+0x7f 0x773aa3d1 : comctl32!CCSendNotify+0xc20 0x773ff831 : comctl32!TBSendUpClick+0x5f 0x77404778 : comctl32!TBOnLButtonUp+0x13b 0x77404bdb : comctl32!ToolbarWndProc+0xb30 0x77d1870c : USER32!InternalCallWinProc+0x28 0x77d1875f : USER32!UserCallWinProcCheckWow+0x150 0x77d1c5ee : USER32!CallWindowProcAorW+0x98 0x77d1c64a : USER32!CallWindowProcW+0x1b 0x773a1b3d : comctl32!CallOriginalWndProc+0x1a 0x773a1e6e : comctl32!CallNextSubclassProc+0x3c 0x773a2026 : comctl32!DefSubclassProc+0x46 0x7ca0ef96 : SHELL32!CSFToolbar::_DefWindowProc+0xb8 0x7ca0ef46 : SHELL32!CNotifySubclassWndProc::_SubclassWndProc+0x7d 0x773a1e6e : comctl32!CallNextSubclassProc+0x3c 0x773a207b : comctl32!MasterSubclassProc+0x54 0x77d1870c : USER32!InternalCallWinProc+0x28 0x77d1875f : USER32!UserCallWinProcCheckWow+0x150 0x77d188f1 : USER32!DispatchMessageWorker+0x306 0x77d18a01 : USER32!DispatchMessageW+0xf 0x100199d : explorer!CTray::_MessageLoop+0xd9 0x1011e62 : explorer!CTray::MainThreadProc+0x29 0x77f5422b : SHLWAPI!WrapperThreadProc+0x94 0x7c80b64c : kernel32!BaseThreadStart+0x37 Thread Id : XXX [...]
Ouf ca fait de la peur :]
En tout cas je pense qu’il y moyen de bien s’amuser avec ce tools on peut
apprendre de bonne chose sur le fonctionnement de certains binaire system. Par
contre mieux vaut avoir les symbols pour ceux-ci si vous voulez des résultats
probants.
Enfin en reversant Process Explorer j’ai remarqué que le mofo utilisait un
driver afin de lire aussi la pile d’appel du thread dans le noyau, je suis
en train de continuer le combat afin que mon code le fasse aussi. Il m’a fallut
reverser le binaire, dumper le driver, reverse le driver …Bref ca ma bien
prit la tete pour capter le bordel. Je suis en train de recoder un tool qui
reprend son fonctionnement mais code est over crade, avec des bouts d’asm
partout et du DeviceIoControl() à la pelle donc celui la ca m’etonnerais que je le montre :]
En attendant vous avez de quoi vous amuser. Je vous file un .rar avec le binaire
les sources et les dll requises, enjoy !
http://membres.lycos.fr/moi118118/StackWatcher.rar
Ivanlef0u
« je te fist comme ca, comme ca et comme ca ! »
Entry Filed under: Non classé
1 Comment
1. shiroko | décembre 30th, 2006 at 14:02
Putain çà fait plaisir de voir des gr0s g33k n0 l1f3 sur Windows ! =)
GG ton code, j’ai rien pigé
Ps : Je continue à dire que en rose ton blog te ressemblerait plus m’enfin bon …
Trackback this post