Vous êtes sur la page 1sur 60

5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Première partie
12 novembre 2015

Cette série de billets vous montrera comment désamorcer une bombe binaire.
Qu'est-ce qu'une bombe binaire ?

"Une "bombe binaire" est un programme C exécutable sous Linux qui se


compose de six "phases". Chaque phase attend de l'étudiant qu'il saisisse une
chaîne de caractères particulière sur stdin. Si l'élève entre dans la chaîne
attendue, cette phase est "désamorcée". Sinon, la bombe "explose" en
imprimant "BOOM !!!". L'objectif des élèves est de désamorcer le plus grand
nombre de phases possible".

J'ai trouvé ce type de bombe sur le site web de l'excellent livre "Computer
Systems : A Programmer's Perspective".

Les outils de base nécessaires pour désamorcer une telle bombe sont les suivants
gdb et objdump . gdb est un débogueur que nous utiliserons pour inspecter le
programme pendant que nous l'exécutons. objdump est un outil permettant de
désassembler les fichiers objets afin de voir les instructions réelles que l'ordinateur
exécute.

Cette série n'est pas destinée à être un tutoriel sur gdb , en particulier parce que
c'était la première fois que je l'utilisais.

Assez parlé de cela, commençons à nous amuser. Après l'extraction de l'archive,


nous nous retrouvons avec :

$ ls -l total 36
-rwxr-xr-x 1 carlos carlos 26406 Jun 9 15:41bombe
-rw-r--r-- 1 carlos carlos 4069 Jun 9 15:41 bombe.c

En regardant bomb.c , nous voyons un tas de commentaires et la façon dont tout est
configuré.
http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 1/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

-rw-rw-r-- 1 carlos carlos 49 Jun 9 15:46LISEZ-MOI

En regardant bomb.c , nous voyons un tas de commentaires et la façon dont tout est
configuré.
http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-2.html+&... 1/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

Vous pouvez passer un fichier en argument pour éviter de taper à chaque fois l'entrée
correcte pour des phases déjà désamorcées.

Ensuite, nous devons jeter un coup d'œil à l'exécutable de la bombe , qui est une donnée
binaire, de sorte que nous ne verrons rien d'intéressant si nous l'ouvrons à l'aide de
$EDITOR . C'est pourquoi nous avons besoin d'objdump pour désassembler cet
exécutable.

$ objdump -d bomb > bomb.s

Si nous examinons les premières lignes de ce nouveau fichier, nous constatons ce qui
suit :

bombe : format de fichier elf64-x86-64

Démontage de la section .init :

0000000000400ac0 <_init> :
400ac0 : 48 83 éc 08 sous $0x8,%rsp
400ac4 : e8 f3 01 00 00 callq 400cbc <call_gmon_start>
400ac9 : 48 83 c4 08 ajouter $0x8,%rsp
400acd : c3 retq

Voici à quoi ressemble un fichier ELF lorsqu'il est désassemblé. Examinons donc la
fonction principale :

0000000000400da0 <main> :

http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 3/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

400da0 : 53 pousser %rbx


400da1 : 83 ff 01 cmp $0x1,%edi
400da4 : 75 10 jne 400db6 <main+0x16>
400da6 : 48 8b 05 9b 29 20 00 déplacer 0x20299b(%rip),%rax
# 603748 <stdin@@GLIBC_2.2.5>
400dad : 48 89 05 b4 29 20 00 déplacer %rax,0x2029b4(%rip)
# 603768 <infile>
400db4 : eb 63 jmp 400e19 <main+0x79>
400db6 : 48 89 f3 déplacer %rsi,%rbx
400db9 : 83 ff 02 cmp 0x2,%edi
400dbc : 75 3a jne 400df8 <main+0x58>
400dbe : 48 8b 7e 08 déplacer 0x8(%rsi),%rdi
400dc2 : être b4 22 40 00 déplacer $0x4022b4,%esi
400dc7 : e8 44 fe ff ff callq 400c10 <fopen@plt>
400dcc : 48 89 05 95 29 2000 déplacer %rax,0x202995(%rip)
# 603768 <infile>
400dd3 : 48 85 c0 test %rax,%rax

http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 4/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino
400dd6 : 75 41 jne mov 400e19 <main+0x79>
400dd8 : 48 8b 4b 08 0x8(%rbx),%rcx
400ddc : 48 8b 13 déplacer (%rbx),%rdx
400ddf : be b6 22 40 00 déplacer $0x4022b6,%esi
400de4 : bf 01 00 00 00 déplacer $0x1,%edi
400de9 : e8 12 fe ff ff callq 400c00 <__printf_chk@plt>
400dee : bf 08 00 00 00 déplacer $0x8,%edi
400df3 : e8 28 fe ff ff callq 400c20 <exit@plt>
400df8 : 48 8b 16 déplacer (%rsi),%rdx
400dfb : be d3 22 40 00 déplacer $0x4022d3,%esi
400e00 : bf 01 00 00 00 déplacer $0x1,%edi
400e05 : b8 00 00 00 00 déplacer $0x0,%eax
400e0a : e8 f1 fd ff ff callq 400c00 <__printf_chk@plt>
400e0f : bf 08 00 00 00 déplacer $0x8,%edi
400e14 : e8 07 fe ff ff callq 400c20 <exit@plt>
400e19 : e8 84 05 00 00 callq 4013a2 <initialisation_bombe>
400e1e : bf 38 23 40 00 déplacer $0x402338,%edi
400e23 : e8 e8 fc ff ff callq 400b10 <puts@plt>
400e28 : bf 78 23 40 00 déplacer $0x402378,%edi
400e2d : e8 de fc ff ff callq 400b10 <puts@plt>
400e32 : e8 67 06 00 00 callq 40149e <read_line>
400e37 : 48 89 c7 déplacer %rax,%rdi
400e3a : e8 a1 00 00 00 callq 400ee0 <phase_1>
400e3f : e8 80 07 00 00 callq 4015c4 <phase_defused>

Je n'ai pas collé l'ensemble de la fonction car elle est suffisamment importante et nous
ne sommes pas encore concernés par les autres phases.

Avant de commencer à analyser la fonction, nous devons comprendre la structure de


chaque ligne. Prenons l'exemple de la ligne suivante :

400db6 : 48 89 f3 mov %rsi,%rbx

Nous pouvons diviser cette ligne en trois sections :

• 400db6 : l'adresse du code que nous examinons.


• 48 89 f3 : l'instruction codée.
• mov %rsi,%rbx : l'instruction décodée.

Les premières lignes de la fonction principale correspondent au code C qui vérifie si un


fichier a été transmis au programme en tant qu'argument. En sautant ces lignes, nous
commençons à voir la partie la plus amusante :

400e19 : e8 84 05 00 00 callq 4013a2 <initialisation de la bombe>

http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 5/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

Cette ligne indique que la fonction initialize_bomb doit être appelée. La ligne
correspondante dans le fichier C est la suivante :

/* Faire toutes sortes de choses secrètes qui rendent la bombe plus difficile à désamorcer.
*/
initialize_bomb() ;

Passons donc à la fonction initialize_bomb .

00000000004013a2 <initialize_bomb>:
4013a2 : 48 83 ec 08 sous $0x8,%rsp
4013a6 : êtr a0 12 40 00 déplacer $0x4012a0,%esi
4013ab : e bf 02 00 00 00 déplacer 0x2,%edi
4013b0 : e8 db f7 ff ff callq 400b90 <signal@plt>
4013b5 : 48 83 c4 08 ajouter $0x8,%rsp
4013b9 : c3 retq

L'inspection des valeurs ne révèle rien d'intéressant. Passons à autre chose. Les
quelques lignes qui suivent initialize_bomb dans la fonction principale correspondent aux
lignes suivantes dans le fichier C :

printf("Bienvenue dans ma petite bombe diabolique. Vous avez 6 phases avec \N") ;
printf("qui s'est fait exploser. Bonne journée!\N") ;

/* Hmm... Six phases doivent être plus sûres qu'une seule phase ! */
input = read_line() ; /* Obtenir une entrée */
phase_1(input) ; /* Exécuter la phase */

Ils impriment donc les messages et lisent les entrées. Il est alors temps de désamorcer la
première phase.

400e3a : e8 a1 00 00 00 callq 400ee0 <phase_1>

Là encore, la fonction phase_1 située à 0x400ee0 est appelée. Voyons ce qu'il en est

la première phase se présente comme suit :

0000000000400ee0 <phase_1> :
400ee0 : 48 83 ec 08 sous $0x8,%rsp

http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 6/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

400ee4 : be 00 24 40 00 déplace $0x402400,%esi


400ee9 : e8 4a 04 00 00 r callq 401338 <strings_not_equal>
400eee : 85 c0 test %eax,%eax
400ef0 : 74 05 je 400ef7 <phase_1+0x17>
400ef2 : e8 43 05 00 00 callq 40143a <explode_bomb>
400ef7 : 48 83 c4 08 ajouter $0x8,%rsp
400efb : c3 retq

Remarquez qu'à 0x400ee4 , la valeur 0x402400 est copiée dans le registre esi . Le
registre esi est généralement utilisé comme registre pour le deuxième argument d'une
fonction qui sera appelée ultérieurement. Dans notre cas, cette fonction est appelée
juste après l'instruction mov . On peut alors se demander où se trouve le premier
argument. Le premier argument est généralement placé dans le registre edi qui, dans
ce cas, sera la chaîne de caractères que nous avons fournie en entrée. Si vous jetez un
coup d'œil à la fonction principale , vous verrez :

400e32 : e8 67 06 00 00 callq 40149e <read_line>


400e37 : 48 89 c7 déplacer %rax,%rdi
400e3a : e8 a1 00 00 00 callq 400ee0 <phase_1>

La valeur de retour (stockée dans rax ) de la fonction read_line a été placée dans le
registre rdi ( edi est un registre de 32 bits et rdi est le registre équivalent de 64 bits) et
sera utilisée comme premier argument pour la fonction qui sera appelée ensuite et
qui, dans ce cas, est phase_1 . Et c'est exactement ce que fait le code C :

/* Hmm... Six phases doivent être plus sûres qu'une seule phase ! */ input = read_line() ; /* Obtenir une
entrée */
phase_1(input) ; /* Exécuter la phase */

Ok, revenons à la fonction phase_1 . Nous savons maintenant quels sont les
arguments donnés à strings_not_equal et, après avoir exécuté cette fonction, il y a un
test pour vérifier le résultat :

http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 7/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

400ee9 : e8 4a 04 00 00 callq 401338 <strings_not_equal>


400eee : 85 c0 test %eax,%eax
400ef0 : 74 05 je 400ef7 <phase_1+0x17>
400ef2 : e8 43 05 00 00 callq 40143a <explode_bomb>

L'instruction de test effectue une opération ET bit à bit entre ses opérandes et place
les drapeaux appropriés dans le registre eflags . L'instruction je est une instruction de
saut conditionnel qui saute à l'emplacement spécifié uniquement si la comparaison
précédente a mis le ZF (Zero Flag) à 1 dans le registre eflags.

Ainsi, l'instruction test ne mettra ZF à 1 que lorsque nous aurons 0 dans eax , ce qui ne
se produit que lorsque strings_not_equal renvoie 0 . ( L'examen de strings_not_equal
ne révèle rien d'intéressant, c'est exactement ce que l'on attend d'une fonction
portant un tel nom. Il renvoie 1 si les deux arguments ne sont pas égaux et 0 sinon ).

Si les chaînes ne sont pas égales, le saut conditionnel n'est pas effectué et la ligne
suivante est exécutée, ce qui fait exploser la bombe. Si les chaînes sont égales, nous
sautons à 0x400eef7 et retournons à la page principale :

400ef0 : 74 05 je 400ef7 <phase_1+0x17>


400ef2 : e8 43 05 00 00 callq 40143a <explode_bomb>
400ef7 : 48 83 c4 08 ajouter $0x8,%rsp
400efb : c3 retq

Ok, nous savons maintenant que la première phase nous demande de fournir une
chaîne que nous ne connaissons pas. Comment allons-nous découvrir de quelle
chaîne il s'agit ? Nous devons commencer à exécuter le programme. Mais dans ce cas,
au lieu de l'exécuter comme vous le faites habituellement avec d'autres programmes,
nous allons l'exécuter avec gdb. gdb nous aidera à inspecter les valeurs et à trouver ce
qu'est cette mystérieuse chaîne de caractères.

$ gdb bomb

La ligne ci-dessus démarre gdb avec le programme de la bombe qui lui est attaché afin
que nous puissions exécuter la bombe et inspecter les valeurs, définir des points
d'arrêt, etc. Dans ce cas, nous avons déjà effectué la majeure partie du travail en
examinant uniquement le code d'assemblage et le code d'identification.
http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 6/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 1 - carlosgaldino

nous savons que la chaîne mystérieuse se trouve à l'adresse 0x402400 (alors qu'elle a
été chargée dans le registre esi à l'adresse 0x400ee4 ). Pour voir quelle est sa valeur,
nous pouvons simplement demander à gdb d'imprimer la valeur à l'adresse souhaitée
et de la traiter comme une séquence de caractères :

(gdb) p (char *) 0x402400


