[French] Reversing on Linux x86 (with GDB)

EDB-ID:

17723

CVE:

N/A


Author:

fr0g

Type:

papers


Platform:

Linux_x86

Date:

2011-08-26


 # Exploit Title: [french] Reversing on Linux x86 (with GDB)
 # Date: 20/08/2011
 # Author: fr0g (hwc-crew.com)
 # Tested on: Debian Squeeze

 
 ################################
 # Author : fr0g (hwc-crew.com)
 # Mail : fr0g@hwc-crew.com
 #
 # Special Thank'x :
 #
 # - int_0x80 (big-daddy.fr)
 # - eko
 ################################
 
 

 Introduction au reversing sous GNU/Linux x86


 Avant toute chose, je tiens a preciser qu'il est preferable
 d'avoir quelques connaissances en langage assembleur afin de comprendre 
 ce paper, (et de connaitre
 correctement le fonctionnement de Linux)



 # 1/ Les outils Necessaires

 Pour vous expliquer le but de cet article, je le redige dans le but
 de familiariser un peu les debutants en R-E sur linux, avec les outils
 gratuits les plus courants sur notre cher systeme open source
 (ayant moi-meme eut des difficultes quand je me suis retrouve avec
 les outils de Linux entre les mains, alors que j'avais l'habitude de 
 OllyDbg sous Windows.)

 Les outils que nous allons utiliser ici sont :

 - GDB (desassembleur/debugger pour Linux)

 - KhexEdit (editeur hexadecimal pour interface KDE, il en existe 
 evidemment d'autres
 comme Ghexedit (sous Gnome))


 2# / Le desassemblage

 Bon commençons, pour la demonstration j'ai utilise un crack-me du site
 root-me.org (le code obtenu ne sera pas celui qui valide la vrai 
 epreuve,
 afin de ne pas spoiler leur travail)


 Afin de desassembler notre programme (appele ch1.bin), on lance le 
 terminal,
 accedez au dossier contenant ch1.bin via la commande "cd" :

 fr0g@XUB:~$ cd Desktop
 fr0g@XUB:~/Desktop$


 Ensuite, lancez GDB avec en parametre le nom du fichier a desassembler:


 fr0g@XUB:~/Desktop$ gdb ch1.bin
 GNU gdb 6.6-debian
 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 "i486-linux-gnu"...
 (no debugging symbols found)
 Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
 (gdb)


 A partir de la, ch1.bin est ouvert par GDB, il vous suffit maintenant 
 de
 desassembler le programme a partir de son point d'entree (appele "main" 
 par defaut):


 (gdb) disass main
 Dump of assembler code for function main:
 0x0804869d <main+0>:    lea    0x4(%esp),%ecx
 0x080486a1 <main+4>:    and    $0xfffffff0,%esp
 0x080486a4 <main+7>:    pushl  0xfffffffc(%ecx)
 0x080486a7 <main+10>:   push   %ebp
 0x080486a8 <main+11>:   mov    %esp,%ebp
 0x080486aa <main+13>:   push   %ecx
 0x080486ab <main+14>:   sub    $0x24,%esp
 0x080486ae <main+17>:   movl   $0x8048841,0xfffffff8(%ebp)
 0x080486b5 <main+24>:   movl   $0x804884c,(%esp)
 0x080486bc <main+31>:   call   0x80484c8 <puts@plt>
 0x080486c1 <main+36>:   movl   $0x804888c,(%esp)
 0x080486c8 <main+43>:   call   0x80484c8 <puts@plt>
 0x080486cd <main+48>:   movl   $0x80488cc,(%esp)
 0x080486d4 <main+55>:   call   0x80484c8 <puts@plt>
 0x080486d9 <main+60>:   movl   $0x804890c,(%esp)
 0x080486e0 <main+67>:   call   0x8048498 <printf@plt>
 0x080486e5 <main+72>:   mov    0xfffffff4(%ebp),%eax
 0x080486e8 <main+75>:   mov    %eax,(%esp)
 0x080486eb <main+78>:   call   0x80485fe <getString>
 0x080486f0 <main+83>:   mov    %eax,0xfffffff4(%ebp)
 0x080486f3 <main+86>:   mov    0xfffffff8(%ebp),%eax
 0x080486f6 <main+89>:   mov    %eax,0x4(%esp)
 0x080486fa <main+93>:   mov    0xfffffff4(%ebp),%eax
 0x080486fd <main+96>:   mov    %eax,(%esp)
 0x08048700 <main+99>:   call   0x80484d8 <strcmp@plt>
 0x08048705 <main+104>:  test   %eax,%eax
 0x08048707 <main+106>:  jne    0x804871e <main+129>
 0x08048709 <main+108>:  mov    0xfffffff8(%ebp),%eax
 0x0804870c <main+111>:  mov    %eax,0x4(%esp)
 0x08048710 <main+115>:  movl   $0x8048930,(%esp)
 0x08048717 <main+122>:  call   0x8048498 <printf@plt>
 0x0804871c <main+127>:  jmp    0x804872a <main+141>
 0x0804871e <main+129>:  movl   $0x8048970,(%esp)
 0x08048725 <main+136>:  call   0x80484c8 <puts@plt>
 0x0804872a <main+141>:  mov    $0x0,%eax
 0x0804872f <main+146>:  add    $0x24,%esp
 0x08048732 <main+149>:  pop    %ecx
 0x08048733 <main+150>:  pop    %ebp
 0x08048734 <main+151>:  lea    0xfffffffc(%ecx),%esp
 0x08048737 <main+154>:  ret
 End of assembler dump.
 (gdb)



 A partir de la ligne 0x08048700, on voit que le code teste si EAX = 0 
 (test %eax,%eax), et fais un
 saut inconditionnel (JNE (JUMP if NOT EQUAL)) apres.

 0x08048700 <main+99>:   call   0x80484d8 <strcmp@plt>
 0x08048705 <main+104>:  test   %eax,%eax
 0x08048707 <main+106>:  jne    0x804871e <main+129>


 Plaçons un BreakPoint sur l'instruction call 0x80484d8, grace a la 
 commande :


 (gdb) b *main+99
 Breakpoint 1 at 0x8048700


 on lance ensuite notre programme en tapant "run" :


 (gdb) run
 Starting program: /home/fr0g/Desktop/ch1.bin
 (no debugging symbols found)
 (no debugging symbols found)
 (no debugging symbols found)
 ############################################################
 ##        Bienvennue dans ce challenge de cracking        ##
 ############################################################

 Veuillez entrer le mot de passe :


 On entre un passe bidon (dans mon cas "AAAAAA"), le programme va 
 evidemment
 nous dire que le password est invalide ^^ (sinon c'est pas drole)
 mais avant cela, il va faire une pause sur le BreakPoint :

 Veuillez entrer le mot de passe : AAAAAA

 Breakpoint 1, 0x08048700 in main ()
 (gdb)


 Maintenant, jetons un oeil au registre $eax (qui a ete manipule dans 
 les precedantes instructions) :

 (gdb) print $eax
 $1 = 134524936
 (gdb)

 Bof, un resultat qui a premiere vue ne nous dit pas grand chose, 
 cependant,
 si on affiche le contenu de eax sous forme de chaine de characteres, on 
 obtiens cela :


 (gdb) x/s $eax
 0x804b008:       "AAAAAA"
 (gdb)


 Le code que nous avons entre, c'est bien, mais cela ne nous avance pas 
 beaucoup ^^.
 penchons nous donc sur l'instruction suivante dans le code qui etait :

 0x08048707 <main+106>:  jne    0x804871e <main+129>

 Plaçons un BreakPoint dessus, comme tout a l'heure :

 (gdb) b *main+106
 Breakpoint 2 at 0x8048707
 (gdb)

 Puis, on va dire au programme de continuer jusqu'au prochain breakpoint 
 :

 (gdb) c
 Continuing.

 Breakpoint 2, 0x08048707 in main ()
 (gdb)

 Bon revenons a l'instruction JNE, comme je l'ai explique plus haut (et 
 si vous connaissez un peu
 l'ASM, vous devez le savoir) il s'agit d'un saut "si les valeurs 
 comparees ne sont pas egales),
 on voit donc que le programme va sauter a la ligne 0x804871e si les 
 valeurs comparees sont inegales.

 Nous allons donc modifier cette instruction, pour on va demander a GDB 
 de nous renvoyer
 la valeur hexadecimale de l'instruction JNE en question, puis, appuyez 
 plusieurs fois
 sur Entr pour obtenir les valeurs hexadecimales suivantes:


 (gdb) x/b 0x08048707
 0x8048707 <main+106>:   0x75
 (gdb)
 0x8048708 <main+107>:   0x15
 (gdb)
 0x8048709 <main+108>:   0x8b
 (gdb)
 0x804870a <main+109>:   0x45


 le 0x75 (75 hexa) correspond a l'instruction JNE "brute", les valeurs 
 suivantes (soit : 0x15, 0x8b, 0x45) correspondent aux valeurs suivantes 
 du code.

 NOTE : Il est important de savoir que si on demande a gdb de nous 
 renvoyer la valeur hexa de la
 ligne de code ou est le JNE en question, celui ci nous renverra :
 (gdb) x/x 0x08048707
 0x8048707 <main+106>:   0x458b1575

 Afin de comprendre pourquoi l'ordre des valeurs est inverse (75 
 apparait en dernier), documentez vous sur les fonctionnement du 
 processeur, et de la "PILE" (la premiere valeur a y entrer est la 
 derniere a en sortir) , je n'argumenterai pas sur ce sujet ici .

 Notez donc la valeur "75158b75", nous allons maintenant modifier notre 
 programme via KhexEdit,
 pour cela, lancez KhexEdit dans un second terminal avec en parametre le 
 nom du programme (ch1.bin)


 # 3/ L'edition en hexadecimal

 KhexEdit s'ouvre et nous affiche le code du programme (en hexadecimal), 
 de tete ce n'est pas vraiment
 comprehensible, mais nous savons deja ce que nous cherchons ;) la 
 sequence hexadecimale : 75158b45
 Il suffit alors de chercher cette sequence en la tapant dans la barre 
 de recherche de KhexEdit (ou en faisant CTRL+F)

 Boom, le programme la trouve (et il n'y en a qu'une, on a de la chance 
 )

 Note : Pourquoi n'aije pas simplement tape 75 (pour JNE) ?

 Car le 75 peut apparaitre plusieurs fois dans un programme (c'est 
 d'ailleurs souvent le cas) mais une sequence contenant 75****** apparait 
 plus difficilement plusieurs fois dans le meme fichier)


 On va donc remplacer le 75 par un 74 (74 = JE (Jump if Equal)), soit 
 remplacer la chaine recherchee : 75158b45 par 74158b45 .

 On enregistre le code (fermez GDB sinon vous n'aurez pas la permission 
 de modifier le programme)

 On relance notre programme dans la console :

 fr0g@XUB:~/Desktop$ ./ch1.bin
 ############################################################
 ##        Bienvennue dans ce challenge de cracking        ##
 ############################################################

 Veuillez entrer le mot de passe : blabla
 Bien joue, vous pouvez valider l'epreuve.


 (en realite une fois cracke, le programme nous donne le code qui valide 
 l'epreuve, je ne l'ai pas affiche ici)

 NOTE : Etant donne que l'on a remplace JNE par un JE via l'editeur 
 hexadecimal, si l'on entre le vrai password dans le programme, celui ci 
 nous renverra le message d'erreur, pour eviter cela, on peut remplacer 
 le 75 (JNE) par un 90 (NOP) qui n'execute aucune instruction)


 Voila, j'espere que ce tuto vous aura un peu aide a comprendre les 
 fonctionnements et commandes les plus pratiques de GDB sous Linux.