Ingénierie inverse (désassembler un programme)
Bonjour,
Je débute avec l'assembleur. Mon objectif est de pouvoir lire aisément l'assembleur mais d'un point de vue ingénierie inverse. J'ai compilé en C, avec GCC sous Fedora Core, un programme très simple que voici:
Désassemblé avec GDB, j'obtiens:
Code:
1 2 3 4 5 6 7 8 9 10 11 12
| (gdb) disas main
Dump of assembler code for function main:
0x0804833c <main+0>: push %ebp
0x0804833d <main+1>: mov %esp,%ebp
0x0804833f <main+3>: sub $0x8,%esp
0x08048342 <main+6>: and $0xfffffff0,%esp
0x08048345 <main+9>: mov $0x0,%eax
0x0804834a <main+14>: sub %eax,%esp
0x0804834c <main+16>: leave
0x0804834d <main+17>: ret
End of assembler dump.
(gdb) |
Et déjà je me questionne sur ce qui se passe. J'ai exécuté ce programme en obtenant les informations sur l'état des registres ainsi que de la pile d'exécution:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| Breakpoint 1, 0x08048342 in main () at example.c:3
3 {
(gdb) info registers
eax 0x0 0
ecx 0xfeedae1c -17977828
edx 0xfeedae14 -17977836
ebx 0x650ffc 6623228
esp 0xfeedad80 0xfeedad80
ebp 0xfeedad88 0xfeedad88
esi 0x1 1
edi 0x6530fc 6631676
eip 0x8048342 0x8048342
eflags 0x200282 2097794
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) info frame
Stack level 0, frame at 0xfeedad90:
eip = 0x8048342 in main (example.c:3); saved eip 0x54ead4 source language c. Arglist at 0xfeedad88, args: Locals at 0xfeedad88, Previous frame's sp is 0xfeedad90 Saved registers:
ebp at 0xfeedad88, eip at 0xfeedad8c
(gdb) n
0x0054ead4 in __libc_start_main () from /lib/tls/libc.so.6
(gdb) info registers
eax 0x0 0
ecx 0xfeedae1c -17977828
edx 0xfeedae14 -17977836
ebx 0x650ffc 6623228
esp 0xfeedad90 0xfeedad90
ebp 0xfeedade8 0xfeedade8
esi 0x1 1
edi 0x6530fc 6631676
eip 0x54ead4 0x54ead4
eflags 0x200382 2098050
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) info frame
Stack level 0, frame at 0xfeedadf0:
eip = 0x54ead4 in __libc_start_main; saved eip 0x80482ad
called by frame at 0x0
Arglist at 0xfeedade8, args:
Locals at 0xfeedade8, Previous frame's sp is 0xfeedadf0
Saved registers:
ebx at 0xfeedaddc, ebp at 0xfeedade8, esi at 0xfeedade0, edi at
0xfeedade4,
eip at 0xfeedadec |
J'ai compilé ce programme sur une plateforme Intel P4.
Est-ce que quelqu'un pourrait me dire ce qui se passe sur la pile? J'essaie de suivre le cheminement du ESP et du EBP mais je ne crois pas y arriver.
En fait j'essaie de reconstituer chronologiquement l'étas de tous les registres et de la pile mais l'info que j'ai obtenue avec gdb me cause des maux de tête!!!
Merci.
N.B. J'aurai bien d'autres questions dans un futur rapproché ;)
Merci.
Balises [code] ajoutées par Hdd34. Merci d'y penser à l'avenir :wink:
Autoréponse et commentaires bienvenus
Bon, j'évolue tant bien que mal dans l'univers de l'assembleur (intel p4). J'ai fais quelques expérimentations et j'en ai déduit certaines chose. Cependant, d'autres demeurent tout de même obscure. Je requiers vos commentaires afin d'éclairer ma lanterne. Débutons.
Voici un petit programme en c:
Code:
1 2 3 4 5 6 7 8 9 10
| int function (int a, int b, int c)
{
return a+b+c;
}
int main (int argc, char ** argv)
{
int add;
add = function (1,2,3);
return 0;
} |
Ce petit programme fut compilé sous la plateforme Mandrake 10.0 avec gcc. Voici le code désassemblé:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| disassembly-flavor intel
push ebp
mov ebp, esp
sub esp, 0x8
and esp, oxfffffff0
mov eax, 0x0
sub esp, eax
sub esp, 0x4
push 0x3
push 0x2
push 0x1
call 0x804832c <function>
push ebp
mov ebp, esp
mov eax, DWORD PTR [ebp+12]
mov eax, DWORD PTR [ebp+8]
mov eax, DWORD PTR [ebp+16]
pop ebp
ret
add esp, 0x10
mov DWORD PTR [ebp-4], eax
mov eax, 0x0
leave
ret |
Voici donc ce que je comprend en examinant le code désassemblé ligne par ligne (vous pouvez suivre l'évolution du esp et du ebp avec le graphique suivant):
http://www.geocities.com/herve_metal/stack.JPG
1) Après push ebp et mov ebp, esp, on se reporte à la ligne pointée par esp1
2) Après sub esp, 0x8, on se reporte à la ligne pointée par esp3
3) and esp, 0xfffffff0 est utilisée pour aligner le esp au début de l'emplacement mémoire de la pile
4) mov eax, 0x0 et sub esp, eax n'ont aucun effet notable
5) sub esp, 0x4 c'est pour réserver un emplacement mémoire pour la variable locale au main int add
6) push 0x3, push 0x2, push 0x1 c'est pour envoyer les paramètres de la fontion sur la pile. On se reporte à la ligne pointée par esp5.
7) call function: le eip est stocké sur la pile (voir esp6) et on entre dans le code de la fonction
8) push ebp, mov ebp, esp, on se reporte à la ligne pointée par esp7
9) mov eax, DWORD PTR [ebp+12]: on envoie la valeur 2 dans eax (voir la ligne pointée par ebp2, à laquelle on ajoute un offset de 12
10 et 11) on additionne les autres paramètres, le résultat est dans eax
12) pop ebp: on renvoie ebp1 dans le registre ebp (on retourne dans le frame du main). On se reporte à la ligne pointée par esp8.
13) ret: on dépile eip et on continue à l'instruction du main suivant call. On se reporte à la ligne pointée par esp9.
14) add esp, 0x10 : on nettoie la pile des paramètres de la fonction. On se reporte à la ligne pointée par esp10.
15) mov DWORD PTR [ebp-4], eax: on envoie le résultat de l'addition i.e. 6 à la ligne pointée par "résultat addition"
16) mov eax, 0x0: on remet le registre eax à 0
17) leave: on nettoie la pile de la variable locale int add et des 8 bytes réservés par le compilateur au début du main
18) ret: on dépile eip et on continue....
C'est bien beau tout cela mais j'ai des question qui demeurent existentielles:
Q1: À quoi sert les 8 bytes réservés par le compilateur au début du main? Est-ce pour argc et argv?
Q2: Pourquoi la valeur de retour de la fonction ne va pas se copier dans l'emplacement de la pile réservé à cet effet i.e. lorsque l'on a fait sub esp, 0x4? En d'autres mots, pourquoi on a l'instruction mov DWORD PTR [ebp-4], eax au lieu de mov DWORD PTR [ebp-12]?
Merci de votre temps.
slackspace