$1 = 0x402400 "Les relations frontalières avec le Canada n'ont jamais été aussi bonnes".

Et voilà ! Nous avons la ficelle qu'il nous faut.

Exécutez maintenant le programme :

(gdb) exécuter
Démarrage du programme : /home/carlos/Downloads/bomb/bomb
Bienvenue dans ma petite bombe diabolique. Vous disposez de 6 phases pour vous faire exploser. Bonne
journée !

En entrant dans la chaîne complète, nous verrons que la phase 1 a été désamorcée :

Les relations frontalières avec le Canada n'ont jamais été aussi bonnes.
Phase 1 désamorcée. Que diriez-vous de la prochaine ?

http://webcache.googleusercontent.com/search?q=cache:NPuQo5CSngAJ:blog.carlosgaldino.com/2015/11/12/defusing-a-binary-bomb-with-gdb-part-1.html+&... 9/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Partie 2
19 novembre 2015

Ce billet fait partie d'une série où je montre comment désamorcer une bombe
binaire en lisant le code assembleur et en utilisant gdb . Vous pouvez lire la
première partie si vous ne l'avez pas encore fait.

Après avoir désamorcé la première phase , nous avons été mis au défi de désamorcer
la suivante :

Les relations frontalières avec le Canada n'ont jamais été aussi bonnes.
Phase 1 désamorcée. Que diriez-vous de la prochaine ?

Le code d'assemblage correspondant dans la fonction principale est le suivant :

400e3a : e8 a1 00 00 00 callq 400ee0 <phase_1>


400e3f : e8 80 07 00 00 callq 4015c4 <phase_defused>
400e44 : bf a8 23 40 00 déplacer $0x4023a8,%edi
400e49 : e8 c2 fc ff ff callq 400b10 <puts@plt>
400e4e : e8 4b 06 00 00 callq 40149e <read_line>
400e53 : 48 89 c7 déplacer %rax,%rdi
400e56 : e8 a1 00 00 00 callq 400efc <phase_2>
400e5b : e8 64 07 00 00 callq 4015c4 <phase_defused>

Comme nous pouvons le voir (à 0x400e53 ), il place notre entrée dans le registre rdi
pour qu'elle soit utilisée comme premier argument de la phase_2 qui sera appelée par
l'instruction suivante. Tout comme on pourrait imaginer que le code C réel le fait :

printf("Phase 1 désamorcée. Que diriez-vous de la prochaine ?)

/* La deuxième phase est plus difficile. Personne ne comprendra jamais


* how to defuse this... */
input = read_line() ;
phase_2(input) ;

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 1/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

phase_defused() ;

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 2/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

À quoi ressemble la phase 2 ?

0000000000400efc <phase_2> :
400efc 55 pousser %rbp
400efd 53 pousser %rbx
400efe 48 83 ec 28 sous 0x28,%rsp
400f02 48 89 e6 déplacer %rsp,%rsi
400f05 e8 52 05 00 00 callq 40145c <read_six_numbers>
400f0a 83 3c 24 01 cmpl $0x1,(%rsp)
400f0e 74 20 je 400f30 <phase_2+0x34>
400f10 e8 25 05 00 00 callq 40143a <explode_bomb>
400f15 eb 19 jmp 400f30 <phase_2+0x34>
400f17 8b 43 fc déplacer -0x4(%rbx),%eax
400f1a 01 c0 ajouter %eax,%eax
400f1c 39 03 cmp %eax,(%rbx)
400f1e 74 05 je 400f25 <phase_2+0x29>
400f20 e8 15 05 00 00 callq 40143a <explode_bomb>
400f25 48 83 c3 04 ajouter $0x4,%rbx
400f29 48 39 eb cmp %rbp,%rbx
400f2c 75 e9 jne 400f17 <phase_2+0x1b>
400f2e eb 0c jmp 400f3c <phase_2+0x40>
400f30 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
400f35 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
400f3a eb db jmp 400f17 <phase_2+0x1b>
400f3c 48 83 c4 28 ajouter 0x28,%rsp
400f40 5b pop %rbx
400f41 5d pop %rbp
400f42 c3 retq

D'emblée, nous constatons que cette phase attend de nous que nous entrions six chiffres
:

400f05 : e8 52 05 00 00 callq 40145c <read_six_numbers>

Cela peut être confirmé en inspectant la fonction read_six_numbers :

000000000040145c <read_six_numbers>:
40145c : 48 83 ec 18 sous 0x18,%rsp
401460: 48 89 f2 déplac %rsi,%rdx
401463: 48 8d 4e 04 er lea 0x4(%rsi),%rcx
401467: 48 8d 46 14 lea 0x14(%rsi),%rax
40146b : 48 89 44 24 08 déplac %rax,0x8(%rsp)
401470: 48 8d 46 10 er lea 0x10(%rsi),%rax
401474: 48 89 04 24 déplac %rax,(%rsp)
er

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 3/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

401478: 4c 8d 4e 0c lea lea 0xc(%rsi),%r9


40147c : 4c 8d 46 08 0x8(%rsi),%r8
401480: be c3 25 40 00 déplace $0x4025c3,%esi
401485: b8 00 00 00 00 r déplace 0x0,%eax
40148a : e8 61 f7 ff ff r callq 400bf0 <__isoc99_sscanf@pl
t>
40148f : 83 f8 05 cmp $0x5,%eax
401492: 7f 05 jg 401499 <read_six_numbers+0
x3d>
401494: e8 a1 ff ff ff callq 40143a <explode_bomb>
401499: 48 83 c4 18 ajouter 0x18,%rsp
40149d : c3 retq

À 0x40148a , nous voyons qu'il appelle sscanf qui a l'objectif suivant :

#include <stdio.h>

int scanf(const char *format, ...) ;


int fscanf(FILE *stream, const char *format, ...) ;
int sscanf(const char *str, const char *format, ...) ;

La famille de fonctions scanf() analyse les entrées en fonction de leur format ,


comme décrit ci-dessous. Ce format peut contenir des spécifications de conversion
; les résultats de ces conversions, le cas échéant, sont stockés dans les
emplacements indiqués par les arguments de pointeur qui suivent le format .
Chaque argument de pointeur doit être d'un type approprié à la valeur renvoyée
par la spécification de conversion correspondante.

En suivant la même idée que celle utilisée pour la phase 1, nous pouvons confirmer
que cette fonction fait exactement ce que son nom suggère. En 0x401480 , quelque
chose est stocké dans esi pour être utilisé comme second argument de sscanf qui,
comme nous l'avons vu plus haut, est le format attendu pour notre entrée.

401480 : be c3 25 40 00 mov $0x4025c3,%esi

Ensuite, sur gdb , nous pouvons imprimer la valeur comme nous l'avons fait pour la
phase_1 :

(gdb) p (char *) 0x4025c3


$1 = 0x4025c3 "%d %d %d %d %d %d"

read_six_numbers vérifie alors si nous avons tapé au moins six nombres, si c'est le cas il

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 4/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

retourne, sinon la bombe explose.

De retour à la fonction phase_2 , nous constatons que notre premier nombre doit être 1 (
comparaison à 0x400f0a ), sinon la bombe explosera immédiatement :

400f05 : e852 05 00 00 callq 40145c <read_six_numbers>


400f0a : 83 3c 24 01 cmpl $0x1,(%rsp)
400f0e : 74 20 je 400f30 <phase_2+0x34>
400f10 : e8 25 05 00 00 callq 40143a <explode_bomb>

Après avoir confirmé que notre premier nombre était 1, il passe à 0x400f30 :

400f30 : 48 8d 5c 24 04 0x4(%rsp),%rbx
400f35 : 48 8d 6c 24 18 lea lea 0x18(%rsp),%rbp
400f3a : eb db jmp 400f17 <phase_2+0x1b>

En 0x400f30 , l'adresse du numéro suivant est stockée dans rbx et en 0x400f35, rbp reçoit
l'adresse juste après l'adresse du dernier numéro analysé par sscanf lors de
read_six_numbers .

(gdb) p $rsp+0x18
$2 = (void *) 0x7fffffddd8
(gdb) p $rsp
$3 = (void *) 0x7fffffddc0

Si l'on considère uniquement l'octet de poids faible : 0xd8 - 0xc0 = 0x18 . Ce qui
correspond à la décimale 24 . Chaque int prend quatre octets, de sorte que la structure
de la mémoire ressemble à l'image ci-dessous, ce qui explique pourquoi rbp retient
l'adresse après le sixième chiffre :

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 5/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino

p 0kco
Quai Oxc ? Ou.cc OkaH

Lk
HG+ OLVE BYTES
x, x xni Xs
AE : Ok'FFFFFFFDD
<6

L'exécution se poursuivra ensuite à 0x400f17 :

ADORESS (LowJ omen


BYTe)
VALEUR
400f17 : 8b 43 fc mov add -0x4(%rbx),%eax %eax,%eax
400f1a : 01 c0
400f1c : 39 03 cmp %eax,(%rbx)
400f1e : 74 05 je 400f25 <phase_2+0x29>
400f20 : e8 15 05 00 00 callq 40143a <explode_bomb>

A 0x400f17 , le nombre précédent est copié dans eax , puis l'instruction suivante
duplique cette valeur dans eax , qui est ensuite comparée à notre deuxième
nombre. S'ils sont égaux, la fonction poursuivra son exécution à 0x400f25 , sinon
vous savez quoi.

À 0x400f25 , le pointeur passe au numéro suivant. Ensuite, il vérifie si le pointeur a


dépassé le dernier nombre, ce qui signifie que les six nombres ont été vérifiés. Si ce
n'est pas le cas, il retourne à 0x400f17 pour vérifier le nombre suivant et si tous les
nombres ont déjà été vérifiés, il saute à 0x400f3c qui retournera alors à la page
principale.

400f25 : 48 83 c3 04 ajouter $0x4,%rbx


400f29 : 48 39 eb cmp %rbp,%rbx
400f2c : 75 e9 jne 400f17 <phase_2+0x1b>
400f2e : eb 0c jmp 400f3c <phase_2+0x40>

La vérification des nombres, le déplacement des pointeurs vers l'avant, les sauts en
avant et en arrière suggèrent que nous avons affaire à une boucle. En supposant
que p est un pointeur sur le premier nombre, la boucle de la phase_2 pourrait
ressembler à ce qui suit :

for (int *x = p + 1 ; x != (p + 6) ; x++) { int previous = *(x - 1) ;

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 2 - carlosgaldino
si (*x != précédent * 2)
explode_bomb() ;
}

Très bien, nous avons maintenant une idée de ce que devraient être les cinq
prochains chiffres. Ils doivent être le double du nombre précédent. Si nous
commençons à 1, le suivant est 2, le suivant est 4 et ainsi de suite. Cela vous
rappelle quelque chose, n'est-ce pas ? Notre entrée doit être les six premières
puissances de 2 :

• 20 = 1
• 21 = 2
• 22 = 4
• 23 = 8
• 24 = 16
• 25 = 32

Après avoir saisi les six chiffres, nous constatons que nous avons désamorcé la
deuxième phase :

Phase 1 désamorcée. Que diriez-vous de la suivante ? 1 2 4 8 16 32


C'est le numéro 2. Continuez !

http://webcache.googleusercontent.com/search?q=cache:0AQyhw4TGq4J:blog.carlosgaldino.com/2015/11/19/defusing-a-binary-bomb-with-gdb-part-2.html+&... 7/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 3 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Troisième partie
03 déc. 2015

Ce billet fait partie d'une série où je montre comment désamorcer une bombe
binaire en lisant du code assembleur et en utilisant gdb . Vous pouvez lire les
autres parties si vous ne l'avez pas encore fait.

Selon le processus habituel, après avoir désamorcé la deuxième phase, nous avons
été invités à désamorcer la troisième :

Bienvenue dans ma petite bombe diabolique. Vous disposez de 6 phases pour vous faire exploser.
Bonne journée !
Les relations frontalières avec le Canada n'ont jamais été aussi bonnes.
Phase 1 désamorcée. Que diriez-vous de la prochaine ?
1 2 4 8 16 32
C'est le numéro 2. Continuez !

Les instructions correspondantes sur l'ordinateur principal sont les suivantes :

400e5b : e8 64 07 00 00 callq 4015c4 <phase_defused>


400e60 : bf ed 22 40 00 déplacer $0x4022ed,%edi
400e65 : e8 a6 fc ff ff callq 400b10 <puts@plt>
400e6a : e8 2f 06 00 00 callq 40149e <read_line>
400e6f : 48 89 c7 déplacer %rax,%rdi
400e72 : e8 cc 00 00 00 callq 400f43 <phase_3>

Le code de la phase_3 est le suivant :

0000000000400f43 <phase_3> :
400f43 : 4883 ec 18 sous 0x18,%rsp
400f47 : 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
400f4c : 48 8d 54 24 08 lea 0x8(%rsp),%rdx
400f51 : êtr cf 25 40 00 déplac $0x4025cf,%esi
400f56 : e b8 00 00 00 00 er déplac 0x0,%eax
er
http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/14/03/defusing-a-binary-bomb-with-gdb-part-3.html+&cd... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 3 - carlosgaldino
400f5b e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@pl
t>
400f60 83 f8 01 cmp $0x1,%eax
400f63 7f 05 jg 400f6a <phase_3+0x27>
400f65 e8 d0 04 00 00 callq 40143a <explode_bomb>
400f6a 83 7c 24 08 07 cmpl 0x7,0x8(%rsp)
400f6f 77 3c ja 400fad <phase_3+0x6a>
400f71 8b 44 24 08 déplacer 0x8(%rsp),%eax
400f75 ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
400f7c b8 cf 00 00 00 déplacer 0xcf,%eax
400f81 eb 3b jmp 400fbe <phase_3+0x7b>
400f83 b8 c3 02 00 00 déplacer $0x2c3,%eax
400f88 eb 34 jmp 400fbe <phase_3+0x7b>
400f8a b8 00 01 00 00 déplacer 0x100,%eax
400f8f eb 2d jmp 400fbe <phase_3+0x7b>
400f91 b8 85 01 00 00 déplacer $0x185,%eax
400f96 eb 26 jmp 400fbe <phase_3+0x7b>
400f98 b8 ce 00 00 00 déplacer 0xce,%eax
400f9d eb 1f jmp 400fbe <phase_3+0x7b>
400f9f b8 aa 02 00 00 déplacer 0x2aa,%eax
400fa4 eb 18 jmp 400fbe <phase_3+0x7b>
400fa6 b8 47 01 00 00 déplacer $0x147,%eax
400fab eb 11 jmp 400fbe <phase_3+0x7b>
400fad e8 88 04 00 00 callq 40143a <explode_bomb>
400fb2 b8 00 00 00 00 déplacer 0x0,%eax
400fb7 eb 05 jmp 400fbe <phase_3+0x7b>
400fb9 b8 37 01 00 00 déplacer $0x137,%eax
400fbe 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2 74 05 je 400fc9 <phase_3+0x86>
400fc4 e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9 48 83 c4 18 ajouter 0x18,%rsp
400fcd c3 retq

A 0x400f51 , nous voyons qu'une valeur est stockée sur esi , eax est initialisé et
sscanf est appelé.

Si vous ne vous souvenez pas de la phase précédente, sscanf est une fonction qui
analyse les données d'entrée en fonction d'un format donné en argument. Ce
format doit être celui qui est stocké dans l'esi.

(gdb) p (char *) 0x4025cf $1 = 0x4025cf "%d %d"

Nous devons donc introduire 2 nombres entiers. Cela peut également être
confirmé par les instructions suivantes qui comparent si nous avons saisi plus d'un
nombre entier à

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/15/03/defusing-a-binary-bomb-with-gdb-part-3.html+&cd... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 3 - carlosgaldino

continuer à exécuter la troisième phase, sinon la bombe explosera.

400f60 : 83 f8 01 cmp $0x1,%eax


400f63 : 7f 05 jg 400f6a <phase_3+0x27>
400f65 : e8 d0 04 00 00 callq 40143a <explode_bomb>

Vous vous demandez peut-être comment sscanf a obtenu son premier argument,
qui est la chaîne de caractères utilisée comme source pour l'analyse des valeurs
souhaitées. Comme expliqué dans les articles précédents, le premier argument des
fonctions est généralement placé dans le registre rdi et n'importe quelle instruction
peut interagir avec n'importe quel registre, de la même manière que vous
interagissez avec une variable globale dans un programme. Si vous regardez à
0x400e6f dans la fonction principale , la chaîne que nous entrons comme entrée
pour la phase_3 est copiée dans rdi pour être ensuite utilisée comme premier
argument de sscanf :

400e6f : 48 89 c7 déplacer %rax,%rdi


400e72 : e8 cc 00 00 00 callq 400f43 <phase_3>

Ok, en continuant l'exécution de la phase_3 , la prochaine instruction à exécuter est


située à 0x400f6a (en supposant que nous ayons entré deux entiers, bien sûr). A cet
endroit, le programme compare le premier entier que nous avons donné en entrée.
Il doit être inférieur ou égal à 7, sinon l'exécution se poursuivra à 0x400fad .

400f6a : 83 7c 24 08 07 cmpl 0x7,0x8(%rsp)


400f6f : 77 3c ja 400fad <phase_3+0x6a>

Et à 0x400fad , nous savons ce qui nous attend :

400fad : e8 88 04 00 00 callq 40143a <explode_bomb>

En supposant que nous ayons saisi un nombre entier inférieur ou égal à 7, le


programme continue :

400f71 : 8b 44 24 08 déplacer 0x8(%rsp),%eax


400f75 : ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/16/03/defusing-a-binary-bomb-with-gdb-part-3.html+&cd... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 3 - carlosgaldino

La première instruction ci-dessus copiera le premier entier dans eax et, lors de la
deuxième instruction, sautera à un emplacement basé sur cet entier. Imaginons
que nous ayons saisi 0 comme premier nombre entier. Dans ce cas, le programme
sautera à l'adresse stockée à 0x402470 . La règle de calcul de l'adresse est la
suivante :

*(%rax * 8 + 0x402470)

C'est-à-dire : multipliez la valeur stockée sur rax par 8, ajoutez-la à 0x402470 et


lisez ensuite la valeur stockée à l'emplacement du résultat. En inspectant la valeur
de 0x402470 , nous voyons qu'il s'agit de l'adresse de la ligne suivante :

(gdb) x 0x402470 0x402470 : 0x00400f7c

Ainsi, en saisissant 0 comme premier chiffre, nous exécuterons les instructions


suivantes :
déplac
400f7c : b8 cf 00 00 00 er 0xcf,%eax
400f81 : eb 3b jmp 400fbe <phase_3+0x7b>

Cette opération stocke 0xcf (décimale 207) sur eax et saute ensuite à 0x400fbe qui
effectue ce qui suit :

400fbe : 3b 44 24 0c 0xc(%rsp),%eax
400fc2 : 74 05 cmp je 400fc9 <phase_3+0x86>
400fc4 : e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9 : 48 83 c4 18 ajouter 0x18,%rsp
400fcd : c3 retq

En d'autres termes, à 0x400fbe , le programme comparera notre deuxième nombre


à ce qui a été stocké sur eax , dans ce cas imaginaire où nous avons entré 0 comme
premier nombre, il comparera ensuite si notre deuxième nombre est 207. Si c'est
le cas, cela signifie que nous avons désamorcé la phase 3 :

0 207
À mi-chemin !

C'est donc tout ! C'est assez simple, non ? Mais qu'en est-il de toutes les autres
http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/17/03/defusing-a-binary-bomb-with-gdb-part-3.html+&cd... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 3 - carlosgaldino

instructions supérieures à 400fbe ? Quels sont leurs objectifs ?

Toutes ces instructions font partie d'une instruction de commutation . C'est


pourquoi, à 0x400f75 , l'adresse à laquelle le programme sautera sera calculée en
fonction de ce que nous avons saisi, contrairement à ce qui se passait auparavant
lorsque l'emplacement à sauter était codé en dur dans l'instruction elle-même1. En
examinant de plus près les instructions précédant 0x400fbe , nous constatons
qu'elles suivent toutes le même schéma : stocker une certaine valeur sur eax , puis
sauter à 0x400fbe pour comparer notre deuxième nombre à cette valeur stockée sur
eax. La phase_3 a donc plus d'une réponse, voyons-les toutes :

(gdb) x/8g 0x402470


0x402470 : 0x0000000000400f7c 0x0000000000400fb9
0x402480 : 0x0000000000400f83 0x0000000000400f8a
0x402490 : 0x0000000000400f91 0x0000000000400f98
0x4024a0 : 0x0000000000400f9f 0x0000000000400fa6

La commande ci-dessus demande à gdb d'examiner la mémoire commençant à


l'adresse 0x402470 et d'afficher huit blocs ( 8 dans la commande) de huit octets ( g
dans la commande, g comme dans mots géants). La sortie montre alors deux valeurs
par ligne, ce qui nous permet de construire un tableau reliant le premier numéro
d'entrée, l'adresse à laquelle le commutateur saute et ce qui devrait être le deuxième
numéro d'entrée :

Premièr Adresse Seconde attendue Seconde


e attendue
numéro
entrée pour sauter numéro d'entrée
nombre à (hexagone) d'entrée
(décimal)

0 0x400f7c 0xcf 207

1 0x400fb9 0x137 311

2 0x400f83 0x2c3 707


3
0x400f8a 0x100 256
4
0x400f91 0x185 389
5
0x400f98 0xce 206

6 0x400f9f 0x2aa 682

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/18/03/defusing-a-binary-bomb-with-gdb-part-3.html+&cd... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 3 - carlosgaldino

7 0x400fa6 0x147 327

Toutes les combinaisons ci-dessus peuvent être utilisées.

Notes

1. Dans ce cas, l' adressage relatif au PC est utilisé.

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/12/03/defusing-a-binary-bomb-with-gdb-part-3.html+&cd... 6/6
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Partie 4
25 avril 2016

Ce billet fait partie d'une série où je montre comment désamorcer une bombe
binaire en lisant le code assembleur et en utilisant gdb . Vous pouvez lire la
première partie si vous ne l'avez pas encore fait.

Nous sommes revenus sur le désamorçage de la quatrième phase de la bombe


binaire.

Le code de la phase_4 est le suivant :

000000000040100c <phase_4> :
40100c : 48 83 ec 18
401010: 48 8d 4c 24 0c sub lea 0x18,%rsp
401015: 48 8d 54 24 08 be cf 25 40 lea 0xc(%rsp),%rcx
40101a : 00 b8 00 00 00 00 mov 0x8(%rsp),%rdx $0x4025cf,%esi
40101f : mov 0x0,%eax
401024:
e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@pl
t>
401029: 83 f8 02 cmp $0x2,%eax
40102c : 75 07 jne 401035 <phase_4+0x29>
40102e : 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)
401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 callq 40143a <explode_bomb>
40103a : ba 0e 00 00 00 déplacer $0xe,%edx
40103f : êtr 00 00 00 00 déplacer $0x0,%esi
401044: e 8b 7c 24 08 déplacer 0x8(%rsp),%edi
401048: e8 81 ff ff ff callq 400fce <func4>
40104d : 85 c0 test %eax,%eax
40104f : 75 07 jne 401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmpl 0x0,0xc(%rsp)
401056: 74 05 je 40105d <phase_4+0x51>
401058: e8 dd 03 00 00 callq 40143a <explode_bomb>
40105d : 48 83 c4 18 ajouter 0x18,%rsp
401061: c3 retq

