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


Calendar

mars 2024
L Ma Me J V S D
« fév    
 123
45678910
11121314151617
18192021222324
25262728293031

Most Recent Posts