Microsoft Windows
Debugger (WinDbg) Windbg
est un debugger developpé par Microsoft et distribué gratuitement sur
leur site. WinDbg possède de nombreuses fonctions (comme debug du kernel, debugging a partir d'un server, etc..) je ne rentrerais pas dans ces fonctionnalités inutiles pour le cracking standard d'une application. Je vous conseille de lire l'aide très complète de WinDbg dans laquelle vous pourrez trouver toutes les commandes et options. L'interface Graphique WinDbg est composé de plusieurs fenetres que l'on peux afficher via le Menu View ou à partir de la barre d'outils. The
Command Window (Command - ALT+1) : The
Watch Window (Watch - ALT+2) : The
Locals Window (Locals - ALT+3) : The
Registers Window (Registers - ALT+4) : The
Memory Window (Memory - ALT+5) : The
Calls Window (Call Stack - ALT+6) : The
Disassembly Window (Disassembly - ALT+7) : The
Scratch Pad (Scratch Pad - ALT+8) : Libre à vous de personnaliser l'affichage de ces fenêtres et de customiser les couleurs et les options de police à partir du Menu View, voici un petit apercu en seance de debugging: Lancement de la cible On sélectionne la cible que l'on veut debugger par le menu par File / Open Executable, on peut aussi attacher un process tournant déja en mémoire par File / Attach to a Process. Après ouverture dans la fenetre de commande vous devriez obtenir à peu pres ceci: Symbol search path
is: c:\ Ensuite
sont affichés tous les registres, par défaut à chaque
fois que vous tracez une instruction, tous les registres seront affichés
dans la fenetre de commandes, pour stopper cette option il suffit
de tapper pr On
voit un message d'erreur: Controle de la cible Si le programme
cible est actif vous n'aurez pas la possibilité de le controler ou
de lancer des commandes. Pour redonner le contrôle au programme il suffit de tapper la commande g ou d'appuyer sur la touche F5 du clavier. Voici un petit recapitulatif des actions de bases pour controler le programme, avec en dernier la colone pour faire la comparaison avec les touches de softice.
Les Breakpoints Voici la liste
des commandes pour controler les Breakpoints. - BL (Breakpoint List) - Liste les breakpoints et leur statut Syntaxe
: bl [ID] 0 e 77d3add7 0001 (0001) 0:*** USER32!MessageBoxA 0 represente
l'ID du breakpoint (son numero dans la liste) - BP (Set Breakpoint) - Place un breakpoint Syntaxe : bp[ID] [/f PredNum] [Address [Passes]] ["CommandString"] Cette commande place un BreakPoint, on peux en placer sur une adresse, un label, une fonction combiné avec ou sans options. [ID]
: determine le numero du breakPoint tel qu'il apparaitra dans la liste,
le chiffre doit etre collé a la commande (ex: bp2) exemple
: bp2 messageboxa 5 "r eax; dd esp; g" Il est possible de poser des BP conditionnels en placant la commande dans l'expression, voir plus bas la commande de condition. - BA (Break on Access) - BreakPoint sur une zone memoire lorsque celle-ci est sollicité (comme bpm pour softice) Syntaxe : ba[ID] Access Size [/f PredNum] [Address [Passes]] ["CommandString"] La plupart des parametres sont les memes que pour BP, seuls 2 arguments supplementaire et obligatoires figure pour cette commande : Access : determine le type d'acces à la mémoire
Size : taille en byte de la memoire à surveillé, peut etre 1, 2 ou 4 bytes Il n'est pas necessaire de separé l'acces et la taille par un espace exemple
: ba r4 401580
Syntaxe : BC breakpoint breakpoint : ID du breakpoint à effacer, pour effacer tous les breakpoints on utilise * à la place de l'ID exemple
: bc * Syntaxe : BD breakpoint breakpoint : ID du breakpoint à desactiver, pour désactiver tous les breakpoints on utilise * à la place de l'ID exemple : bd * - BE (Breakpoint Enable) - Active un Breakpoint Syntaxe : BE breakpoint breakpoint : ID du breakpoint à activer, pour activer tous les breakpoints on utilise * à la place de l'ID exemple : be * Conditional Breakpoints : Pour poser des breakpoint conditionnels on se sert d'une commande J (Execute If - Else) dont voici la syntaxe, que l'on placera dans le parametre commande J Expression Command1
; Command2 Expression
: expression à tester, si le resultat est non-zero la command 1 est
executé, si le resultat est zero la command2 est executé. exemple
: bp messageboxa " j (eax != 0) g ; 'r eax; r edx' " Lire et modifier la mémoire On peux lire et ecrire directement en mémoire localisé par une adresse ou le nom d'une variable. On peux acceder sous plusieurs format tel que : hexadecimal bytes, words, double words, quad-words; short, long, quad integers et unsigned integers; 10, 16, 32, et 64 byte real numbers, et en caracteres ASCII. On y accede via les commandes suivantes: Pour specifier
une plage de memoire on peux utliser 2 formes : D* (Display
Memory) E* (Enter Values) M (Move Memory) Syntaxe : m range address range : plage
de l'adresse à copier F (Fill Memory) Syntaxe : f Range Pattern range : plage
d'adresse mémoire à remplir exemple
: f 401000 L50 'A' 'B' 'C' C (Compare
Memory) Syntaxe : c Range Address Range : la premiere
des 2 plage memoire à comparer exemple
: c 401000 L10 402000 S (Search Memory) Syntaxe1 :
s [-Type] Range Pattern
Range : Plage
memoire ou effectué la recherche, la plage ne peux ecceder 250 MO
de taille. Si la valeur est retrouvé, le debugger affichera l'adresse de depart de celle ci exemple : s -a 0012ff40 L20 "Hello" Lire et modifier les registres et les flags La commande R
(Registers) permet de modifier un registre ou un flag, exemple : r
eax = 5 ou r zf = 1 En tracant, tout les registres seront affichés dans le fenetre de commande, on peux stopper cette fonction en tappant PR p correspondant a la commande STEP (F10) et r pour registre annulant ainsi cette fonction en retappant cette commande on la reactive. Modifier et rechercher du code assembleur La commande # (Search for Disassembly Pattern) permet de rechercher un pattern (adresse, instruction, expression, valeur, registre ou tout autre text ) dans la fenetre du code désassemblé Syntaxe : # [pattern] [address] pattern
: pattern a recherché dans le fentre du code désassemblé voici quelques exemples, nous avons ce code: 00401000 6a00 push 0x0 en tappant la commande # mov 401000, le debugger nous retournera : 00401007 a300304000 mov [image00400000+0x3000 (00403000)],eax Qui est la premiere adresse ou l'on rencontre le pattern 'mov', on peux tres bien rechercher une valeur comme A3 sui sera retourné à l'adresse 401007 comme la valeur hexa de l'instruction asm qui suit. Bref une commande tres pratique pour recherché tout et n'importe quoi dans le code désassemblé. Pour modifier du code directement en assembleur on se sert de la commande A A (Assemble) Syntaxe : a [address] adress
: etant l'adresse de depart ou modifier le code, si
l'on ne specifie pas d'adresse la modification commence à l'adresse
courante, pour sortir du mode assembleur il suffit de presser la touche
ENTRER sans entrer de nouvelle instruction. N : La base numerique utilsé par defaut par le debugger est l'hexadecimal, on peux en changer en tappant la commande N suivi de la base souhaité : n 10 (decimal), en tappant simplement n le debbugger affiche la base courante. ? : Permet Evaluer une expression, un registre, une variable.. Comme sous softice. exemple : ? eax, ? E52F .cls : efface la fenetre des commande !dh [Module Name] : Affiche le header du module specifier (generalement le nom de votre module sera image00400000) LM : Liste les modules chargés .load : charge une nouvelle DLL dans le debugger x : affiche tous les symbols contenu dans un module exemple : x user32!mes* affichera toutes les fonctions contenu dans User32.dll commenecant par 'mes' ENTER : (La touche) repete la commande precedente .tlist : List tous les programme chargé en memoire .reboot : Reboot le system en cas de gros plantage .formats : Affiche dans plusieurs format une expression ou une valeur .kill : Termine un processus
Voila les presentations sont faites, bien sur il faut un petit temps d'adaptation pour s'en servir efficacement, ce debugger possede beaucoup de fonctions et de possibilités, encore une fois allez faire un tour dans l'aide (tres complete) qui vous detaillera toutes les possibilté de celui-ci. Sur le net il est tres dur de trouver des tutos de crack avec Windbg, voir impossible, c'est ce qui m'a aussi poussé a faire ce tutorial. Et j'espere que la pratique et l'utilisation de ce debugger se repandra un peu permettant d'elaborer des techniques, scripts et des plug-ins avancés. A mon humble avis ce debugger à sa place dans le monde du cracking, surtout pour ceux qui souhaite utiliser un debugger efficace sous XP et qui sont rebutté comme moi par DriverStudio. Les commandes etant tres proche de celle de softice les habitué de SI n'auront aucun probleme à se servir de ce debugger et la methode de travail reste sensiblement la meme. Peut etre un peu moins simple à s'en servir du fait qu'il faille je pense quelques notions et base de cracking avant de se lancer dans ce debugger et de s'en servir efficacement... D'un autre coté le mode graphique et certaines options apparaitront plus conviviales aux yeux de certains. Lors d'un BP sur une API, le debugger va breaker sous les dll system auquel appartienne l'api sollicité. C'est a dire que l'on se retrouve avant tout dans les dll du system avant d'etre dans notre module. Pour sortir des ces dll et aller dans notre module on peux faire comme sous SI et F12, sous WinDbg (SHIFT+F11) ou alors le boutton step out. On peux aussi tracer un peu avec F10 dans ces dll system ou l'on pourra ainsi voir les parametre pushé et etudier leurs valeurs avant que la fonction ne s'execute, ensuite nous rencontrerons un ret qui suffira de tracer et qui nous rammenera dans notre programme. Sous Windbg quand on trace sur l'adresse de l'instruction courante, sera rajouté selon l'instruction des infos supplementaires comme l'evaluation d'une valeur, une valeur pointé par une adresse, le nom d'une fonction etc... Apercu d'un crack avec WInDbg Voici un mini-tutorial sur un petit crackme, pour montrer comment travailler avec Windbg. Bien sur, étant donné que j'ai exploré ce debugger par moi meme, sans avoir pu trouver un seul tutorial et d'autres experiences de cracking complete avec cet outil et qu'il reste relativement nouveau pour moi, je n'ai pas la pretention de donner la methode ultime ou de maitriser parfaitement cet outil, mais simplement je veux vous expliquer comment je m'en sers pour les fonctions de bases. On ouvre le programme via le menu File | open executable. CommandLine: C:\netix\compil.exe Windbg nous affiche les modules alors chargé, tels que User32, Kernel32 etc... Notre programme se nomme image00400000 Puis l'adresse ou le debugger à breaké : 77f6f570 cc int 3 Contrairement à SoftIce nous ne somme pas sous notre module à l'entry-point, et si nous voulons faire un un break sur l'entry point, il va falloir le specifier. Pour cela, on affiche le header de notre crackme et on recupere l'entry-point avec la commande: !dh image00400000 OPTIONAL HEADER VALUES Ne vous inquietez pas si vous obtenez des erreurs, celles ci viennent du fait que notre module est correctement chargé mais qu'aucun symbol n'est present dans celui-ci. Les symbols etant des labels, noms de variables fonctions etc.. qui sont normalement inserés dans un prog pendant la compilation et déstinés à faciliter le debugging par la suite. Etant donné que le programme n'a normalement pas ces informations , le debugger nous en rendra compte. On redonne la main au programme avec la touche F5 ou la commande G, aussitot celui-ci break et nous nous retrouvons sur notre bp dans la fenetre du code: 00400ffa 0000 add [eax],al On pose un bp sur l'api MessageBoxA et lui redonne la main avec G ou F5 bp messageboxa Si vous obtenez à nouveau un message d'erreur sur les symbols ne vous inquitez pas c'est le dernier, apres le debugger ne nous embetera plus avec ca, il aura surement compris que nous crackeur n'avons pas besoins de ces shits la pour debugger On rempli les champs du crackme avec un nom et un serial et on presse le boutton check, ca break et on se retrouve ici: USER32!MessageBoxA: Ici on a breaké dans une dll du systeme, USER32 qui contient la fonction MessageBoxA, on voit que l'API est referencé par un label en tout debut avec USER32!MessageBoxA puis les arguments qui vont etre passés pour cette fonction. On pourrait comme sous SI faire un F12 (sous Windbg un SHIFT+F11 ou le boutton Step out) ce qui aurait pour effet d'executer l'API MessageBox, et ensuite une fois que nous aurions quitté la message box, le debugger nous redonnerais la main dans notre programme en se placant juste apres le call de la messagebox. Cepandant on peux ici de voir les arguments qui seront passé pour la message box avant que celle-ci s'affiche. Pour cela nous restons nous restons dans la dll system et nous tracons avec F10. Les instructions qui suivent sont les push des argument pour MessageBoxA , exemple du 2eme argument pushé , lorsque l'on arrive dessus les infos suivantes sont ajoutées : 77d3adea ff742414 push dword ptr [esp+0x14] ss:0023:0012fbc8=00401147 Cet argument selon le prototype represente le titre de la message box, pour voir celui-ci il suffit de tapper la commande suivante dans le fenetre de commande: d 00401147 et on obtient : 0:000> d 00401147 On continu à tracer, depassé le call, la MessageBox va s'afficher, on clik OK sur celle -ci et le debugger reprend la main, en pointant sur l'instruction qui suit, a savoir un ret qui va nous faire revenir dans notre programme juste apres le call de la messagebox, (comme si nous avions effectué le step out des le debut) : 0040116b 114000 adc [eax],eax bc * (efface tous les breakpoints) bp GetDlgItemTextA On redonne la main au programme avec F5, on entre un nom et un serial et on clik sur le boutton Check, ca break dans USER32! : USER32!GetDlgItemTextA: 004010b1 6a10 push 0x10 On se retouve juste apres le call de GetDlgItemTextA, si on examines ses parametres pushé (les 4 derniers avant le call, puisque cet api utilise 4 arguments selon le prototype) on peux voir notre nom en examinant le 2eme argument pushé (rappel : inverse par rapport au prototype) : d 40300d 0:000> d 40300d On continue en tracant, des que l''on rencontre un call d'une api, en tracant avec F10 on entre dans la dll ou elle est declaré, on en ressort avec un Step out. Voila en gros
comment controler sa cible, ce qui parrait deroutant au debut est
de ne pas voir le nom des fonctions directement dans le code desassemblé
de notre module, mais apres on s'y habitue et cela ne gene pas vraiment,
l'important etant d'examiner les parametres pushé avant celle-ci,
apres l'avoir tracé. Peut etre aussi existe t-il une manip qui m'a
echapé et qui permetrai d'y remedier, j'attend avec impatiente vos
solutions. Un moyen que j'ai trouvé pour y remedier est par l'export de IDA vers WindDbg, voyons comment faire. Export de IDA vers WinDbg Pour cela il faut
une petite manip, avec un petit prgramme creer par Borland qui s'appelle
Map2Dbg que vous trouverez ICI On utilise ensuite Map2Dbg, pour s'en servir rien de plus simple : on place Map2Dbg dans le meme rep qui contient l'EXE analysé ainsi que son fichier .MAP, tout 2 porte le meme nom, On fait glisser l'EXE sur Map2Dbg et un nouveau fichier va etre creé portant le nom de l'EXE avec l'extension .DBG. C'est ce fichier qui va nous servir pour WinDbg, mais avant tout une chose tres importante, il faut le renommer en image00400000.dbg en effet image00400000 est le nom de notre module sous WinDbg et le debugger va donc chercher le fichier .dbg correspondant a ce nom de module. Ensuite on va specifier le chemin du repertoire ou se trouve ce fichiers qui contient des Symbols, on peux via le menu File | Symbol File Path, specifier le repertoire ou se trouve le fichier image00400000.dbg et ensuite ouvrir l'EXE. La commande .sympath [chemin vers le repertoire ou se trouve le fichier] permet de modifier ce chemin. Voyons voir le rendu : 00400ff6 0000 add [eax],al On peut voir à present les labels ( start, DialogProc ), les fonctions appelés, les variables ( mov [image00400000!hInstance (00403000)],eax ). On peux poser des BP sur ces labels et Fonctions : BP start , BP DialogProc ainsi qu'examiner la valeur des variables en les designant par leur nom, bref debugger en utilisant les symbols contenu dans ce fichier .DBG. Conclusion J'espere que vous
avez apprecié ce debugger, et que vous vous en servirez et
ferez evoluer des methodes de cracking par l'intermediaire de tutoriaux
voir pourquoi pas si vous en etes capables de programmer des plug-ins
ou scripts qui permettraient d'ajouter des fonctions à ce petit debugger. |