Tout comme pour la phase 3 , nous pouvons constater que cette phase attend deux

http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 1/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino

entiers en entrée. En 0x40101a , le même format utilisé précédemment est stocké


sur esi , qui est ensuite utilisé par sscanf en 0x401024.

(gdb) p (char *) 0x4025cf $1 = 0x4025cf "%d %d"

En 0x401029 , nous pouvons également confirmer que si nous entrons plus de deux
entiers, le code passe à 0x401035 qui appelle explode_bomb :

401029: 83 f8 02 cmp$0x2,%eax
40102c : 75 07 jne 401035 <phase_4+0x29>

Quels sont donc les chiffres exacts à saisir ? Il doit s'agir d'un nombre inférieur à 15
:

40102e : 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)


401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 callq 40143a <explode_bomb>

cmpl compare 0xe qui est 14 au premier entier1 que nous avons entré pour cette
phase. Ensuite, jbe ("jump below or equal") évitera de faire exploser la bombe si la
valeur est inférieure ou égale à 14.

Ensuite, nous pouvons voir qu'une certaine configuration est effectuée avant
d'appeler une nouvelle fonction, func4 :

40103a : ba 0e 00 00 00 déplacer $0xe,%edx


40103f : êtr 00 00 00 00 déplacer $0x0,%esi
401044: e 8b 7c 24 08 déplacer 0x8(%rsp),%edi
401048: e8 81 ff ff ff callq 400fce <func4>

edi est généralement utilisé comme registre pour contenir le premier argument,
esi le deuxième et edx le troisième. Le premier argument est le premier nombre que
nous avons fourni, les deuxième et troisième sont respectivement 0 et 14 .

Jetons un coup d'œil à func4 :

http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 2/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino

0000000000400fce
400fce : <func4>
48 83 éc: 08 sous $0x8,%rsp
400fd2 : 89 d0 déplace %edx,%eax
400fd4 : 29 f0 r sous %esi,%eax
400fd6 : 89 c1 déplace %eax,%ecx
400fd8 : c1 e9 1f r shr $0x1f,%ecx
400fdb : 01 c8 ajouter %ecx,%eax
400fdd : d1 f8 sar %eax
400fdf : 8d 0c 30 lea (%rax,%rsi,1),%ecx
400fe2 : 39 f9 cmp %edi,%ecx
400fe4 : 7e 0c jle 400ff2 <func4+0x24>
400fe6 : 8d 51 ff lea -0x1(%rcx),%edx
400fe9 : e8 e0 ff ff ff callq 400fce <func4>
400fee : 01 c0 ajouter %eax,%eax
400ff0 : eb 15 jmp 401007 <func4+0x39>
400ff2 : b8 00 00 00 00 déplace $0x0,%eax
400ff7 : 39 f9 r cmp %edi,%ecx
400ff9 : 7d 0c jge 401007 <func4+0x39>
400ffb : 8d 71 01 lea 0x1(%rcx),%esi
400ffe : e8 cb ff ff ff callq 400fce <func4>
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401007: 48 83 c4 08 ajouter $0x8,%rsp
40100b : c3 retq

