IDA - The Interactive Disassembler - part 1 Voici une petite serie
de 4 tutos pour ceux qui souhaiteraient s'initier à IDA, et je peux vous
assurer que ca en vaut le détour (de se mettre à IDA, loin de moi de penser
que mes tuts en vaillent le détour :p). Note: Certaines fonctionnalitées décrites par la suite peuvent ne pas etre presente dans IDA selon la version que vous utilisez. Tous les exemples ici sont accessibles à partir de la version 4.15. IDA en lui même Multi-processeur
: Désassembleur intelligent
: FLIRT pour Fast Library Identification and Recognition Technology, permet de reconnaitre des appels de fonction sur des librairies standard de certains compilteurs. Exemple sur un programme en C si vous appelez la fonction strcpy(..) IDA pourra reconnaitre cet appel de fonction et au lieu de preciser un simple call xxxxxx lequel vous devrez explorer avant de comprendre que cette fonction sert à copier une string, vous obtiendrez directement call strcpy ce qui economise du temps et facilite bien la tache. PIT pour Parameter Identification and Tracking permet à IDA de suivre et d'identifier les paramètres d'une fonction aux travers de la pile afin de reconnaitre et marquer les paramètres employés, ce qui là encore facilite grandement la tache. IDA permet aussi de désassembler proprement faisant la différence entre du code et des déclarations de variables ainsi que du code inexploité par le programme. Interactif : Voila pour les fonctionnalités de base, bien sur il y en a beaucoup d'autres mais je vous laisse le soins de les découvrir par vous même. De Wdasm à IDA Wdasm étant le désassembleur le plus connu et le plus utilisé du fait de son extreme facilité, il s'agit surement du désassembleur par lequel vous avez commencé à pratiquer et quand on passe de wdasm à IDA on peux se trouver quelque peu dépaysé. D'abord je tient à dire que je ne déconsidere ou ne critique pas Wdasm qui est un très bon outil et pour des programmes simples qui ne necessitent pas une analyse poussée. Il convient amplement surtout avec le patch assez recent à l'heure où je parle qui ajoute des quantités de choses telles la colorisation syntaxique, ajout de commentaires etc.. La première difficulté se pose sans doute avec les Sting Datas References, puisque c'est la méthode la plus facile et par laquelle on apprend à cracker. Sous IDA on peux tout de meme lister les strings declarées et utilisées par le code via le menu / view / name ou voir directement en commentaire les strings reference par le code. Vous obtenez une fenêtre listant les noms des fonctions et des noms de variables explicites nommées selon leur contenu. Exemple : une string qui contient "Merci de vous être enregistré" sera nommée par défaut comme ceci : aMerciDeVous. Sur ce point Wdasm est plus fort (surtout la version 8.5) car souvent il liste beaucoup plus de reference que IDA, mais il faut savoir que la technique des strings datas n'est pas la seule facon de cracker et qu'avec la pratique du cracking vous n'en avez presque plus l'utilité. Vous en viendrez même à l'éviter du fait des pièges que cette technique peut engendrer (crackmes tordus, etc...). Les jump et les call
références sont aussi un probleme, puisque definis différement. Portion de code désassemblé sous Wdasm * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040105C(C) | :0040106D 817D0C11010000 cmp dword ptr [ebp+0C], 00000111 :00401074 0F850B010000 jne 00401185 :0040107A 8B4510 mov eax, dword ptr [ebp+10] :0040107D 837D1400 cmp dword ptr [ebp+14], 00000000 :00401081 0F8407010000 je 0040118E :00401087 8B5510 mov edx, dword ptr [ebp+10] :0040108A C1EA10 shr edx, 10 :0040108D 660BD2 or dx, dx :00401090 753B jne 004010CD :00401092 6683F801 cmp ax, 0001 :00401096 7518 jne 004010B0 :00401098 6A30 push 00000030 * Possible StringData Ref from Data Obj ->"Enregistrement..." | :0040109A 6816304000 push 00403016 * Possible StringData Ref from Data Obj ->"Merci de vous êtes enregistrés " ->"!" | :0040109F 6828304000 push 00403028 :004010A4 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:01BBh | :004010A6 E817010000 Call 004011C2 :004010AB E9D3000000 jmp 00401183 Portion de code désassemblé sous IDA 0040106D loc_40106D: ; CODE XREF: sub_40102B+31j Pour les jumps et calls références, sous Wdasm on a: Referenced by a (U)nconditional or (C)onditional Jump at Address :0040105C(C) et sous IDA : 0040106D loc_40106D: ; CODE XREF: sub_40102B+31j Cette petite ligne en dit beaucoup: - On
se situe à l'adresse 0040106D. On voit que l'adresse 0040106D figure 2 fois, cela permet juste à IDA de rajouter des lignes interressantes ou plusieurs lignes de commentaires sur l'adresse. Comme ici la XREF. On vois aussi que les strings data referencées par des adresses sous Wdasm ont été renommées sous IDA en nom de variables explicites suivi d'un commentaire indiquant leur contenu. On peut aussi double-clicker sur le nom de la variable pour aller directement là où celle-ci est déclarée suivi de sa XREF. 00403016 aEnregistrement db 'Enregistrement...',0 ; DATA XREF: sub_40102B+6Fo Cette
variable de type chaine de caracteres est déclarée comme dans une source
asm avec la pseudo instruction db. Pour la référence de
l'API MessageBox, Wdasm nous informe par On voit aussi que sur la première instruction cmp [ebp+arg_4], 111h , on utilise ebp+arg_4 alors que Wdasm emploie la valeur réel ebp+0C. arg_4 représente ici tout simplement l'un des arguments de cette procédure definie un peu plus haut: 0040102B sub_40102B proc near ; DATA XREF: start+Eo arg_4 représente
bien la valeur 0C d'ailleur si on clique droit sur arg_4
dans cmp [ebp+arg_4],
111h, un petit menu va apparaitre nous donnant la valeur exact
sous différentes bases (hexa, decimal, binaire...). Les options On peux afficher plus
ou moins de renseignements et organiser selon nos souhaits le listing. Le nombre d'options
etant relativement important je ne peux pas toutes les décrires mais je
vous conseille de prendre quelques minutes afin d'explorer chacune d'elle
pour personaliser IDA selon vos désir. Utilisation de IDA - les commandes et fonctions de base Déja on commence par ouvrir le fichier que l'on souhaite via le menu File / Open file.. ou le bouton raccourci dans la barre d'outil. Une fenêtre apparaît nous permettant de spécifier quelques options, on ne touche à rien et on clique directement sur OK. On voit dans la petite fenêtre du bas l'évolution de l'analyse et on attend qu'il ait fini, ce qui peut etre très long pour des programmes conséquents. Les zones On obtient finalement un listing que l'on peux diviser en différentes zones comme suit :- le code où l'on voit les instructions - les datas on l'on voit les déclarations des variables comme en asm par les pseudos instruction db, dd, dw - Inexploré que l'on reconnais car les segments d'offset sont grisés (partie de gauche), et ça ressemble a des déclaration de variables (ex : DB 82). Les zone inexplorées sont des zones qui ne sont ni référencées dans le code ni dans les datas. On peux modifier chaque zone en sélectionnant les lignes ou la ligne et en pressant : 'c' - pour code 'd' - pour data (si on se place seulement sur une ligne qui défini déjà une variable par db par ex on peut changer le ......type en pressant 'd' et en faisant défiler les types) 'u' - pour unexplored Les jumps et le tracing Sous IDA pour activer
des options etc.. tout dépend de la position du curseur, il faut placer
le curseur sur le nom d'une variable ou d'une fonction pour activer les
options propres aux modifications de ces valeurs. On utilise la touche 'echap' pour revenir en arrière autant de fois que l'on a avancé (pratique pour revenir d'un jump ou d'un call). On peux aussi utiliser les 2 petites flèches latérales de la barre d'outils. Depuis le menu / jump on a une foultitude de jump possibles, les plus utilisés etant 'jump to adress' accessibles directement via le raccourci clavier 'G', 'jump to entry-point' pour se rendre sur l'entry-point, 'Jump to function' etc... On a la possibilité aussi de définir des points clés que l'on nomme par 'Mark position'. On tape la description de ce point et l'on pourra s'y rendre directement en passant par "jump to marked position". Le File Offset et adresse courante Le File Offset nous
permet de nous repérer dans le fichier avec un éditeur hexadecimal
en vue de modification, on l'obtient en visualisant la barre d'etat muni
de plusieurs cases tout en bas de la fenetre. C'est la 4eme case, si on
laisse la souris dessus quelques instants nous verrons "current position
in the input file". Les commentaires Il y a 2 types de
commentaires : les commentaires uniques et les commentaires répétitifs
: Les noms C'est là la grande force de l'interactivité de IDA on peux renommer n'importe quel variable, fonction, valeur ou label et lui donner un nom bien plus explicite que celui donné par défaut. Pour changer le nom d'un label ou en ajouter un, on se place sur le label déjà existant ou à l'adresse souhaité et on presse 'n'. Une boite apparaît permettant de spécifier le nom à utiliser. Le label sera changé et toutes les instructions qui y font references, ainsi si nous avons par exemple: 00401112 loc_401112: ; CODE XREF: sub_40102B+116j 00401112 mov al, [esi] 00401114 test al, al 00401116 jz short loc_401143 nous renommons loc_401112 en coucou. Si on se rend au jump ( par la ligne XREF ) qui référence ce label nous ne verrons plus jmp loc_401112 mais jmp coucou. Pour changer le nom
d'une fonction c'est un peu le meme procédé, la fonction etant déclaré
comme suit : 004011A0 sub_4011A0 proc near ; CODE XREF: sub_401160+27p 004011A0 004011A0 arg_0 = dword ptr 8h 004011A0 arg_4 = dword ptr 0Ch 004011A0 arg_8 = dword ptr 10h 004011A0 arg_C = dword ptr 14h 004011A0 004011A0 push ecx 004011A1 push ebx Et soit on presse
'n' pareil que pour un label et editer le nom soit on
peux passer par un menu spécifique au fonction en pressant 'alt-p'
ou clic droit pour y acceder via un petit menu contextuel. 004011A0 ; int Calcul1(HWND hwnd,int var1,int var2,BOOL value) On peux se servir du nom de constante symbolique pour renommer des valeurs. Exemple dans une procedure de gestion de message d'une fenetre, la constante WM_INITDIALOG une fois désassemblé sera remplacé par sa valeur numerique 110: .code:0040102E cmp [ebp+arg_4], 110h Si on clique droit
sur 110h, on choisi 'use standard symbol constant' une liste apparait
nous proposant les différentes constantes de Windows qui ont la valeur
110, apres il suffit de situer le contexte dans lequel nous sommes afin
de choisir la bonne, Ici c'est dans une procedure de gestion des messages
la constante que l'on recherche est donc un message celui qui nous est
proposé est bien WM_INITDIALOG ( WM_ pour Windows Message
). Tant
qu'on y est on va pousser un peu plus loin en montrant la technique de
travail sous IDA, Pour passer des arguments à une fonction on les push dans la pile avant le call de la fonction et en ordre inverse par rapport au prototype, la pile est accessible via le registre esp, ensuite dans la procédure on se sert de ebp pour recuperer les element de la pile selon ce shema : push
ebp ; sauvegarde valeur de ebp ebp+00
= esp = old ebp => viens d'etre sauvgardé ;fin de la procedure mov esp,ebp
; ebp contient l'ancienne valeur d'ebp ret ; retourne juste apres le call de la fonction Revenons a notre exemple: .code:0040102E cmp [ebp+arg_4], 110h .code:00401035 jz short loc_401058 Là on compare ebp+arg_4 qui represente ebp+0C qui lui même est le 2eme argument de cette procedure de gestion de message si on examine la prototype de la procedure de gestion des messages : BOOL CALLBACK DialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); Le 2eme argument est
uMsg c'est une variable qui contient des valeurs numeriques (UINT
- unsigned int) représentées par des constantes symboliques comme WM_INITDIALOG,
c'est aussi en sachant que c'est ce 2eme argument que nous pouvons deduire
que la valeur qui suit est un Windows Message. .code:0040102E cmp [uMsg], WM_INITDIALOG Pour ceux qui n'ont rien compris je reprendrais plus en détail dans la 2eme partie de cette serie de tutoriaux dont le thème sera de d'analyser et modifier un listing complet sur un petit programme très simple. Ce qui permettra de mettre en pratique et de pousser encore plus loin ce que nous venons de voir. Cet exemple étant là pour illustrer comment on travaille sous IDA et avoir un apercu du résultat qui ne ressemble plus trop à l'original, notez que l'exemple était sur 2 lignes de code. Imaginez sur une source complète ou même juste une fonction. On peux aussi renommer tout ce que l'on souhaite en choisissant 'Manuel' depuis le menu contextuel ou 'alt-F1' et en cochant 'allow no matched operand' même si c'est completement illogique ou rien à voir donc prudence surtout si vous desirez plus tard exporter votre code (voir part 2 et 3). Sauvegarder son travail et l'exporter Une fois qu'on a bien bossé ou qu'on veux en laisser pour le lendemain, il suffit de sauvegarder le listing qui sera sauvegardé avce l'extension .idb lequel on pourra bien sur re-ouvrir et retrouver tout son boulot intact :) Parmi les exports ( menu / produce ) on peux exporter le listing en .asm qui produira une source utilisable avec un assembleur, attention la source obtenue ne sera pas forcement compilable tout de suite voir même pas du tout, il faudra la retravailler et l'adapter. La 3eme partie expliquera la procedure à suivre. On peux produire un fichier .map qui fait la correspondance entre les labels, fonctions variables et les adresses du programme, on s'en servira pour exporter le listing sous Soft-ice ce qui alors ouvre une voie dans un debugging plus clair. |