MyAPITracer
Dernièrement j’ai consacré mon temps à coder un petit tool pour me simplifier la vie, il s’agit d’un traceur d’API ring 3 utilisant les symboles de debug pour récupérer des informations sur les noms des fonctions utilisées par le programme et leurs arguments. L’idée est de mettre sur le prologue de chacunes des fonctions exportées par les DLL un breakpoint (int 3), de lancer le process puis de gérer les exceptions, si on tombe sur une EXCEPTION_DEBUG_EVENT alors on affiche le nom de la fonction qui la généré et on relance le thread. Dans la théorie ca parait simple après c’est un peu plus compliqué, disons que avoir un tool complètement opérationnel va me demander pas mal de taff et que pour l’instant j’arrive à le faire tourner sur des programmes assez basiques.
Le mieux est de montrer ce tool balance pour l’instant. Le code qui sera utilisé est celui-ci :
//systeminfo.c #include <windows.h> #include <stdio.h> int main(int argc, char * argv[]) { SYSTEM_INFO SystemInfo; GetSystemInfo(&SystemInfo); printf("lpMinimumApplicationAddress : 0x%xn", SystemInfo.lpMinimumApplicationAddress); printf("lpMaximumApplicationAddress : 0x%xn", SystemInfo.lpMaximumApplicationAddress); return 0; }
Il permet d’obtenir les adresses hautes et basses du Userland, on obtient comme adresse minumum 0×10000 et comme adresse max 0x7ffeffff. Le binaire à été compilé avec le flag /DEBUG et le linker nous à aussi généré un joli .pdb contenant les informations de debug de notre programme.
Maitenant je lance mon petit tool dessus :
****STARTING DEBUGEE**** EntryPoint : 0x402337 Number of modules: 3 Base : 0x7c800000 NumberOfFunctions : 949 NumberOfNames : 949 ****STARTING LOGGING**** Call From : 0x40235d : systeminfo!mainCRTStartup+0x26 0x7c8111da : kernel32!GetVersion Call From : 0x403938 : systeminfo!_heap_init+0x11 0x7c812bb6 : kernel32!HeapCreate Call From : 0x403fe2 : systeminfo!_mtinitlocks+0x9 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x403fea : systeminfo!_mtinitlocks+0x11 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x403ff2 : systeminfo!_mtinitlocks+0x19 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x403ffa : systeminfo!_mtinitlocks+0x21 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x403795 : systeminfo!_mtinit+0x6 0x7c812d9f : kernel32!TlsAlloc Call From : 0x4054b5 : systeminfo!__sbh_alloc_new_region+0x76 0x7c809a51 : kernel32!VirtualAlloc Call From : 0x7c809a64 : kernel32!VirtualAlloc+0x13 0x7c809a72 : kernel32!VirtualAllocEx Call From : 0x405541 : systeminfo!__sbh_alloc_new_group+0x51 0x7c809a51 : kernel32!VirtualAlloc Call From : 0x7c809a64 : kernel32!VirtualAlloc+0x13 0x7c809a72 : kernel32!VirtualAllocEx Call From : 0x4037bd : systeminfo!_mtinit+0x2e 0x7c809bc5 : kernel32!TlsSetValue Call From : 0x4037ce : systeminfo!_mtinit+0x3f 0x7c809728 : kernel32!GetCurrentThreadId Call From : 0x4035dd : systeminfo!_ioinit+0x5e 0x7c801eee : kernel32!GetStartupInfoA Call From : 0x4036eb : systeminfo!_ioinit+0x16c 0x7c812f39 : kernel32!GetStdHandle Call From : 0x4036f9 : systeminfo!_ioinit+0x17a 0x7c810e51 : kernel32!GetFileType Call From : 0x7c810e8e : kernel32!GetFileType+0x3d 0x7c81aeaa : kernel32!VerifyConsoleIoHandle Call From : 0x4036eb : systeminfo!_ioinit+0x16c 0x7c812f39 : kernel32!GetStdHandle Call From : 0x4036f9 : systeminfo!_ioinit+0x17a 0x7c810e51 : kernel32!GetFileType Call From : 0x7c810e8e : kernel32!GetFileType+0x3d 0x7c81aeaa : kernel32!VerifyConsoleIoHandle Call From : 0x4036eb : systeminfo!_ioinit+0x16c 0x7c812f39 : kernel32!GetStdHandle Call From : 0x4036f9 : systeminfo!_ioinit+0x17a 0x7c810e51 : kernel32!GetFileType Call From : 0x7c810e8e : kernel32!GetFileType+0x3d 0x7c81aeaa : kernel32!VerifyConsoleIoHandle Call From : 0x403730 : systeminfo!_ioinit+0x1b1 0x7c80cc97 : kernel32!SetHandleCount Call From : 0x4023bc : systeminfo!mainCRTStartup+0x85 0x7c812f1d : kernel32!GetCommandLineA Call From : 0x403464 : systeminfo!__crtGetEnvironmentStringsA+0x17 0x7c812f08 : kernel32!GetEnvironmentStringsW Call From : 0x4034dc : systeminfo!__crtGetEnvironmentStringsA+0x8f 0x7c80a0d4 : kernel32!WideCharToMultiByte Call From : 0x4034fe : systeminfo!__crtGetEnvironmentStringsA+0xb1 0x7c80a0d4 : kernel32!WideCharToMultiByte Call From : 0x40351b : systeminfo!__crtGetEnvironmentStringsA+0xce 0x7c814ae7 : kernel32!FreeEnvironmentStringsW Call From : 0x4040ab : systeminfo!_lock+0x3d 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x404653 : systeminfo!_setmbcp+0x13 0x7c809915 : kernel32!GetACP Call From : 0x404691 : systeminfo!_setmbcp+0x51 0x7c812e76 : kernel32!GetCPInfo Call From : 0x4048a7 : systeminfo!_setmbcp+0x267 0x7c812e76 : kernel32!GetCPInfo Call From : 0x406cbe : systeminfo!__crtGetStringTypeA+0x3f 0x7c80a490 : kernel32!GetStringTypeW Call From : 0x406d44 : systeminfo!__crtGetStringTypeA+0xc5 0x7c809bf8 : kernel32!MultiByteToWideChar Call From : 0x406d9a : systeminfo!__crtGetStringTypeA+0x11b 0x7c809bf8 : kernel32!MultiByteToWideChar Call From : 0x406dac : systeminfo!__crtGetStringTypeA+0x12d 0x7c80a490 : kernel32!GetStringTypeW Call From : 0x406a72 : systeminfo!__crtLCMapStringA+0x42 0x7c80cca8 : kernel32!LCMapStringW Call From : 0x406b0f : systeminfo!__crtLCMapStringA+0xdf 0x7c809bf8 : kernel32!MultiByteToWideChar Call From : 0x406b67 : systeminfo!__crtLCMapStringA+0x137 0x7c809bf8 : kernel32!MultiByteToWideChar Call From : 0x406b7d : systeminfo!__crtLCMapStringA+0x14d 0x7c80cca8 : kernel32!LCMapStringW Call From : 0x406c18 : systeminfo!__crtLCMapStringA+0x1e8 0x7c80cca8 : kernel32!LCMapStringW Call From : 0x406c3d : systeminfo!__crtLCMapStringA+0x20d 0x7c80a0d4 : kernel32!WideCharToMultiByte Call From : 0x406b0f : systeminfo!__crtLCMapStringA+0xdf 0x7c809bf8 : kernel32!MultiByteToWideChar Call From : 0x406b67 : systeminfo!__crtLCMapStringA+0x137 0x7c809bf8 : kernel32!MultiByteToWideChar Call From : 0x406b7d : systeminfo!__crtLCMapStringA+0x14d 0x7c80cca8 : kernel32!LCMapStringW Call From : 0x406c18 : systeminfo!__crtLCMapStringA+0x1e8 0x7c80cca8 : kernel32!LCMapStringW Call From : 0x406c3d : systeminfo!__crtLCMapStringA+0x20d 0x7c80a0d4 : kernel32!WideCharToMultiByte Call From : 0x403223 : systeminfo!_setargv+0x23 0x7c80b4cf : kernel32!GetModuleFileNameA Call From : 0x7c80b508 : kernel32!GetModuleFileNameA+0x39 0x7c80b3d5 : kernel32!GetModuleFileNameW Call From : 0x4022ba : systeminfo!main+0xa 0x7c812d56 : kernel32!GetSystemInfo Call From : 0x7c812d3b : kernel32!GetProcessVersion+0x118 0x7c812c23 : kernel32!GetProcessVersion Call From : 0x4040ab : systeminfo!_lock+0x3d 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x407554 : systeminfo!_lock_fhandle+0x3d 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x406149 : systeminfo!_write_lk+0xc7 0x7c810d87 : kernel32!WriteFile Call From : 0x7c81cf4c : kernel32!WriteConsoleA+0x27 0x7c81cf25 : kernel32!WriteConsoleA Call From : 0x406149 : systeminfo!_write_lk+0xc7 0x7c810d87 : kernel32!WriteFile Call From : 0x7c81cf4c : kernel32!WriteConsoleA+0x27 0x7c81cf25 : kernel32!WriteConsoleA Call From : 0x4040ab : systeminfo!_lock+0x3d 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x4040ab : systeminfo!_lock+0x3d 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x4040ab : systeminfo!_lock+0x3d 0x7c809ef1 : kernel32!InitializeCriticalSection Call From : 0x402f9b : systeminfo!_c_exit+0xac 0x7c81cdda : kernel32!ExitProcess Process Exited
Remarquez que je ne loggue pas les appels aux fonctions de ntdll. On voit que la CRT (C RunTime) bouffe la majorité du log pour pas dire grand chose d’utile et qu’au final le code se résume en fait à :
Pour la fonction GetSystemInfo:
Call From : 0x4022ba : systeminfo!main+0xa
0x7c812d56 : kernel32!GetSystemInfo
et pour printf:
Call From : 0×406149 : systeminfo!_write_lk+0xc7
0x7c810d87 : kernel32!WriteFile
Call From : 0x7c81cf4c : kernel32!WriteConsoleA+0×27
0x7c81cf25 : kernel32!WriteConsoleA
En fait ce tool se raproche un peu d’un strace sous nux, sauf qu’ici on loggue tous les appels aux API et pas uniquement les appels système.
Alors je sais, vous allez me dire que ce genre d’outils existe déjà, certes c’est vrai, mais combien utilisent les symboles de débuggage pour obtenir les noms des fonctions ? La plupart de ceux que j’ai vu comme le logger.exe des Debugging Tools for Windows utilisent une database à coté pour parser leurs informations. Avec les symboles on est sur d’avoir des infos à la fois sur notre programme (si celui-ci est compilé en debug) et sur les fonctions des DLL.
Développe ce tool commence à me prendre un peu la tête, je releaserais le binaire quand je l’aurais amélioré, par contre je garde les sources pour moi, le code étant tellement crade que même un moine tibétain défoncé au beurre de yack ne pourrait le comprendre.
En attendant voiçi un lien sur un topic d’OpenRCE causant des outils de monitoring pour Win, si jamais vous cherchez un tool du même genre vous y trouverez votre bonheur :
http://www.openrce.org/forums/posts/274
2 comments mars 8th, 2007