En examinant les premières instructions, nous pouvons essayer d'écrire ce qui se


passe exactement avec les arguments qui ont été donnés à cette fonction. Les
instructions jusqu'à 0x400fe2 font en fait quelque chose comme ce qui suit :

int func4(int a, int b, int c) {


int x = c - b ; // 0x400fd2 et 0x400fd4
int y = x >> 31 ; // 0x400fd6 et 0x400fd8
x = x + y ; // 0x400fdb
x = x >> 1 ; // 0x400fdd
y = x + b ; // 0x400fdf
}

Il compare ensuite y à a ( notre premier nombre d'entrée pour cette phase) et si y


<= a , il passe à 0x400ff2 . Sinon, il appelle à nouveau func4 , mais cette fois-ci, c
sera y - 1 (défini à 0x400fe6 ). Ainsi, à 0x400fe9 , nous pouvons considérer que
l'invocation est la suivante :

func4(a, b, y - 1) ;
Après l'avoir appelé, vous pouvez voir que 0x400fee double le résultat de cette
invocation "interne" ( eax contient la valeur de retour de cette exécution) et saute
ensuite à 0x401007 qui nettoie le cadre de la pile pour cette invocation. Le résultat
http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 3/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino

de cet appel récursif est donc en fait :

return 2 * func4(a, b, y - 1) ;

Si y >= a , le code continuera son exécution à 0x400ff2 . À cette ligne, il fixe le


résultat possible à 0, puis compare à nouveau le même y avec a. Cette fois-ci, si y
>= a , il saute à 0x401007 et renvoie 0, c'est pourquoi eax a reçu la valeur 0 par
l'instruction précédente. Si y < a , func4 sera à nouveau appelé, mais dans ce cas, b
sera y + 1 (cette affectation a lieu à 0x400ffb ) et l'invocation suivante a lieu à
0x400ffe :

func4(a, y + 1, c) ;

Après le retour de cet appel récursif, la valeur de retour est fixée à 0x401003 en
utilisant le résultat de l'appel récursif, ce qui donne le résultat suivant :

return 2 * func4(a, y + 1, c) + 1 ;

Avec tout ce contexte, nous pouvons maintenant essayer de deviner ce qui se passe
exactement avec cette fonction :

int func4(int a, int b, int c) {


int x = c - b ;
int y = x >> 31 ;
x=x+y;
x = x >> 1 ;
y=x+b;

if (y <= a) {
if (y >= a) { return 0 ;
} else {
return 2 * func4(a, y + 1, c) + 1 ;
}
} else {
return 2 * func4(a, b, y - 1) ;

Rappelez-vous que l'appel initial à func4 est func4(ourFirstInputNumber, 0, 14) et que


ourFirstInputNumber <= 14 . Essayons de voir ce qui se passe si nous entrons 1
comme premier nombre :
http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 4/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino
func4(1, 0, 14) { int x = 14 - 0 ;
int y = 14 >> 31 ; x = 14 + 0 ;
x = 14 >> 1 ;
y=7+0;
}

Nous pouvons alors voir que func4 sera appelé par la clause else de la première
clause
si :

return 2 * func4(1, 0, 7 - 1) ;

Le premier appel récursif sera alors :

func4(1, 0, 6) { int x = 6 - 0 ;
int y = 6 >> 31 ; x = 6 + 0 ;
x = 6 >> 1 ;
y=3+0;
}

Une fois de plus, la même branche sera prise :

retour 2 * func4(1, 0, 3 - 1) ;

L'exécution sera alors :

func4(1, 0, 2) { int x = 2 - 0 ;

int y = 2 >> 31 ;
x=2+0;
x = 2 >> 1 ;
y=1+0;
}

Cette fois-ci, y == 1 , donc les deux branches if seront prises et 0 sera renvoyé de
cette invocation récursive. Rappelez-vous que nous avons invoqué cette fonction
deux fois, de sorte que le résultat final sera :

http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 5/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino
return func4(1, 0, 14) ;
return 2 * func4(1, 0, 6) ;
return 2 * func4(1, 0, 2) ;
retour 0 ;

Comme le dernier appel à func4 a retourné 0, le résultat final sera également 0 et


l'exécution se poursuivra cette fois sur la phase_4 à 0x40104d :

401048: e8 81 ff ff ff callq 400fce <func4>


40104d : 85 c0 test %eax,%eax
40104f : 75 07 jne 401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmpl 0x0,0xc(%rsp)
401056: 74 05 je 40105d <phase_4+0x51>
401058: e8 dd 03 00 00 callq 40143a <explode_bomb>
40105d : 48 83 c4 18 ajouter 0x18,%rsp
401061: c3 retq

Cette ligne et la ligne suivante testent si le résultat de l'invocation de func4 a


retourné 0 ou non , si c'est le cas notre première entrée est correcte et l'exécution
continue à 0x401051 . Cette instruction vérifie alors simplement si notre deuxième
entrée est 0. Si c'est le cas, la fonction revient et la phase 4 est désamorcée :

10
Vous l'avez donc compris. Essayez celui-ci.

Nous avons quelque chose d'intéressant ici, rappelez-vous qu'il y a deux


vérifications à propos de y et a ? La deuxième vérification utilise l'instruction jge
qui vérifie si la valeur est supérieure ou égale à (ce qui est assez évident si l'on
réfléchit à la signification de ge dans le nom de l'instruction). Il est intéressant de
noter que le contrôle précédent a également vérifié l'égalité avec jle . Ainsi, si y <=
a et que vous vérifiez ensuite si y >= a , il n'y a qu'un seul cas qui satisferait aux
deux conditions, à savoir y == a . Je ne sais pas si le compilateur a choisi jge alors
que le code était écrit sous la forme if (y == a) ou si le code était en fait écrit sous la
forme if (y >= a) .

Un autre aspect intéressant de cette phase est la manière dont le compilateur gère
les résultats des appels récursifs. Comme eax est un registre, les résultats de
chaque invocation récursive seront disponibles pour le cadre de pile qui l'a
invoquée et peuvent ensuite être simplement renvoyés sans sauvegarder le résultat

http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 6/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 4 - carlosgaldino

à un autre endroit. Vous voyez également qu'après avoir rappelé func4 , rien ne
gère les variables locales x et y, ce qui explique qu'elles soient également stockées
dans des registres au lieu d'être sauvegardées à l'intérieur de chaque trame de pile.

Un exercice laissé au lecteur est d'essayer de trouver les autres solutions possibles
pour cette phase, y compris une entrée qui n'appelle même pas func4
récursivement. Essayez également de voir quels sont les nombres invalides pour
cette phase et le résultat que renvoie func4 lorsque ces nombres sont utilisés.

Notes

1. 0x8(%rsp ) et 0xc(%rsp) stockent les deux numéros d'entrée en tant que


variables locales dans le cadre de la pile phase_4 .

http://webcache.googleusercontent.com/search?q=cache:POrmVxSy8kgJ:blog.carlosgaldino.com/2016/04/25/defusing-a-binary-bomb-with-gdb-part-4.html+&c... 7/7
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 5 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Cinquième partie
28 avril 2016

Ce billet fait partie d'une série où je montre comment désamorcer une bombe
binaire en lisant le code assembleur et en utilisant gdb . Vous pouvez lire la
première partie si vous ne l'avez pas encore fait.

Après avoir désamorcé la quatrième phase , le programme passe à la phase


suivante :

400ea2 : e8 f7 05 00 00 callq 40149e <read_line>


400ea7 : 48 89 c7 déplacer %rax,%rdi
400eaa : e8 b3 01 00 00 callq 401062 <phase_5>

Le code de la phase_5 est le suivant :

0000000000401062 <phase_5> :
401062: 53 pousser %rbx
401063: 48 83 ec 20 sous 0x20,%rsp
401067: 48 89 fb déplacer %rdi,%rbx
40106a : 64 48 8b 04 25 28 00 déplacer %fs:0x28,%rax
401071: 00 00
401073: 48 89 44 24 18 déplacer %rax,0x18(%rsp)
401078: 31 c0 xor %eax,%eax
40107a : e8 9c 02 00 00 callq 40131b <longueur_de_chaîne>
40107f : 83 f8 06 cmp $0x6,%eax
401082: 74 4e je 4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 callq 40143a <explode_bomb>
401089: eb 47 jmp 4010d2 <phase_5+0x70>
40108b : 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx
40108f : 88 0c 24 déplacer %cl,(%rsp)
401092: 48 8b 14 24 déplacer (%rsp),%rdx
401096: 83 e2 0f et $0xf,%edx
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx
4010a0 : 88 54 04 10 déplacer %dl,0x10(%rsp,%rax,1)
4010a4 : 48 83 c0 01 ajouter $0x1,%rax

http://webcache.googleusercontent.com/search?q=cache:r7Vvh9Ci4SUJ:blog.carlosgaldino.com/2016/04/28/defusing-a-binary-bomb-with-gdb-part-5.html+&cd... 1/5
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 5 - carlosgaldino

4010a8 : 48 83 f8 06 cmp $0x6,%rax


4010ac : 75 dd jne 40108b <phase_5+0x29>
4010ae : c6 44 24 16 00 movb 0x0,0x16(%rsp)
4010b3 : be 5e 24 40 00 déplace $0x40245e,%esi
4010b8 : 48 8d 7c 24 10 r lea 0x10(%rsp),%rdi
4010bd : e8 76 02 00 00 callq 401338 <strings_not_equal>
4010c2 : 85 c0 test %eax,%eax
4010c4 : 74 13 je 4010d9 <phase_5+0x77>
4010c6 : e8 6f 03 00 00 callq 40143a <explode_bomb>
4010cb : 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4010d0 : eb 07 jmp 4010d9 <phase_5+0x77>
4010d2 : b8 00 00 00 00 déplace $0x0,%eax
4010d7 : eb b2 r jmp 40108b <phase_5+0x29>
4010d9 : 48 8b 44 24 18 déplace 0x18(%rsp),%rax
4010de : 64 48 33 04 25 28 00 r xor %fs:0x28,%rax
4010e5 : 00 00
4010e7 : 74 05 je 4010ee <phase_5+0x8c>
4010e9 : e8 42 fa ff ff callq 400b30 <__stack_chk_fail@p
lt>
4010ee : 48 83 c4 20 ajouter 0x20,%rsp
4010f2 : 5b pop %rbx
4010f3 : c3 retq

Les premières lignes configurent la pile pour cette fonction et, à 0x40106a , le
protecteur de pile1 est mis en place.

En 0x40107a , une nouvelle fonction string_length est appelée pour vérifier la


longueur de l'entrée que nous avons donnée à la phase_5. Rappelez-vous que
l'argument pour la phase_5 est stocké dans le registre rdi et que la même valeur est
disponible lorsque la phase_5 est activée.
string_length est appelée. L'entrée doit comporter exactement six caractères,
comme le montre la comparaison avec 0x40107f . Si la longueur de l'entrée est
correcte, il passe alors à
0x4010d2 qui met rax à 0 et saute ensuite à 0x40108b pour poursuivre l'exécution
de cette phase.

En 0x40108b , le premier octet de la chaîne d'entrée est copié dans ecx . Remarquez
qu'au début de cette fonction, la chaîne d'entrée stockée sur rdi a été copiée sur rbx
à 0x401067 . L'instruction à 0x40108b utilise à la fois rbx et rax , mais comme rax a
une valeur de 0, l'adresse des données utilisée comme source sera uniquement
l'adresse stockée sur rbx. Nous pouvons le confirmer avec :

(gdb) p (char *) $rbx

http://webcache.googleusercontent.com/search?q=cache:r7Vvh9Ci4SUJ:blog.carlosgaldino.com/2016/04/28/defusing-a-binary-bomb-with-gdb-part-5.html+&cd... 2/5
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 5 - carlosgaldino

$1 = 0x6038c0 <input_strings+320> "input5"

Et pour voir chaque octet en hexadécimal :

(gdb) x/6xb $rbx


0x6038c0 <input_strings+320> : 0x69 0x6e 0x70 0x75 0x74
0x35

En passant à l'instruction suivante, nous pouvons également confirmer que l'octet


du premier caractère est stocké sur ecx :

(gdb) i r $ecx
ecx 0x69 105

0x69 est i dans la table ASCII.

Ensuite, dans les deux instructions suivantes, cet octet est copié dans rdx et, dans
0x401096 , un ET bit à bit est effectué par rapport à cet octet. La valeur après l'ET
bit à bit est ensuite utilisée comme décalage pour copier une valeur d'un
emplacement quelconque vers le même registre edx sur 0x401099 . Cette même
valeur d'un octet est ensuite stockée dans une variable locale à 0x4010a0 .
L'instruction suivante incrémente rax qui est ensuite vérifié par l'instruction
suivante pour voir si ce processus a été exécuté pour tous les caractères de notre
entrée. Si le processus n'a pas été exécuté pour tous les caractères, il saute à
nouveau à 0x40108b pour lire le caractère suivant et répéter les étapes ci-dessus.

À la fin de ce processus, une variable locale contiendra une nouvelle chaîne créée
en utilisant nos caractères d'entrée comme décalage vers une chaîne mystérieuse.

Si le processus a été exécuté pour tous les caractères, il prépare les arguments pour
l'appel de fonction suivant, qui commence à 0x4010ae . La nouvelle chaîne dont
nous parlons servira d'argument à la fonction strings_not_equal que nous avons déjà
vue dans cette série. L'autre chaîne à laquelle la nôtre sera comparée est située à
0x40245e , comme vous pouvez le voir à 0x4010b3 .

Après avoir appelé strings_not_equal , le résultat sera testé à 0x4010c2 et s'il est égal,
le code sautera à la fin de la phase_5 à 0x4010d9 qui vérifiera que la pile n'a pas été
corrompue et retournera. Si les cordes sont différentes, vous savez ce qui va se
passer.

http://webcache.googleusercontent.com/search?q=cache:r7Vvh9Ci4SUJ:blog.carlosgaldino.com/2016/04/28/defusing-a-binary-bomb-with-gdb-part-5.html+&cd... 3/5
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 5 - carlosgaldino

Maintenant que nous connaissons le déroulement de cette phase, il est temps de


voir quelle chaîne de caractères notre entrée

doit produire.

(gdb) p (char *) 0x40245e $2 = 0x40245e "flyers"

Il ne nous reste plus qu'à examiner la chaîne intermédiaire pour voir quels sont les
décalages que nous devons saisir pour que la chaîne finale soit composée d'éléments
volants.

(gdb) p (char *) 0x4024b0


$3 = 0x4024b0 <array>"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you ?"

En regardant la sortie ci-dessus, nous pouvons deviner que la chaîne intermédiaire


réelle doit être juste maduiersnfotvbyl . En regardant la position de chaque
caractère, nous pouvons alors vérifier que les décalages corrects doivent être :

lettre comp
ensati
f 0x9

l 0xf
y
0xe

e 0x5

r 0x6

s 0x7

La réponse est donc en fait toute séquence de caractères dont la représentation en


octets se termine par 9FE567 .

Si l'on considère uniquement les caractères imprimables de la table ASCII, on peut


établir le tableau suivant :

compe caractères
nsation possibles
0x9 )9IYiy

http://webcache.googleusercontent.com/search?q=cache:r7Vvh9Ci4SUJ:blog.carlosgaldino.com/2016/04/28/defusing-a-binary-bomb-with-gdb-part-5.html+&cd... 4/5
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 5 - carlosgaldino

0xf / ? O _ o DEL
0xe N^n~
0x5 0x6 0x7

Toute combinaison d'un seul caractère pour chaque décalage désamorcera la


phase_5.

La sixième et dernière phase sera abordée dans le prochain billet.

Notes

1. https://en.wikipedia.org/wiki/Buffer_overflow_protection

http://webcache.googleusercontent.com/search?q=cache:r7Vvh9Ci4SUJ:blog.carlosgaldino.com/2016/04/28/defusing-a-binary-bomb-with-gdb-part-5.html+&cd... 5/5
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Partie 6
19 mai 2016

Ce billet fait partie d'une série où je montre comment désamorcer une bombe
binaire en lisant le code assembleur et en utilisant gdb . Vous pouvez lire la
première partie si vous ne l'avez pas encore fait.

Nous voici arrivés à la dernière phase. C'est la phase la plus intéressante jusqu'à
présent. Le code de la phase_6 est le suivant :

00000000004010f4 <phase_6> :
4010f4 41 56 pousser %r14
4010f6 41 55 pousser %r13
4010f8 41 54 pousser %r12
4010fa 55 pousser %rbp
4010fb 53 pousser %rbx
4010fc 48 83 ec 50 sous $0x50,%rsp
401100 49 89 e5 déplacer %rsp,%r13
401103 48 89 e6 déplacer %rsp,%rsi
401106 e8 51 03 00 00 callq 40145c <read_six_numbers>
40110b 49 89 e6 déplacer %rsp,%r14
40110e 41 bc 00 00 00 00 déplacer $0x0,%r12d
401114 4c 89 ed déplacer %r13,%rbp
401117 41 8b 45 00 déplacer 0x0(%r13),%eax
40111b 83 e8 01 sous $0x1,%eax
40111e 83 f8 05 cmp $0x5,%eax
401121 76 05 jbe 401128 <phase_6+0x34>
401123 e8 12 03 00 00 callq 40143a <explode_bomb>
401128 41 83 c4 01 ajouter $0x1,%r12d
40112c 41 83 fc 06 cmp $0x6,%r12d
401130 74 21 je 401153 <phase_6+0x5f>
401132 44 89 e3 déplacer %r12d,%ebx
401135 48 63 c3 movslq %ebx,%rax
401138 8b 04 84 déplacer (%rsp,%rax,4),%eax
40113b 39 45 00 cmp %eax,0x0(%rbp)
40113e 75 05 jne 401145 <phase_6+0x51>
401140 e8 f5 02 00 00 callq 40143a <explode_bomb>
401145 83 c3 01 ajouter $0x1,%ebx

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 1/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

401148 83 fb 05 cmp $0x5,%ebx

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 2/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

40114b 7e e8 jle 401135 <phase_6+0x41>


40114d 49 83 c5 04 ajouter $0x4,%r13
401151 eb c1 jmp 401114 <phase_6+0x20>
401153 48 8d 74 24 18 lea 0x18(%rsp),%rsi
401158 4c 89 f0 déplace %r14,%rax
40115b b9 07 00 00 00 r déplace $0x7,%ecx
401160 89 ca r déplace %ecx,%edx
401162 2b 10 r sous (%rax),%edx
401164 89 10 déplace %edx,(%rax)
401166 48 83 c0 04 r ajouter $0x4,%rax
40116a 48 39 f0 cmp %rsi,%rax
40116d 75 f1 jne 401160 <phase_6+0x6c>
40116f be 00 00 00 00 déplace $0x0,%esi
401174 eb 21 r jmp 401197 <phase_6+0xa3>
401176 48 8b 52 08 déplace 0x8(%rdx),%rdx
40117a 83 c0 01 r ajouter $0x1,%eax
40117d 39 c8 cmp %ecx,%eax
40117f 75 f5 jne 401176 <phase_6+0x82>
401181 eb 05 jmp 401188 <phase_6+0x94>
401183 ba d0 32 60 00 déplace $0x6032d0,%edx
401188 48 89 54 74 20 r déplace %rdx,0x20(%rsp,%rsi,2)
40118d 48 83 c6 04 r ajouter $0x4,%rsi
401191 48 83 fe 18 cmp $0x18,%rsi
401195 74 14 je 4011ab <phase_6+0xb7>
401197 8b 0c 34 déplace (%rsp,%rsi,1),%ecx
40119a 83 f9 01 r cmp $0x1,%ecx
40119d 7e e4 jle 401183 <phase_6+0x8f>
40119f b8 01 00 00 00 déplace $0x1,%eax
4011a4 ba d0 32 60 00 r déplace $0x6032d0,%edx
4011a9 eb cb r jmp 401176 <phase_6+0x82>
4011ab 48 8b 5c 24 20 déplace 0x20(%rsp),%rbx
4011b0 48 8d 44 24 28 r lea 0x28(%rsp),%rax
4011b5 48 8d 74 24 50 lea 0x50(%rsp),%rsi
4011ba 48 89 d9 déplace %rbx,%rcx
4011bd 48 8b 10 r déplace (%rax),%rdx
4011c0 48 89 51 08 r déplace %rdx,0x8(%rcx)
4011c4 48 83 c0 08 r ajouter 0x8,%rax
4011c8 48 39 f0 cmp %rsi,%rax
4011cb 74 05 je 4011d2 <phase_6+0xde>
4011cd 48 89 d1 déplace %rdx,%rcx
4011d0 eb eb r jmp 4011bd <phase_6+0xc9>
4011d2 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
4011d9 00
4011da bd 05 00 00 00 déplace $0x5,%ebp
4011df 48 8b 43 08 r déplace 0x8(%rbx),%rax
4011e3 8b 00 r déplace (%rax),%eax
4011e5 39 03 r cmp %eax,(%rbx)
4011e7 7d 05 jge 4011ee <phase_6+0xfa>
4011e9 e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee 48 8b 5b 08 déplace 0x8(%rbx),%rbx
4011f2 83 ed 01 r sous $0x1,%ebp

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 3/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino
4011f5 : 75 e8 jne 4011df <phase_6+0xeb>
4011f7 : 48 83 c4 50 ajouter $0x50,%rsp
4011fb : 5b pop %rbx
4011fc : 5d pop %rbp
4011fd : 41 5c pop %r12
4011 et 41 5d pop %r13
suivants :
401201: 41 5e pop %r14
401203: c3 retq

Elle est plus longue que les autres phases et semble plus compliquée. Nous allons
donc la diviser en plusieurs parties afin d'expliquer le rôle de chacune d'entre elles.

La première partie que nous pouvons examiner est celle où la fonction s'initialise.
Il commence par enregistrer certaines valeurs de registres, car elles seront utilisées
comme variables locales dans cette fonction, puis il fait de la place pour d'autres
variables locales et lit l'entrée qui sera utilisée pour désamorcer la phase. À
0x401106 , nous pouvons voir que l'entrée de cette phase doit être composée de six
nombres :

4010f4 : 41 56 pousser %r14


4010f6 : 41 55 pousser %r13
4010f8 : 41 54 pousser %r12
4010fa : 55 pousser %rbp
4010fb : 53 pousser %rbx
4010fc : 48 83 ec 50 sous $0x50,%rsp
401100: 49 89 e5 déplacer %rsp,%r13
401103: 48 89 e6 déplacer %rsp,%rsi
401106: e8 51 03 00 00 callq 40145c <read_six_numbers>
40110b : 49 89 e6 déplacer %rsp,%r14
40110e : 41 bc 00 00 00 00 déplacer $0x0,%r12d
401114: 4c 89 ed déplacer %r13,%rbp
401117: 41 8b 45 00 déplacer 0x0(%r13),%eax
40111b : 83 e8 01 sous $0x1,%eax
40111e : 83 f8 05 cmp $0x5,%eax
401121: 76 05 jbe 401128 <phase_6+0x34>
401123: e8 12 03 00 00 callq 40143a <explode_bomb>

Après avoir lu les six nombres et placé le premier sur rsp , le code copie l'adresse
pointant vers le premier dans r14 , puis il configure d'autres variables et enfin, sur
0x40111e , il vérifie si le premier nombre que nous avons fourni est inférieur ou
égal à 6. Comment cela s'est-il produit ?

rsi est utilisé pour contenir le deuxième argument d'un appel de fonction et avant
d'appeler read_six_numbers (à 0x401103 ), l'adresse de rsp a été copiée dans rsi.
http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 4/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

à utiliser par read_six_numbers . C'est là que nos nombres ont été stockés, dans un
tableau qui commence à l'adresse de rsi . Cette même adresse est également
stockée sur rsp et r13 . Nous pouvons consulter les registres pour voir de quelle
adresse il s'agit :

(gdb) i r rsp rsp rsi rsi r13


0x7fffffdd60 0x7fffffdd60
0x7fffffdd60 140737488346464

r13 0x7fffffdd60 140737488346464

Après le retour de read_six_numbers , cette même adresse est stockée sur r14 à
0x40110b et à 0x40114 , elle est également stockée sur rbp.

Ensuite, à 0x401117 , la valeur stockée à l'adresse r13 , notre premier nombre, est
copiée dans eax et le code vérifie ensuite si elle est inférieure ou égale à 6 .

Maintenant que nous avons compris comment le chèque a été effectué, passons à
la partie suivante :

401128: 41 83 c4 01 ajouter $0x1,%r12d


40112c : 41 83 fc 06 cmp $0x6,%r12d
401130: 74 21 je 401153 <phase_6+0x5f>
401132: 44 89 e3 déplacer %r12d,%ebx
401135: 48 63 c3 movslq %ebx,%rax
401138: 8b 04 84 déplacer (%rsp,%rax,4),%eax
40113b : 39 45 00 cmp %eax,0x0(%rbp)
40113e : 75 05 jne 401145 <phase_6+0x51>
401140: e8 f5 02 00 00 callq 40143a <explode_bomb>

Rappelez-vous qu'à la ligne 0x40110e , le registre r12d a stocké la valeur 0. Les trois
premières lignes servent donc uniquement à vérifier si le code a déjà effectué 6
itérations. Continuons à 0x401132 où la nouvelle valeur de r12d (qui est 1 pour la
première itération) est copiée dans ebx qui est ensuite copiée dans rax par
extension de signe d'un double mot (4 octets) à un quadruple mot (8 octets)
puisque ebx est un registre de 32 bits tandis que rax est un registre de 64 bits.

Ensuite, le numéro suivant que nous avons saisi est comparé au premier. Le
deuxième nombre est copié dans eax par cette instruction :

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 5/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

401138 : 8b 04 84 mov (%rsp,%rax,4),%eax


Ce que cette ligne fait en réalité, c'est multiplier par 4 la valeur sur rax ( 1
puisqu'elle vient de r12d ) et ajouter cette valeur à la valeur stockée sur rsp (l'adresse
de départ du tableau contenant nos nombres d'entrée). Pour la première itération,
l'adresse résultante sera :

(gdb) x $rsp+$rax*0x4 0x7fffffdd64 : 0x00000002

La valeur stockée à cette adresse est alors copiée dans eax . Pour la première
itération, il s'agit de notre deuxième numéro d'entrée.

Ensuite, notre deuxième valeur (sur eax ) est comparée à la première pour voir si
elles ne sont pas égales et passer à la partie suivante :

401145: 83 c3 01 ajouter $0x1,%ebx


401148: 83 fb 05 cmp $0x5,%ebx
40114b : 7e e8 jle 401135 <phase_6+0x41>
40114d : 49 83 c5 04 ajouter $0x4,%r13
401151: eb c1 jmp 401114 <phase_6+0x20>

Les trois premières lignes vérifieront si nous avons effectué cette vérification pour
les six nombres, ce qui signifie que nous ne pouvons pas saisir de nombres répétés.
Ensuite, à 0x40114d , r13 est modifié pour contenir l'adresse du deuxième numéro
d'entrée en ajoutant 4 octets ( sizeof(int) ) à l'adresse que r13 stocke actuellement. Il
retourne ensuite à 0x401114 pour effectuer les mêmes vérifications avec les autres
numéros que nous avons fournis.

Nous connaissons à présent certains éléments concernant les données attendues :

• Il doit s'agir de six chiffres ;


• Ils doivent être inférieurs ou égaux à 6 ;
• Ils ne peuvent pas se répéter.

Continuons à voir quelles sont les autres caractéristiques que ces nombres doivent
avoir.

Après avoir effectué ces vérifications initiales, le code passe à 0x401153 :

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 6/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino
401153 : 48 8d 74 24 18 lea 0x18(%rsp),%rsi
401158 : 4c 89 f0 déplacer %r14,%rax
40115b : b9 07 00 00 00 déplac $0x7,%ecx
401160: 89 ca er déplac %ecx,%edx
401162: 2b 10 er sous (%rax),%edx
401164: 89 10 déplac %edx,(%rax)
401166: 48 83 c0 04 er ajouter $0x4,%rax
40116a : 48 39 f0 cmp %rsi,%rax
40116d : 75 f1 jne 401160 <phase_6+0x6c>
40116f : be 00 00 00 00 déplac $0x0,%esi
401174: eb 21 er jmp 401197 <phase_6+0xa3>

La première ligne de cette partie définit simplement l'adresse qui signifie que nous
avons itéré sur les six nombres. Le premier nombre est stocké à l'adresse détenue
par rsp et le sixième nombre sera stocké à $rsp + 0x14 (adresse de départ + décalage
de 5 int ).

r14 contient également l'adresse du premier nombre, qui sera copiée dans rax à
0x401158 pour être utilisée dans cette itération. Ensuite, sur les deux lignes
suivantes, ecx et edx stockent la valeur 7 . Après la configuration, l'itération
proprement dite commencera par la soustraction de edx de la valeur stockée à
l'adresse rax (notre premier nombre dans la première itération). À 0x401164 , le
résultat de cette soustraction remplacera la valeur de rax , puis à 0x401166 , le code
passera au prochain int que nous avons fourni, comparera à 0x40116d si nous
avons itéré sur les six nombres et reviendra à 0x401160 si ce n'est pas le cas, sinon
sortira de la boucle et poursuivra l'exécution à 0x401197 .

Simulons ce qui se passe après l'exécution de cette boucle. Supposons que nous
ayons saisi 1 2 3 4 5 6 comme numéros d'entrée pour cette phase. Après avoir itéré
dans cette boucle, notre tableau aura les nouvelles valeurs suivantes : 6 5 4 3 2 1 .
La boucle modifie simplement tous les nombres du tableau pour qu'ils soient
abs(n-7) .

Après avoir quitté la boucle, nous continuons à 0x401197 , ce qui nous amène à la
partie suivante de cette phase :

401176: 48 8b 52 08 déplac 0x8(%rdx),%rdx


40117a : 83 c0 01 er ajouter $0x1,%eax
40117d : 39 c8 cmp %ecx,%eax
40117f : 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 déplac $0x6032d0,%edx
er
http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 7/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

401188: 48 89 54 74 20 déplac %rdx,0x20(%rsp,%rsi,2)


40118d : 48 83 c6 04 er ajouter $0x4,%rsi
401191: 48 83 fe 18 cmp $0x18,%rsi
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 déplac (%rsp,%rsi,1),%ecx
40119a : 83 f9 01 er cmp $0x1,%ecx
40119d : 7e e4 jle 401183 <phase_6+0x8f>
40119f : b8 01 00 00 00 déplac $0x1,%eax
4011a4 : ba d0 32 60 00 er déplac $0x6032d0,%edx
4011a9 : eb cb er jmp 401176 <phase_6+0x82>

Bien que la première ligne de cette partie se trouve à 0x401176 , l'exécution


commence en fait à 0x401197 . Après l'exécution de cette ligne, ecx contiendra le
premier nombre de notre tableau parce que la valeur stockée sur rsi est 0 ( à partir
de 0x40116f ) et l'instruction sur 0x401197 signifie : copier la valeur stockée par
l'adresse de $rsi*0x1 + $rsp à ecx . Cette opération signifie clairement qu'elle fait
partie d'une itération et nous pouvons supposer que rsi sera mis à jour au cours du
processus pour passer en revue les autres nombres du tableau.

401197: 8b 0c 34 déplac (%rsp,%rsi,1),%ecx


40119a : 83 f9 01 er cmp $0x1,%ecx
40119d : 7e e4 jle 401183 <phase_6+0x8f>
40119f : b8 01 00 00 00 déplac $0x1,%eax
4011a4 : ba d0 32 60 00 er déplac $0x6032d0,%edx
4011a9 : eb cb er jmp 401176 <phase_6+0x82>

Si le nombre actuel sur ecx est inférieur ou égal à 1, le code sautera à 0x401183 ,
sinon il sautera à 0x401176 .

Dans la dernière partie, notre tableau est devenu : 6 5 4 3 2 1 . Le code sautera


donc à 0x401176 . Voyons ce qu'il en est.

déplac
401176: 48 8b 52 08 er 0x8(%rdx),%rdx
40117a : 83 c0 01 ajouter $0x1,%eax
40117d : 39 c8 cmp %ecx,%eax
40117f : 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>

Remarquez qu'avant de sauter à 0x401176 , l'adresse 0x6032d0 a été stockée sur edx
. Ensuite, la valeur stockée après les 8 premiers octets de cette adresse sera copiée
dans rdx sur 0x401176 . Après cette opération, eax sera incrémenté et comparé à

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 8/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

ecx pour sauter conditionnellement à un autre endroit de cette partie ou à


0x401176. Dans ce cas, la valeur initiale de eax est 1 et a été définie à 0x40119f
avant de passer à 0x401176. ecx contient la valeur 6, nous retournons donc à
0x401176 et copions la valeur de $rdx + 0x8 dans rdx , incrémentons eax et vérifions
par rapport à ecx.

Les valeurs de ecx et eax ne correspondent qu'après six itérations : dans notre
exemple, ecx commence par 6 et eax par 1 . Dans ce cas, avant de sauter à
0x401188 , rdx aura la valeur stockée dans $rdx + 0x48 (six fois en ajoutant 0x8 à
l'adresse initiale et en copiant la valeur de la nouvelle adresse dans rdx ).

Le code passe ensuite à 0x401188 :

401183: ba d0 32 60 00 déplac $0x6032d0,%edx


401188: 48 89 54 74 20 er déplac %rdx,0x20(%rsp,%rsi,2)
40118d : 48 83 c6 04 er ajouter $0x4,%rsi
401191: 48 83 fe 18 cmp $0x18,%rsi
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 déplac (%rsp,%rsi,1),%ecx
40119a : 83 f9 01 er cmp $0x1,%ecx
40119d : 7e e4 jle 401183 <phase_6+0x8f>
40119f : b8 01 00 00 00 déplac $0x1,%eax
4011a4 : ba d0 32 60 00 er déplac $0x6032d0,%edx
4011a9 : eb cb er jmp 401176 <phase_6+0x82>

À cette ligne, l'adresse détenue par rdx sera copiée à l'adresse résultant de :
$rsi*0x2 + $rsp + 0x20 . rsi est l'index de l'itération en cours :

(gdb) i r rsi rsi 0x0 0

Ensuite, rsi est incrémenté de 4 ( sizeof(int) ) et comparé à 0x18 pour voir si nous
avons itéré sur les six nombres. Si ce n'est pas le cas, à 0x401197 , ecx obtient le
numéro suivant de notre tableau et l'itération suivante commence.

Maintenant que nous savons en quoi consiste cette itération, voyons ce que
contient exactement l'adresse initiale de rdx :

(gdb) x 0x6032d0
0x6032d0 <node1> : 0x0000014c

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 9/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

Huh, node1 , un nom intéressant, n'est-ce pas ? Voyons ce que cette adresse plus 8
octets nous réservent :

(gdb) x 0x6032d0+0x8
0x6032d8 <node1+8> : 0x006032e0

En regardant ce qu'il y a sur 0x6032e0 :

(gdb) x 0x6032e0
0x6032e0 <node2> : 0x000000a8

Aha ! Cela ressemble à une liste chaînée. Pour voir l'adresse du nœud3 :

(gdb) x 0x6032e0+0x8
0x6032e8 <node2+8> : 0x006032f0

Et ce que node3 stocke :

(gdb) x *(0x6032e0+0x8)
0x6032f0 <node3> : 0x0000039c

Nous avons une liste chaînée qui contient une valeur int , l'identifiant du nœud et
le pointeur vers le nœud suivant, quelque chose comme ce qui suit :

struct node {
int x ;
int i ;
struct node *next;
};

Ainsi, lorsque le code saute à 0x401188 , rdx aura l'adresse de la valeur stockée par
node6 puisque notre tableau est 6 5 4 3 2 1 et qu'il est passé par

0x401176 six fois :

(gdb) i r rdx
rdx 0x603320 6304544
(gdb) x 0x6032d0+0x48
http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 10/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino
0x603318 <node5+8> : 0x00603320
(gdb) x $rdx
0x603320 <node6> : 0x000001bb

L'adresse rdx , qui contient la valeur 0x1bb , sera placée en première position d'un
nouveau tableau commençant à $rsp + 0x20 . Puisque ce code itère sur les six
nombres, après avoir exécuté cette partie pour tous les nombres, ce nouveau
tableau stockera en fait les adresses contenant les valeurs que le nœud
correspondant stocke, sur la base de notre tableau d'entrée transformé.

Explication : de 0x401176 à 0x401181 , le code recherche le nœud correspondant à


l'itération en cours. En 0x401188 , l'adresse de la valeur x détenue par le nœud est
alors copiée à l'index de l'itération en cours sur le nouveau tableau. L'itération
suivante commence alors.

Voyons quelles sont les valeurs stockées par chaque nœud et leurs adresses. Nous
commençons par définir une commande pour imprimer les valeurs des nœuds et
passer au nœud suivant :

définir plist
set var $n = $arg0
while $n
printf "node%d (%p) : value = %#.3x, next=%p\n", *($n+0x4), $n, *$n,
*($n+0x8)
set var $n = *($n+0x8)
fin
fin

Impression des valeurs :

(gdb) plist 0x6032d0


nœud1 (0x6032d0) : valeur = 0x14c, next=0x6032e0
nœud2 (0x6032e0) : valeur = 0x0a8, next=0x6032f0
nœud3 (0x6032f0) : valeur = 0x39c, next=0x603300
nœud4 (0x603300) : valeur = 0x2b3, next=0x603310
nœud5 (0x603310) : valeur = 0x1dd, next=0x603320
nœud6 (0x603320) : value = 0x1bb, next=(nil)
Après avoir itéré sur les six nombres en utilisant notre tableau d'entrée qui a été
transformé en 6 5 4 3 2 1 , le nouveau tableau (commençant à $rsp + 0x20 )
contiendra les adresses de x dans l'ordre suivant : node6 node5 node4 node3 node2
node1 .

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 11/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

(gdb) x/6gx $rsp+0x20


0x7fffffdd80 : 0x0000000000603320 0x00000000603310
0x7fffffdd90 : 0x0000000000603300 0x000000006032f0
0x7fffffdda0 : 0x00000000006032e0 0x000000006032d0

Après avoir créé ce nouveau tableau, le code poursuit son exécution à 0x4011ab ,
qui est la partie suivante :

4011ab : 48 8b 5c 24 20 déplace 0x20(%rsp),%rbx


4011b0 : 48 8d 44 24 28 r lea 0x28(%rsp),%rax
4011b5 : 48 8d 74 24 50 lea 0x50(%rsp),%rsi
4011ba : 48 89 d9 déplace %rbx,%rcx
4011bd : 48 8b 10 r déplace (%rax),%rdx
4011c0 : 48 89 51 08 r déplace %rdx,0x8(%rcx)
4011c4 : 48 83 c0 08 r ajouter 0x8,%rax
4011c8 : 48 39 f0 cmp %rsi,%rax
4011cb : 74 05 je 4011d2 <phase_6+0xde>
4011cd : 48 89 d1 déplace %rdx,%rcx
4011d0 : eb eb r jmp 4011bd <phase_6+0xc9>
4011d2 : 48 c7 42 08 00 00 00 movq 0x0,0x8(%rdx)
4011d9 : 00
4011da : bd 05 00 00 00 déplace $0x5,%ebp
4011df : 48 8b 43 08 r déplace 0x8(%rbx),%rax
4011e3 : 8b 00 r déplace (%rax),%eax
4011e5 : 39 03 r cmp %eax,(%rbx)
4011e7 : 7d 05 jge 4011ee <phase_6+0xfa>
4011e9 : e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee : 48 8b 5b 08 déplace 0x8(%rbx),%rbx
4011f2 : 83 ed 01 r sous $0x1,%ebp
4011f5 : 75 e8 jne 4011df <phase_6+0xeb>

A la première ligne de cette partie, rbx obtient la valeur du premier élément du


nouveau tableau qui est l'adresse de x pour le nœud6 . À la ligne suivante, rax
obtient le deuxième élément du nouveau tableau et à la troisième ligne, rsi obtient
une adresse située juste après le dernier élément de ce nouveau tableau,
probablement pour vérifier plus tard si nous avons itéré sur l'ensemble du
nouveau tableau.

A 0x4011ba , rcx contiendra la valeur du premier élément du nouveau tableau, puis


rdx obtiendra la deuxième valeur et à la ligne suivante, 0x4011c0 , cette valeur sera
copiée dans $rcx + 0x8 . Revenons en arrière une minute et voyons les valeurs dans
les deux registres après l'exécution de l'instruction à 0x4011c0 :

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 12/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino
(gdb) i r rcx rdx
rcx 0x603320 6304544
rdx 0x603310 6304528

$rcx + 0x8 est l'adresse qui contient le pointeur sur l'élément suivant de la liste et,
après l'exécution de 0x4011c0 , il pointera sur la valeur stockée par rdx :

(gdb) x $rcx+0x8
0x603328 <node6+8> : 0x0000000000603310

Ensuite, à 0x4011c4 , la valeur suivante du nouveau tableau est placée dans rax
pour l'itération suivante, qui est comparée à rsi dans la ligne suivante, et le
processus se répète. À la fin de cette opération, le pointeur suivant de chaque nœud
sera modifié en fonction des valeurs du nouveau tableau. Comme nous l'avons vu
ci-dessus, le nouveau tableau contient les valeurs suivantes :

(gdb) x/6gx $rsp+0x20


0x7fffffdd80 : 0x0000000000603320 0x00000000603310
0x7fffffdd90 : 0x0000000000603300 0x000000006032f0
0x7fffffdda0 : 0x00000000006032e0 0x000000006032d0

Ces valeurs correspondent au nœud6 nœud5 nœud4 nœud3 nœud2 nœud1 . Après
l'itération ci-dessus, les pointeurs seront donc modifiés pour refléter cet ordre.
Nous pouvons le confirmer avec notre commande plist après avoir exécuté
l'instruction sur 0x4011d2 :

(gdb) plist 0x603320


nœud6 (0x603320) : valeur = 0x1bb, next=0x603310
nœud5 (0x603310) : valeur = 0x1dd, next=0x603300
nœud4 (0x603300) : valeur = 0x2b3, next=0x6032f0
nœud3 (0x6032f0) : valeur = 0x39c, next=0x6032e0
nœud2 (0x6032e0) : valeur = 0x0a8, next=0x6032d0
node1 (0x6032d0) : value = 0x14c, next=(nil)

Avec la saisie initiale de 1 2 3 4 5 6 , le code a inversé la liste. Notez que j'ai utilisé
l'adresse du nœud 6 comme adresse de départ de la liste car c'est l'ordre du tableau
situé à $rsp + 0x20 . Remarquez également qu'à 0x4011d2 , le pointeur suivant de la
dernière itération reçoit la valeur NULL et, dans notre cas, il s'agit de node1->next .

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 13/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino
4011da : bd 05 00 00 00 déplacer $0x5,%ebp
4011df : 48 8b 43 08 déplacer 0x8(%rbx),%rax
4011e3 : 8b 00 déplacer (%rax),%eax
4011e5 : 39 03 cmp %eax,(%rbx)
4011e7 : 7d 05 jge 4011ee <phase_6+0xfa>
4011e9 : e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee : 48 8b 5b 08 déplacer 0x8(%rbx),%rbx
4011f2 : 83 ed 01 sous $0x1,%ebp
4011f5 : 75 e8 jne 4011df <phase_6+0xeb>

Maintenant que la liste a été modifiée, l'exécution se poursuit à 0x4011da en


stockant la valeur 5 dans ebp . Ensuite, l'adresse de la valeur x du nœud suivant est
stockée dans rax et, dans la ligne suivante, la valeur x réelle est stockée dans eax
(registre de 32 bits puisque nous avons affaire à int ). À 0x4011e5 , la valeur x du
premier nœud (à rbx ) est comparée à la valeur x du second et si la première valeur
est supérieure ou égale à la seconde, le code passe à 0x4011ee qui met à jour la
valeur de rbx pour pointer vers la valeur x suivante et met également à jour la
valeur de ebp qui est ensuite comparée pour voir si nous avons itéré sur l'ensemble
de la liste.

Cette itération vérifie donc que la valeur x du nœud actuel est supérieure ou égale à
la valeur x suivante pour tous les nœuds de la liste. Si ce n'est pas le cas, la bombe
explose, comme on peut le voir à 0x4011e9 .

L'autre partie de cette fonction commençant à 0x4011f7 nettoie le cadre de la pile


pour la phase_6 et revient.

Maintenant que nous avons vu tout ce que fait cette fonction, nous savons que nos
nombres d'entrée sont utilisés pour trier la liste chaînée dans l'ordre
décroissant.

N'oubliez pas qu'avant d'être utilisé pour réorganiser la liste, chaque nombre
d'entrée sera transformé en abs(n-7) .

Les valeurs de chaque nœud sont les suivantes

x
nœud # x (déc)
(hexagone
1 0x14c 332

2 0x0a8 168

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 14/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 6 - carlosgaldino

3
0x39c 924
4
0x2b3 691
5
0x1dd 477

6 0x1bb 443

Les valeurs de x pour la liste finale doivent être dans l'ordre suivant :

924 -> 691 -> 477 -> 443 -> 332 -> 168

Ce qui signifie que la liste doit être réordonnée comme suit :

nœud3 -> nœud4 -> nœud5 -> nœud6 -> nœud1 -> nœud2

La solution pour cette phase est donc la suivante :

432165
Félicitations ! Vous avez désamorcé la bombe !

Enfin ! La bombe a été désamorcée !

Ou non ? Il y a quelque chose de bizarre dans le fichier C. La fonction principale se


termine ainsi :

input = read_line () ;
phase_6(input) ;
phase_defused() ;

/* Wow, ils ont réussi ! Mais quelque chose ne manque-t-il


pas ? Peut-être
* quelque chose qu'ils ont négligé ? Mua ha ha ha ha ! */

retour 0;

http://webcache.googleusercontent.com/search?q=cache:1K1SsGLv47UJ:blog.carlosgaldino.com/2016/05/19/defusing-a-binary-bomb-with-gdb-part-6.html+... 15/15
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino

Désamorcer une bombe binaire


avec gdb
- Partie 7
24 mai 2016

Ce billet fait partie d'une série où je montre comment désamorcer une bombe
binaire en lisant le code assembleur et en utilisant gdb . Vous pouvez lire la
première partie si vous ne l'avez pas encore fait.

Nous y sommes. Nous en sommes enfin au dernier billet de la série.

Dans le dernier message , la bombe a été désamorcée mais il y avait quelque chose
de bizarre dans le fichier C. C'est la fin de la fonction principale :

input = read_line () ;
phase_6(input) ;
phase_defused() ;

/* Wow, ils ont réussi ! Mais quelque chose ne manque-t-il


pas ? Peut-être
* quelque chose qu'ils ont négligé ? Mua ha ha ha ha ! */

retour 0;

Et j'ai laissé un indice dans le dernier message à propos d'un appel à une fonction
secret_phase à partir de phase_defused .

401630 : e8 0d fc ff ff callq 401242 <secret_phase>

phase_defused est une fonction qui est appelée à chaque fois qu'une phase est
désamorcée :

00000000004015c4 <phase_defused>:
4015c4 : 48 83 ec 78 sous 0x78,%rsp
4015c8 : 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
4015cf : 00 00

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino

4015d1 : 48 89 44 24 68 %rax,0x68(%rsp)
4015d6 : 31 c0 mov xor %eax,%eax
4015d8 : 83 3d 81 21 20 00 06 cmpl $0x6,0x202181(%rip)
# 603760 <nombre_d'entr chaînes>
4015df : ées_ 75 5e jne 40163f <phase_defused+0x7b
>
4015e1 : 4c 8d 44 24 10 lea 0x10(%rsp),%r8
4015e6 : 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
4015eb : 48 8d 54 24 08 lea 0x8(%rsp),%rdx
4015f0 : être 19 26 40 00 déplace $0x402619,%esi
4015f5 : bf 70 38 60 00 r déplace $0x603870,%edi
4015fa : e8 f1 f5 ff ff r callq 400bf0 <__isoc99_sscanf@pl
t>
4015 et 83 f8 03 cmp $0x3,%eax
suivants
401602: : 75 31 jne 401635 <phase_defused+0x71
>
401604: être 22 26 40 00 déplace $0x402622,%esi
401609: 48 8d 7c 24 10 r lea 0x10(%rsp),%rdi
40160e : e8 25 fd ff ff callq 401338 <strings_not_equal>
401613: 85 c0 test %eax,%eax
401615: 75 1e jne 401635 <phase_defused+0x71
>
401617: bf f8 24 40 00 déplace $0x4024f8,%edi
40161c : e8 ef f4 ff ff r callq 400b10 <puts@plt>
401621: bf 20 25 40 00 déplace $0x402520,%edi
401626: e8 e5 f4 ff ff r callq 400b10 <puts@plt>
40162b : b8 00 00 00 00 déplace $0x0,%eax
401630: e8 0d fc ff ff r callq 401242 <secret_phase>
401635: bf 58 25 40 00 déplace $0x402558,%edi
40163a : e8 d1 f4 ff ff r callq 400b10 <puts@plt>
40163f : 48 8b 44 24 68 déplace 0x68(%rsp),%rax
401644: 64 48 33 04 25 28 00 r xor %fs:0x28,%rax
40164b : 00 00
40164d : 74 05 je 401654 <phase_defused+0x90
>
40164f : e8 dc f4 ff ff callq 400b30 <__stack_chk_fail@p
lt>
401654: 48 83 c4 78 ajouter 0x78,%rsp
401658: c3 retq
401659: 90 nop
40165a : 90 nop
40165b : 90 nop
40165c : 90 nop
40165d : 90 nop
40165e : 90 nop
40165f : 90 nop

Les premières lignes jusqu'à 0x4015d8 servent à définir le protecteur de pile1 puis à
sauvegarder rax avant de le mettre à 0 à 0x4015d6 . Puis, à 0x4015d8 , on trouve

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino
compare si nous avons déjà parcouru les six phases en regardant le nombre de
chaînes d'entrée. Cette comparaison ne sera vraie qu'après avoir désamorcé les six
phases, donc avant le dernier message, le code sautait toujours à 0x40163f qui
restaurait la valeur de rax et vérifiait le protecteur de pile avant de revenir.

Maintenant que la sixième phase a été désamorcée, le code continue sur 0x4015e1 .
Dans les trois lignes suivantes, les registres r8 , rcx et rdx stockent les adresses des
variables locales, puis à 0x4015f0 et 0x4015f5 , esi et edi reçoivent deux adresses.
Examinons-les pour voir ce que contient chaque adresse :

(gdb) p (char *) 0x402619


$1 = 0x402619 "%d %d %s"
(gdb) p (char *) 0x603870
$2 = 0x603870 <input_strings+240> "1 0"

Comment ai-je pu deviner qu'il s'agissait de cordes ? Regardez la ligne suivante :

4015fa : e8 f1 f5 ff ff callq 400bf0 <__isoc99_sscanf@plt>

sscanf a la signature suivante :

int sscanf(const char *str, const char *format, ...) ;

edi et esi sont tous deux utilisés pour contenir respectivement le premier et le
deuxième argument. Dans ce cas, la seule chose que les deux registres peuvent
stocker est une adresse pointant vers strings2.

La valeur 1 0 sur l'edi vous semble familière ? Il devrait, car c'est la réponse à la
quatrième phase.

sscanf est ensuite utilisé pour analyser à nouveau l'entrée de la quatrième phase,
mais avec un format différent : une chaîne de caractères est attendue après la
deuxième valeur. Vous pouvez voir qu'à 0x4015ff , s'il ne voit pas 3 valeurs, il saute
à 0x401635 qui imprimera le message suivant et retournera :

(gdb) p (char *) $edi

$3 = 0x402558 "Félicitations ! Vous avez désamorcé la bombe !"


http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino
Dans le cas contraire, cette fonction comparera si nous avons saisi la bonne chaîne
de caractères pour activer la phase secrète. En regardant l'instruction à 0x401604 ,
nous pouvons voir quelle est l'adresse de la chaîne d'activation :

(gdb) p (char *) 0x402622 $4 = 0x402622 "DrEvil"

Si l'entrée de la phase 4 comprend DrEvil à la fin, le code appellera alors la phase


secrète sur 0x401630 :

401630 : e8 0d fc ff ff callq 401242 <secret_phase>

Nous savons maintenant comment appeler secret_phase . Jetons un coup d'œil à


son code :

0000000000401242 <secret_phase>:
401242: 53 pousser %rbx
401243: e8 56 02 00 00 callq 40149e <read_line>
401248: ba 0a 00 00 00 déplacer 0xa,%edx
40124d : êtr 00 00 00 00 déplacer $0x0,%esi
401252: e 48 89 c7 déplacer %rax,%rdi
401255: e8 76 f9 ff ff callq 400bd0 <strtol@plt>
40125a : 48 89 c3 déplacer %rax,%rbx
40125d : 8d 40 ff lea -0x1(%rax),%eax
401260: 3d e8 03 00 00 cmp $0x3e8,%eax
401265: 76 05 jbe 40126c <secret_phase+0x2a>
401267: e8 ce 01 00 00 callq 40143a <explode_bomb>
40126c : 89 de déplacer %ebx,%esi
40126e : bf f0 30 60 00 déplacer $0x6030f0,%edi
401273: e8 8c ff ff ff callq 401204 <fun7>
401278: 83 f8 02 cmp $0x2,%eax
40127b : 74 05 je 401282 <secret_phase+0x40>
40127d : e8 b8 01 00 00 callq 40143a <explode_bomb>
401282: bf 38 24 40 00 déplacer $0x402438,%edi
401287: e8 84 f8 ff ff callq 400b10 <puts@plt>
40128c : e8 33 03 00 00 callq 4015c4 <phase_defused>
401291: 5b pop %rbx
401292: c3 retq
401293: 90 nop
401294: 90 nop

401295: 90 nop
401296: 90 nop
401297: 90 nop
401298: 90 nop

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino
401299: 90 nop
40129a : 90 nop
40129b : 90 nop
40129c : 90 nop
40129d : 90 nop
40129e : 90 nop
40129f : 90 nop

Après avoir lu l'entrée de cette phase secrète sur 0x401243 , edx stockera la valeur
10 , esi stockera NULL et rdi stockera l'entrée que nous avons donnée. Puis strtol 3
sera appelé à 0x401255 et, à en juger par les valeurs des registres, cela signifie que
notre entrée sera convertie en un nombre en base 10. Ensuite, à 0x40125a , le
nombre déjà converti sera stocké sur rbx . En 0x40125d , la valeur sera modifiée en
soustrayant 1 et placée à nouveau sur eax . Puis une comparaison avec 0x3e8 qui
est 1000 en base 10. Si notre entrée est inférieure à 1000 , le code sautera à
0x40126c pour continuer et si ce n'est pas le cas, la bombe explosera.

À 0x40126c , notre valeur est placée sur esi et edi reçoit une adresse. Les deux
valeurs seront utilisées dans la fonction suivante fun7 qui est appelée à 0x401273 .
Le résultat que fun7 doit renvoyer est 2 comme vous pouvez le voir sur 0x401278 .

Avant d'examiner fun7 , regardons ce que contient l'adresse reçue par edi et utilisée
comme premier argument de fun7 :

(gdb) x 0x6030f0
0x6030f0 <n1> : 0x00000024

Hmm, n1 . Ce nom ne donne aucun indice sur ce que c'est exactement. Voyons
donc ce qu'il en est de fun7 :

0000000000401204 <fun7> :
401204: 48 83 éc 08 sous $0x8,%rsp
401208: 48 85 ff test %rdi,%rdi
40120b : 74 2b je 401238 <fun7+0x34>
40120d : 8b 17 déplace (%rdi),%edx
40120f : 39 f2 r cmp %esi,%edx
401211: 7e 0d jle 401220 <fun7+0x1c>
401213: 48 8b 7f 08 déplace 0x8(%rdi),%rdi
401217: e8 e8 ff ff ff r callq 401204 <fun7>
40121c : 01 c0 ajouter %eax,%eax
40121e : eb 1d jmp 40123d <fun7+0x39>
401220: b8 00 00 00 00 déplace 0x0,%eax
r
http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino
401225: 39 f2 cmp %esi,%edx
401227: 74 14 je 40123d <fun7+0x39>
401229: 48 8b 7f 10 déplace 0x10(%rdi),%rdi
40122d : e8 d2 ff ff ff r callq 401204 <fun7>
401232: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401236: eb 05 jmp 40123d <fun7+0x39>
401238: b8 ff ff ff ff déplace $0xffffffff,%eax
40123d : 48 83 c4 08 r ajouter $0x8,%rsp
401241: c3 retq

Elle vérifie d'abord si rdi est NULL ( 0x0 ) et si c'est le cas, la fonction renvoie la
valeur -1 ( 0xffffffff à 0x401238 ). Si ce n'est pas le cas, la valeur stockée dans
l'adresse stockée par rdi sera placée sur edx et comparée (sur 0x40120f ) à notre
nombre d'entrée. Si la valeur sur edx est inférieure ou égale à notre nombre, le
code va à 0x401220 , sinon il continue à 0x401213. Continuons sur 0x401213 puis
revenons pour voir ce qui se passe dans l'autre branche.

En 0x401213, rdi stocke ce qui se trouve 8 octets après l'adresse déjà présente sur
rdi et appelle à nouveau fun7 .

Dans l'autre branche, lorsque le nombre sur edx est inférieur ou égal à notre
nombre, le code va à 0x401220 qui met eax à 0, compare ce qui est sur edx avec
notre nombre et s'ils sont égaux, il va à 0x40123d qui renvoie. Si les nombres sont
différents, l'instruction à 0x401229 changera rdi pour stocker ce qui se trouve 16
octets après l'adresse actuelle, puis appellera fun7 comme le fait l'autre branche.

Dans chaque branche, rdi est modifié pour contenir la nouvelle adresse située 8 ou
16 octets après son adresse actuelle. La première chose que contient rdi est un
nombre, les deux autres sont des pointeurs, il pourrait donc s'agir d'un arbre
binaire:

struct node { int data ; struct node *left; struct node *right;

};

Le nœud racine, situé à l'adresse initiale avec laquelle fun7 est appelé, est le suivant
:

(gdb) x 0x6030f0
0x6030f0 <n1> : 0x00000024
(gdb) x 0x6030f0+0x8
http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino
0x6030f8 <n1+8> : 0x00603110
(gdb) x 0x6030f0+0x10
0x603100 <n1+16> : 0x00603130

Après avoir suivi les pointeurs de nœuds, nous pouvons voir que la structure de
l'arbre est la suivante :

Nous savons comment l'arbre est structuré, mais nous ne savons pas ce que nous
devons faire pour obtenir la bonne réponse. secret_phase appelle fun7 et s'attend à
ce qu'il renvoie la valeur 2 :

401273: e8 8c ff ff ff callq 401204 <fun7>


401278: 83 f8 02 cmp $0x2,%eax
40127b : 74 05 je 401282 <secret_phase+0x40>
40127d : e8 b8 01 00 00 callq 40143a <explode_bomb>
401282: bf 38 24 40 00 déplacer $0x402438,%edi
401287: e8 84 f8 ff ff callq 400b10 <puts@plt>
40128c : e8 33 03 00 00 callq 4015c4 <phase_defused>
401291: 5b pop %rbx
401292: c3 retq

Voyons donc ce que fun7 nous renvoie. Nous savons qu'il s'agit d'une fonction
récursive. Voyons quel est le cas de base, qui est en fait double :

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino

401208 : 48 85 ff %rdi,%rdi
test je
40120b : 74 2b 401238 <fun7+0x34>

Et.. :

401225: 39 f2 cmp %esi,%edx


401227: 74 14 je 40123d <fun7+0x39>

Les deux montrent que la fonction revient lorsque nous avons atteint un pointeur
NULL (premier cas) ou si le nombre que nous avons donné est égal à celui du
nœud actuel (deuxième cas).

Mais dans le premier cas, le code saute à 0x401238 , ce qui fixe la valeur de retour à
-1 :

401238 : b8 ff ff ff ff ff mov
$0xffffffff,%eax
40123d : 48 83 c4 08 add
$0x8,%rsp
401241 : c3 retq

Dans le deuxième cas, on passe


directement à 0x40123d mais avant de comparer le
il fixe la valeur de retour à 0à 0x401220 :

dépla
401220 : b8 00 00 00 00 cer $0x0,%eax
401225 : 39 f2 cmp %esi,%edx
401227: 74 14 je 40123d <fun7+0x39>

Ainsi, si nous fournissons un nombre qui n'est pas présent dans l'arbre, le code
atteindra un pointeur NULL et renverra -1 et si notre nombre est présent, il
renverra 0.

Nous devons maintenant examiner chaque appel récursif à fun7 et voir ce que
l'appel en cours fera avec le résultat de l'appel interne. Voyons ce qui se passe
après le retour de l'appel interne de fun7 :

40120f : 39f2 cmp %esi,%edx


401211: 7e0d jle 401220 <fun7+0x1c>
401213: 48 8b 7f 08 déplacer 0x8(%rdi),%rdi
401217: e8 e8 ff ff ff callq 401204 <fun7>
http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino add %eax,%eax
40121c : 01 c0
jmp 40123d <fun7+0x39>
40121e : eb 1d

C'est le cas lorsque notre nombre est plus petit que la valeur actuelle du nœud. Il
double simplement la valeur de retour (à 0x40121c ) et saute à 0x40123d pour revenir.

Dans l'autre branche, lorsque notre nombre est supérieur ou égal à la valeur du nœud
actuel, il passe à 0x401220 :

401220: b8 00 00 00 00 déplace $0x0,%eax


401225: 39 f2 cmp %esi,%edx
401227: 74 14 je 40123d <fun7+0x39>
401229: 48 8b 7f 10 déplace 0x10(%rdi),%rdi
40122d : e8 d2 ff ff ff r callq 401204 <fun7>
401232: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401236: eb 05 jmp 40123d <fun7+0x39>

Ici, si les valeurs sont égales, la fonction renverra 0 comme nous l'avons vu
précédemment, mais si elles sont différentes, fun7 sera appelé à nouveau et la valeur
de retour de l'appel interne sera doublée comme dans l'autre branche, mais dans ce
cas, elle sera également augmentée de 1 :

401232 : 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax

Bien que lea signifie load effective address, cette instruction est souvent utilisée
pour des opérations arithmétiques.4 et c'est exactement le cas ici. L'instruction ci-
dessus signifie :

eax = 1 * rax + rax + 1

Simplifier :

eax = 2*rax + 1

Ce qui nous amène au code suivant pour fun7 :

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 9/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino

int fun7(node *n, int value) {


if (n == NULL) { return-1;
}

if (n->data <= value) { if (n->data == value) {


retour 0;
}
return 2 * fun7 (n->right, value) + 1;
} else {
return 2 * fun7 (n->left, value) ;
}
}

En examinant à nouveau la structure de l'arbre, nous pouvons essayer de deviner


quelle valeur fournira la bonne réponse en visitant les bons nœuds.

Une option consiste à visiter 0x8 et 0x16 . En remplaçant les adresses des nœuds par
les données réelles dont ils disposent, nous obtiendrions les appels suivants à fun7 :

return fun7(0x24, 0x16) ; // de `secret_phase`


return 2 * fun7(0x8, 0x16) ;
retour 2 * fun7(0x16, 0x16) + 1;
retour 0;

Vous obtiendrez ainsi la bonne réponse :

Malédiction, vous avez trouvé la phase secrète !


Mais le trouver et le résoudre sont deux choses bien différentes... 22
Ouah ! Vous avez désamorcé l'étape secrète !
Félicitations ! Vous avez désamorcé la bombe !

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11
5/29/2016 Désamorcer une bombe binaire avec gdb - Partie 7 - carlosgaldino

Il existe une autre réponse possible pour cette phase, mais le lecteur est invité à la
trouver.

Notes

1. En supposant qu'il s'agit d'un programme correct.

2. https://en.wikipedia.org/wiki/Buffer_overflow_protection

3. Pour plus d'informations sur strtol : http://man7.org/linux/man-


pages/man3/strtol.3.html

long int strtol(const char *nptr, char **endptr, int base) ;

La fonction strtol() convertit la partie initiale de la chaîne de caractères


contenue dans nptr en une valeur entière longue selon la base donnée, qui
doit être comprise entre 2 et 36 inclus, ou être la valeur spéciale 0.

4. Si vous souhaitez en savoir plus sur lea , sa différence avec mov , comment et
pourquoi les opérations arithmétiques peuvent être effectuées avec lea , vous
pouvez commencer par lire la page suivante :
https://en.wikibooks.org/wiki/X86_Assembly/Data_Transfer#Load_Effe
ctive_Address

http://webcache.googleusercontent.com/search?q=cache:aW_YFEmXe2cJ:blog.carlosgaldino.com/2016/05/24/defusing-a-binary-bomb-with-gdb-part-7.html+... 2/11

Vous aimerez peut-être aussi