2008/04/26

Initiation aux bases du Reversing

Salut a tous !
Ce nouvel article traitera d'un sujet trés intéréssant : les bases en matiere de Reversing.
Nous verrons ici seulement le strict minimum , ce qui permettra tout de meme d'acquérir quelque notions en la matiere ,et qui pourrait ( on sais jamais ) susciter des vocations..?
Pour les besoins de cet article nous utiliseront un codes et un programmes de déboggage incontournable : GDB ( sous Linux) puis un crack-me appellé "cm"codé en C trouvé sur un célèbre site .
Le principe ne changeant pas , je n'ai pas trouvé d'intéret a en coder d'autre ( ba ouai quoi) .

Trève de bavardages place a l'article now :

Le Crack-me

1)Ici nous cherchons donc le password , bien , pour cela nous devons d'abord désassembler le "main" ( fonction pricipale du programme) afin d'y placer un "break point" ( point d'arret destiné a stopper le programme a l'endroit que l'on veut examiner , soit l'endroit ou le programme teste l'entrée utilisateur ou a la fin de celle ci selon la façon choisie) .
Commençons par lancer GDB avec "cm" puis désassemblons le "main" avec l'instruction " disas main" de Gdb.
Vous devriez avoir quelque chose comme ça :
[user@localhost asm]$ gdb cm
GNU gdb 6.6-3mdv2008.0 ( Linux release 2008.0)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i586-mandriva-linux-gnu"...
Using host libthread_db library "/lib/i686/libthread_db.so.1".
(gdb) disas main
Dump of assembler code for function main:
0x080483a4 : lea 0x4(%esp),%ecx
0x080483a8 : and $0xfffffff0,%esp
0x080483ab : pushl 0xfffffffc(%ecx)
0x080483ae : push %ebp
0x080483af : mov %esp,%ebp
0x080483b1 : push %ecx
0x080483b2 : sub $0x24,%esp
0x080483b5 : mov %ecx,0xffffffe8(%ebp)
0x080483b8 : mov 0xffffffe8(%ebp),%eax
0x080483bb : cmpl $0x2,(%eax)
0x080483be : jne 0x8048426
0x080483c0 : mov 0xffffffe8(%ebp),%edx
0x080483c3 : mov 0x4(%edx),%eax
0x080483c6 : add $0x4,%eax
0x080483c9 : mov (%eax),%eax
0x080483cb : mov %eax,0x4(%esp)
0x080483cf : movl $0x8048500,(%esp)
0x080483d6 : call 0x80482f0
0x080483db : mov 0x8048552,%eax
0x080483e0 : mov 0x8048556,%edx
0x080483e6 : mov %eax,0xfffffff4(%ebp)
0x080483e9 : mov %edx,0xfffffff8(%ebp)
0x080483ec : mov 0xffffffe8(%ebp),%edx
0x080483ef : mov 0x4(%edx),%eax
0x080483f2 : add $0x4,%eax
0x080483f5 : mov (%eax),%edx
0x080483f7 : lea 0xfffffff4(%ebp),%eax
0x080483fa : mov %eax,0x4(%esp)
0x080483fe : mov %edx,(%esp)
0x08048401 : call 0x8048310
0x08048406 : test %eax,%eax
0x08048408 : jne 0x8048418
0x0804840a : movl $0x8048514,(%esp)
0x08048411 : call 0x8048300
0x08048416 : jmp 0x8048432
0x08048418 : movl $0x8048527,(%esp)
0x0804841f : call 0x8048300
0x08048424 : jmp 0x8048432
0x08048426 : movl $0x804853e,(%esp)
0x0804842d : call 0x8048300
0x08048432 : mov $0x0,%eax
0x08048437 : add $0x24,%esp
0x0804843a : pop %ecx
0x0804843b : pop %ebp
0x0804843c : lea 0xfffffffc(%ecx),%esp
0x0804843f : ret
End of assembler dump.

Ok , maintenant cherchons un peu ou se trouve l'endroit qui nous intéresse ....
Ici , j'ai personnellement choisi de placé mon Break Point a la fin de la condition c'est a dire juste avante le " Mauvais mot de passe " . ( façon certe inabituelle mais efficace tout de meme ,comme vous pourrez le constatez par la suite.
Pour le break point nous choisirons donc l'adresses 0x8048419 puisque :
0x08048408 : jne 0x8048418 ; saute a l'adresse main+116 si non égalité
Nous en déduisons donc que Main+116 se trouve entre l'instruction "else" et "printf("Mauvais mot de passe !\n");" car on y est renvoyé si il y a une inégalité.
Choisissons donc la l'adresse
0x8048419 soit main+117 de cette maniere :
(gdb) b *main+117
Breakpoint 1 at 0x8048419: file ./cm.c, line 15 ; message indiquant la création du break point
Ok , lançons donc le crack-me ("cm") en passant 40*a en argument puis observons ce qui se passe :
(gdb) r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Starting program: /home/kmkz/Bureau/asm/cm aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Vous avez ecrit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Program received signal SIGILL, Illegal instruction.
main (ac=2, av=0xbf90e174) at ./cm.c:15
15 printf("Mauvais mot de passe !\n");
Bon , nous avions vu juste , l'adresse pointait bel et bien sur la fin de la condition .Afin de le vérifié , utilisons la commande "list" de Gdb pour voir exatement ou le break point stoppe le programme :

(gdb) list

10 {
11 printf("Bon mot de passe !\n");
12 }
13 else
14 {
15 printf("Mauvais mot de passe !\n");
16 }
17 }
18 else
19 {
Tout va bien , on est sur la bonne voie \o/ .
C'est bien beau , mais le pass dans tout ça ? il est ou ?
Bah pour le trouver maintenant il nous faut l'adresse du pointeur ESP afin de voir ce qui s'y trouve , pour cela commençons par trouver l'adresse de nos 40*a passé en argument puis tentons de remonter a la pile :
(gdb) print av[1] ; nos "a" étant l'argument [1]
$1 = 0xbf910255 'a' repeats 40 times ; répétés 40 fois on est ok
Poursuivons par l'affichage de tout les argument passés au programme stockés dans "av" :
(gdb) print av
$2 = (char **) 0xbf90e174
Maintenant nous possédons l'adresse du tableau d'argument du programme "cm" , alons donc voir ce qu'il contient a partir de cette adresse mémoire....Bienvenu dans :"la Pile "!
Nous utilisons ici l'instruction x/16x afin d'afficher les 16*4 octets contenu dans la pile :
(gdb) x/16x 0xbf90e174
0xbf90e174: 0xbf91023c 0xbf910255 0x00000000 0xbf91027e

0xbf90e184: 0xbf910291 0xbf9102a6 0xbf9102b9 0xbf9102d0
0xbf90e194: 0xbf9102e3 0xbf9102fb 0xbf91030f 0xbf91031a
0xbf90e1a4: 0xbf91032a 0xbf910337 0xbf910388 0xbf910396
av étant le 1er et av[1] le 2eme de la ligne 1 et ceux la on les connait déja pas vrai ;
ceci dit de petites vérifications s'imposent :
(gdb) printf "%s", 0xbf91023c
/home/kmkz/Bureau/asm/cm(gdb) printf "%s", 0xbf910255 ; on obtient le chemin du programme cm
et :
(gdb) print "%s",0xbf910255
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$3 = 3213951573 ; ici c'est bien av[1] avec nos 40*a , no soucy

Il est temp pour nous de voir vers quelle adresse pointe ESP ( ESP pointe vers le sommet de la pile).
(gdb) print $esp
$4 = (void *) 0xbf90e0b0
Ici se trouve donc l'adresse du sommet de la pile allos dons y jeter un oeil ...
(gdb) x/16x $esp ; meme explications que tout a l'heure
0xbf90e0b0: 0xbf910255 0xbf90e0cc 0xbf90e0c8 0x080482bc

0xbf90e0c0: 0xbf90e0f0 0x08049640 0xbf90e0e8 0x666b646d
0xbf90e0d0: 0x0079766a 0xbf90e0f0 0xbf90e148 0xb7e93f90
0xbf90e0e0: 0xb7fe9cc0 0x08048450 0xbf90e148 0xb7e93f90
bon la on peu constater que l'on a :
l'adresse de la pile :
0xbf90e0c0
l'adresse de nos "a" (av[1]) :
0xbf910255

Mais aussi une adresse que l'on avait pas encore vu jusqu'ici :
0xbf90e0cc


Testons donc
0xbf90e0cc afin de voir ce que cette adresse contient .
(gdb) printf "%s", 0xbf90e0cc
mdkfjvy(gdb)
Hey !! Mais qu'est-ce donc ..? Notre pass seait donc la ? ??
Et oui , en effet le pass est bel et bien
mdkfjvy !

Voila , vous venez de voir les principes de base du Reversing , mais la route est encore longue alors courage et a bientot!