Sunteți pe pagina 1din 57

5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 1
12 noiembrie 2015

Această serie de postări vă va arăta cum putem dezamorsa o bombă binară. Deci,
ce este o bombă binară?

O "bombă binară" este un program C executabil Linux care constă din șase
"faze". Fiecare fază se așteaptă ca elevul să introducă un anumit șir pe stdin.
Dacă elevul intră în șirul așteptat, atunci acea fază este "dezamorsată". În caz
contrar, bomba "explodează" prin imprimarea "BOOM!! ". Scopul elevilor este
de a dezamorsa cât mai multe faze."

Am găsit acest tip de bombă pe site-ul web pentru excelenta carte "Computer
Sisteme: perspectiva unui programator".

Instrumentele de bază necesare pentru dezamorsarea unei astfel de bombe sunt


gdb și objdump . GDB este un depanator pe care îl vom folosi pentru a inspecta
programul pe măsură ce îl rulăm. Objdump este un instrument pentru
dezasamblarea fișierelor obiect, astfel încât să putem vedea instrucțiunile reale pe
care le execută computerul.

Această serie nu este destinată să fie un tutorial despre gdb special pentru că a
fost prima dată când am folosit-o.

Destul de asta, să începem să ne distrăm. După extragerea tarball-ului rămânem


cu:

$ ls -l total 36
-rwxr-xr-x 1 Carlos Carlos 26406 Iun 9 15:41bombă
-rw-r--r-- 1 Carlos Carlos 4069 Iun 9 15:41 bombă.c
-rw-rw-r-- 1 Carlos Carlos 49 Iun 9 15:46README

Uitându-ne la bomb.c vedem o grămadă de comentarii și cum este configurat totul.


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 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino

Puteți trece un fișier ca argument pentru a evita tastarea de fiecare dată intrarea corectă
pentru fazele deja dezamorsate.

În continuare, trebuie să aruncăm o privire la executabilul bombei , care este date binare,
astfel încât să nu vedem nimic interesant dacă îl deschidem folosind $EDITOR . De
aceea avem nevoie de objdump pentru a dezasambla acest executabil.

$ objdump -d bombă > bombe.s

Dacă aruncăm o privire la primele câteva linii ale acestui nou fișier, vedem:

bombă: Formatul fișierului: ELF64-x86-64

Demontarea secțiunii .init:

0000000000400ac0 <_init>:
400ac0: 48 83 CE 08 sub $0x8,%rsp
400ac4: E8 F3 01 00 00 Apel 400cBc <call_gmon_start>
400AC9: 48 83 C4 08 adăuga $0x8,%rsp
400ACD: C3 Retq

Așa arată un fișier ELF atunci când este dezasamblat. Să ne uităm la funcția principală
atunci:

0000000000400da0 <principal>:

400da0: 53 împinge %rbx


400da1: 83 Ff 01 CMP $0x1,%EDI
400da4: 75 10 JNE 400dB6 <Main+0x16>
400da6: 48 8b 05 9b 29 20 00 .mov 0x20299b(%RIP),%RAX
# 603748 <stdin@@GLIBC_2.2.5>
400tată: 48 89 05 b4 29 20 00 .mov %rax,0x2029b4(%RIP)
# 603768 <infile>
400db4: Eb 63 JMP 400e19 <principal+0x79>
400db6: 48 89 F3 .mov %rsi,%rbx
400db9: 83 Ff 02 CMP $0x2,%EDI
400dbc: 75 3a JNE 400df8 <principal+0x58>
400dbe: 48 8b 7e 08 .mov 0x8(%rsi),%CDI
400DC2: fi b4 22 40 00 .mov $0x4022b4,%esi
400DC7: E8 44 f Ff Ff Apel 400C10 <fopen@plt>
400dcc: 48 89 05 95 29 2000 .mov %rax,0x202995(%RIP)
# 603768 <infile>
400dd3: 48 85 c0 testa %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+&... 2/7
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino
400dd6: 75 41 JNE 400e19 <principal+0x79>
400dd8: 48 8b 4b 08 MOV 0x8(%rbx),%rcx
400DDC: 48 8b 13 .mov (%rbx),%rdx
400DDF: să fie B6 22 40 00 .mov $0x4022b6,%esi
400de4: BF 01 00 00 00 .mov $0x1,%EDI
400de9: E8 12 fe ff ff Apel 400c00 <__printf_chk@plt>
400dee: BF 08 00 00 00 .mov $0x8,%EDI
400df3: E8 28 FE ff ff Apel 400C20 <exit@plt>
400df8: 48 8b 16 .mov (%rsi),%rdx
400dfb: BE D3 22 40 00 .mov $0x4022d3,%esi
400E00: BF 01 00 00 00 .mov $0x1,%EDI
400E05: b8 00 00 00 00 .mov $0x0,%eax
400E0a: E8 F1 FD FF FF Apel 400c00 <__printf_chk@plt>
400e0f: BF 08 00 00 00 .mov $0x8,%EDI
400E14: E8 07 fe ff ff Apel 400C20 <exit@plt>
400E19: E8 84 05 00 00 Apel 4013a2 <initialize_bomb>
400E1e: BF 38 23 40 00 .mov $0x402338,%EDI
400E23: E8 E8 FC FF FF Apel 400B10 <puts@plt>
400E28: BF 78 23 40 00 .mov $0x402378,%EDI
400E2d: E8 de FC FF FF Apel 400B10 <puts@plt>
400E32: E8 67 06 00 00 Apel 40149e <read_line>
400E37: 48 89 c7 .mov %rax,%CDI
400E3a: E8 A1 00 00 00 Apel 400ee0 <phase_1>
400e3f: E8 80 07 00 00 Apel 4015c4 <phase_defused>

Nu am lipit întreaga funcție, deoarece este suficient de mare și nu suntem încă


preocupați de celelalte faze.

Înainte de a începe să analizăm funcția, trebuie să înțelegem structura fiecărei linii. Să


luăm următoarea linie ca exemplu:

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

Putem împărți această linie în trei secțiuni:

• 400db6 : adresa codului la care ne uităm.


• 48 89 F3 : Instrucțiunea codificată.
• MOV %RSI,%RBX : Instrucțiunea decodificată.

Primele câteva linii din funcția principală corespund codului C care verifică dacă am
transmis sau nu un fișier ca argument programului. Sărind peste aceste rânduri,
începem să vedem partea distractivă:

400E19: E8 84 05 00 00 Callq 4013A2 <initialize_bomb>

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 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino

Această linie spune că funcția initialize_bomb ar trebui apelată. Linia de corelare din
fișierul C este următoarea:

/* Faceți tot felul de lucruri secrete care fac bomba mai greu de dezamorsat.
*/
initialize_bomb();

Deci, să trecem la funcția initialize_bomb .

00000000004013a2 <initialize_bomb>:
4013A2: 48 83 Ce 08 sub $0x8,%rsp
4013A6: fi A0 12 40 00 .mov $0x4012a0,%esi
4013ab: Bf 02 00 00 00 .mov $0x2,%EDI
4013b0: E8 .db F7 ff ff Apel 400B90 <signal@plt>
4013b5: 48 83 C4 08 adăuga $0x8,%rsp
4013B9: C3 Retq

Inspectarea valorilor nu dezvăluie nimic interesant. Să mergem mai departe.


Următoarele câteva linii după initialize_bomb în funcția principală corespund
următoarelor linii din fișierul C:

printf("Bine ați venit la mica mea bombă. Aveți 6 faze cu \n");


printf("care să te arunce în aer. O zi frumoasa!\n");

/*Hmm... Șase faze trebuie să fie mai sigure decât o singură fază! */
intrare = read_line(); /* Obțineți informații */
phase_1(intrare); /* Rulați faza */

Așa că tipăresc mesajele și citesc intrarea. Apoi este timpul să dezamorsăm prima fază.

400E3a: E8 A1 00 00 00 callq 400ee0 <phase_1>

Din nou, aceasta numește funcția phase_1 localizată la 0x400ee0 . Să vedem ce

Prima fază arată astfel:

0000000000400ee0 <phase_1>:
400ee0: 48 83 CE 08 sub $0x8,%rsp
400EE4: să fie 00 24 40 00 .mov $0x402400,%esi
400EE9: E8 4A 04 00 00 Apel 401338 <strings_not_equal>

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 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino
400eee: 85 c0 testa %EAX,%EAX
400ef0: 74 05 Je 400ef7 <phase_1+0x17>
400ef2: E8 43 05 00 00 Apel 40143a <explode_bomb>
400ef7: 48 83 c4 08 adăuga $0x8,%rsp
400EFB: C3 Retq

Observați pe 0x400ee4 că valoarea 0x402400 este copiată în registrul esi . Registrul esi
este de obicei folosit ca registru pentru al doilea argument al unei funcții care va fi
apelat mai târziu. În cazul nostru, o astfel de funcție este apelată imediat după
instrucțiunea mov . Ați putea întreba atunci: unde este primul argument? Primul
argument este de obicei plasat in registrul edi , care in acest caz va fi sirul pe care l-am
furnizat ca intrare. Dacă aruncați o privire la funcția principală , veți vedea:

400E32: E8 67 06 00 00 Apel 40149e <read_line>


400E37: 48 89 c7 .mov %rax,%CDI
400E3a: E8 A1 00 00 00 Apel 400ee0 <phase_1>

Valoarea returnată (stocată în rax) a funcției read_line a fost plasată în registrul rdi (
edi este un registru pe 32 de biți și rdi este registrul echivalent pe 64 de biți) și va fi
utilizată ca prim argument pentru funcția care va fi apelată în continuare, care în
acest caz este phase_1 . Și exact asta face codul C:

/*Hmm... Șase faze trebuie să fie mai sigure decât o singură fază! */ intrare = read_line(); /* Obțineți
informații */
phase_1(intrare); /* Rulați faza */

Ok, înapoi la funcția phase_1 . Acum știm care sunt argumentele date strings_not_equal
și după executarea unei astfel de funcții există un test pentru a verifica rezultatul:

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 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino

400EE9: E8 4a 04 00 00 Apel 401338 <strings_not_equal>


400eee: 85 c0 testa %EAX,%EAX
400ef0: 74 05 Je 400ef7 <phase_1+0x17>
400ef2: E8 43 05 00 00 Apel 40143a <explode_bomb>

Instrucțiunea de testare va efectua o operație AND la nivel de biți între operanzii săi
și va seta steagurile corespunzătoare pe steagurile electronice ale registrului .
Instrucțiunea je este o instrucțiune de salt condiționată care sare la locația specificată
numai dacă comparația anterioară a setat ZF (Zero Flag) la 1 în registrul eflags .

Deci , instrucțiunea de testare va seta ZF la 1 numai atunci când avem 0 în eax,


ceea ce se întâmplă numai atunci când strings_not_equal returnează 0 .
(Examinarea strings_not_equal nu dezvăluie nimic interesant, este exact ceea ce vă
așteptați de la o funcție cu un astfel de nume. Returnează 1 dacă ambele argumente
nu sunt egale și 0 în caz contrar.)

Dacă corzile nu sunt egale, saltul condiționat nu va fi efectuat și apoi va fi executată


următoarea linie, care va exploda bomba. Dacă corzile sunt egale, sărim la 0x400eef7
și revenim la principal :

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


400ef2: E8 43 05 00 00 Apel 40143a <explode_bomb>
400ef7: 48 83 c4 08 adăuga $0x8,%rsp
400EFB: C3 Retq

Ok, acum știm că prima fază ne cere să furnizăm un șir pe care nu îl cunoaștem. Cum
vom descoperi care șir este acesta? Trebuie să începem să executăm programul. Dar,
în acest caz, în loc să executați așa cum faceți de obicei cu alte programe, îl vom rula
cu gdb . GDB ne va ajuta să inspectăm valorile și să aflăm ce este acest șir misterios.

$ GDB bombă

Linia de mai sus începe gdb cu programul bombei atașat la acesta, astfel încât să
putem executa bomba și să inspectăm valorile, să setăm puncte de întrerupere etc. În
acest caz, am făcut deja cea mai mare parte a muncii examinând doar codul de
asamblare și
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 Dezamorsarea unei bombe binare cu gdb - Partea 1 · carlosgaldino

Știm că șirul misterios se află la adresa 0x402400 (când a fost încărcat pe Register ESI
la adresa 0x400ee4 ). Pentru a vedea care este valoarea acesteia, putem cere pur și
simplu gdb să tipărească valoarea la adresa dorită și să o trateze ca secvență de
caractere :

(gdb) p (caracter *) 0x402400


$1 = 0x402400 "Relațiile de frontieră cu Canada nu au fost niciodată mai bune."

Și voilà! Avem sfoara de care avem nevoie.

Acum execută programul:

(GDPR) Rulare
Program de pornire: /home/carlos/Downloads/bomb/bomb
Bine ați venit la mica mea bombă diabolică. Ai 6 faze cu care să te arunci în aer. O zi bună!

Apoi, intrând în șirul complet, vom vedea că faza 1 a fost dezamorsată:

Relațiile de frontieră cu Canada nu au fost niciodată mai bune.


Faza 1 dezamorsată. Ce zici de următorul?

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 Dezamorsarea unei bombe binare cu gdb - Partea 2 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 2
19 noiembrie 2015

Acest post face parte dintr-o serie în care vă arăt cum să dezamorsați o bombă
binară citind codul de asamblare și folosind gdb . S-ar putea să doriți să citiți
prima parte dacă nu ați făcut-o încă.

După dezamorsarea primei faze am fost provocați să o dezamorsăm pe următoarea:

Relațiile de frontieră cu Canada nu au fost niciodată mai bune.


Faza 1 dezamorsată. Ce zici de următorul?

Codul de asamblare corespunzător din funcția principală este următorul:

400E3a: E8 A1 00 00 00 Apel 400ee0 <phase_1>


400e3f: E8 80 07 00 00 Apel 4015c4 <phase_defused>
400E44: Bf A8 23 40 00 .mov $0x4023a8,%EDI
400E49: E8 c2 Fc Ff Ff Apel 400B10 <puts@plt>
400e4e: E8 4b 06 00 00 Apel 40149e <read_line>
400E53: 48 89 C7 .mov %rax,%CDI
400E56: E8 A1 00 00 00 Apel 400EFC <phase_2>
400e5b: E8 64 07 00 00 Apel 4015c4 <phase_defused>

După cum putem vedea ( cel 0x400e53 ) pune contribuția noastră în registrul CDI
pentru a fi folosită ca prim argument pentru a phase_2 care va fi apelat de următoarea
instrucțiune. La fel cum v-ați imagina că codul C real face:

printf("Faza 1 dezamorsată. Ce zici de următorul?\n");

/* A doua fază este mai grea. Nimeni nu-și va da seama vreodată


* cum să dezamorsați acest lucru ... * /
intrare = read_line();
phase_2(intrare);
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+&... 1/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 2 · carlosgaldino

Deci, cum arată phase_2 ?

0000000000400EFC <phase_2>:
400EFC 55 împinge %rbp
400EFD 53 împinge %rbx
400efe 48 83 Ce 28 sub $0x28,%rsp
400F02 48 89 E6 .mov %rsp,%rsi
400F05 E8 52 05 00 00 Apel 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 Apel 40143a <explode_bomb>
400F15 Eb 19 JMP 400F30 <phase_2+0x34>
400F17 8b 43 Fc .mov -0x4(%RBX),%EAX
400F1A 01 c0 adăuga %EAX,%EAX
400F1C 39 03 CMP %eax,(%rbx)
400F1E 74 05 Je 400F25 <phase_2+0x29>
400F20 E8 15 05 00 00 Apel 40143a <explode_bomb>
400F25 48 83 C3 04 adăuga $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 pășune 0x4(%rsp),%rbx
400F35 48 8D 6c 24 18 pășune 0x18(%rsp),%rbp
400F3A Eb .db JMP 400F17 <phase_2+0x1b>
400F3C 48 83 C4 28 adăuga $0x28,%rsp
400F40 5b pop %rbx
400F41 5D pop %rbp
400F42 C3 Retq

Încă de la început putem vedea că această fază se așteaptă să introducem șase numere:

400F05: E8 52 05 00 00 Callq 40145C <read_six_numbers>

Acest lucru poate fi confirmat prin inspectarea funcției read_six_numbers :

000000000040145c <read_six_numbers>:
40145C: 48 83 Ce 18 sub $0x18,%rsp
401460: 48 89 F2 .mov %rsi,%rdx
401463: 48 8D 4e 04 pășune 0x4(%rsi),%rcx
401467: 48 8D 46 14 pășune 0x14(%rsi),%rax
40146B: 48 89 44 24 08 .mov %rax,0x8(%rsp)
401470: 48 8D 46 10 pășune 0x10(%rsi),%rax
401474: 48 89 04 24 .mov %rax,(%rsp)

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 Dezamorsarea unei bombe binare cu gdb - Partea 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 .mov $0x4025c3,%esi
401485: b8 00 00 00 00 .mov $0x0,%eax
40148a: E8 61 F7 FF FF Apel 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 Apel 40143a <explode_bomb>
401499: 48 83 c4 18 adăuga $0x18,%rsp
40149d: C3 Retq

La 0x40148a vedem că se numește sscanf care are următorul scop:

#include <stdio.h>

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


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

Familia de funcții scanf() scanează intrarea conform formatului descris mai jos.
Acest format poate conține specificații privind conversiile; Rezultatele unor astfel
de conversii, dacă există, sunt stocate în locațiile indicate de argumentele
indicatorului care urmează formatul . Fiecare argument indicator trebuie să fie
de un tip adecvat pentru valoarea returnată de specificația de conversie
corespunzătoare.

Urmând aceeași idee pe care am folosit-o în faza 1, putem confirma că această funcție
face exact ceea ce sugerează numele său. Pe 0x401480 ceva este stocat la esi pentru a fi
folosit ca al doilea argument pentru sscanf , care, așa cum se vede mai sus, este
formatul așteptat pentru intrarea noastră.

401480: BE C3 25 40 00 mov $0x4025c3,%esi

Apoi, pe gdb putem imprima valoarea la fel cum am făcut-o pe phase_1 :

(gdb) p (caracter *) 0x4025c3


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

read_six_numbers apoi verifică dacă am tastat cel puțin șase numere, dacă am făcut-o se
întoarce, altfel explodează bomba.

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 Dezamorsarea unei bombe binare cu gdb - Partea 2 · carlosgaldino

Revenind la funcția phase_2 , constatăm că primul nostru număr trebuie să fie 1


(comparație la 0x400f0a ), altfel bomba va exploda imediat:

400F05: E852 05 00 00 Apel 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 Apel 40143a <explode_bomb>

După confirmarea faptului că primul nostru număr a fost 1 , merge la 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>

Pe 0x400f30 adresa următorului număr este stocată pe rbx, iar pe 0x400f35 rbp primește
adresa imediat după adresa ultimului număr analizat de sscanf pe read_six_numbers .

(GDPR) p $rsp+0x18
$2 = (vid *) 0x7fffffffddd8
(GDPR) p $rsp
$3 = (vid *) 0x7fffffffddc0

Având în vedere doar octetul de ordin scăzut: 0xd8 - 0xc0 = 0x18 . Care este zecimal 24 .
Fiecare int are patru octeți, astfel încât structura memoriei arată ca imaginea de mai jos,
ceea ce explică de ce rbp deține adresa după al șaselea număr:

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 Dezamorsarea unei bombe binare cu gdb - Partea 2 · carlosgaldino

Andoc
p 0kco a Oxc? Or.cc OkaH

Lk x,
HG + OLVE OCTEȚI
x xni Xs
AE: Ok'FFFFFFFDD
<6

Apoi execuția va continua pe 0x400f17 :

ADORESS (LowJ omen


BYTe)
VALOARE
400F17: 8b 43 FC mov adauga -0x4(%RBX),%EAX %EAX,
400F1a: 01 c0 %EAX
400F1C: 39 03 CMP %eax,(%rbx)
400F1e: 74 05 Je 400F25 <phase_2+0x29>
400F20: E8 15 05 00 00 Apel 40143a <explode_bomb>

Pe 0x400f17 numărul anterior este copiat în eax, apoi următoarea instrucțiune


duplică această valoare pe eax, care este apoi comparată cu al doilea număr. Dacă
sunt egale, funcția va continua execuția la 0x400f25 , altfel știi ce.

Pe 0x400f25 indicatorul merge la numărul următor. Apoi verifică dacă indicatorul


a trecut ultimul număr, ceea ce înseamnă că toate cele șase numere au fost
verificate. Dacă nu, se întoarce la 0x400f17 pentru a verifica următorul număr și
dacă toate numerele au fost deja verificate, va sări la 0x400f3c care va reveni apoi
la principal .

400F25: 48 83 c3 04 adăuga $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>

Verificarea numerelor, mutarea indicatorilor înainte, sărind înainte și înapoi


sugerează că avem de-a face cu o buclă. Presupunând că p este un indicator către
primul număr, bucla din phase_2 ar putea arăta astfel:

pentru (int *x = p + 1; x != (p + 6); x++) { int anterior = *(x - 1);

dacă (*x != anterior * 2)


explode_bomb();
}

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 Dezamorsarea unei bombe binare cu gdb - Partea 2 · carlosgaldino

Bine, acum avem o idee despre care ar trebui să fie următoarele cinci numere.
Acestea trebuie să fie dublul numărului anterior. Dacă începem de la 1 , următorul
este 2 , următorul este 4 și așa mai departe. S-ar putea să sune un clopoțel, nu-i
așa? Contribuția noastră trebuie să fie primele șase puteri din 2 :

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

După introducerea celor șase numere, vedem că am dezamorsat a doua fază:

Faza 1 dezamorsată. Ce zici de următorul? 1 2 4 8 16 32


Acesta este numărul 2. Continuă!

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 Dezamorsarea unei bombe binare cu gdb - Partea 3 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 3
03 decembrie 2015

Acest post face parte dintr-o serie în care vă arăt cum să dezamorsați o bombă
binară citind codul de asamblare și folosind gdb . S-ar putea să doriți să citiți
celelalte părți dacă nu ați făcut-o încă.

Urmând procesul obișnuit, după dezamorsarea celei de-a doua faze am fost
provocați să o dezamorsăm pe a treia:

Bine ați venit la mica mea bombă diabolică. Ai 6 faze cu care să te arunci în aer. O zi bună!
Relațiile de frontieră cu Canada nu au fost niciodată mai bune.
Faza 1 dezamorsată. Ce zici de următorul?
1 2 4 8 16 32
Acesta este numărul 2. Continuă!

Instrucțiunile corespunzătoare privind principalele sunt următoarele:

400e5b: E8 64 07 00 00 Apel 4015c4 <phase_defused>


400E60: BF ED 22 40 00 .mov $0x4022ed,%EDI
400E65: E8 A6 Fc ff ff Apel 400B10 <puts@plt>
400e6a: E8 2F 06 00 00 Apel 40149e <read_line>
400e6f: 48 89 C7 .mov %rax,%CDI
400E72: E8 cc 00 00 00 Apel 400F43 <phase_3>

Codul pentru phase_3 este următorul:

0000000000400f43 <phase_3>:
400F43: 4883 Ce 18 sub $0x18,%rsp
400F47: 48 8D 4c 24 0C pășune 0xc(%rsp),%rcx
400F4C: 48 8D 54 24 08 pășune 0x8(%rsp),%rdx
400F51: fi cf 25 40 00 .mov $0x4025cf,%esi
400F56: b8 00 00 00 00 .mov $0x0,%eax

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/14/03/dezamorsarea-unei-bombe-binare-cu-gdb-part-
3.html+&cd... 6/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 3 · carlosgaldino
400F5B E8 90 FC FF FF Apel 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 Apel 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 .mov 0x8(%rsp),%eax
400F75 ff 24 C5 70 24 40 00 jmpq *0x402470(,%rax,8)
400F7C B8 CF 00 00 00 .mov $0xcf,%eax
400F81 EB 3b JMP 400fbe <phase_3+0x7b>
400F83 B8 C3 02 00 00 .mov $0x2c3,%eax
400F88 EB 34 JMP 400fbe <phase_3+0x7b>
400F8A B8 00 01 00 00 .mov $0x100,%eax
400F8F EB 2d JMP 400fbe <phase_3+0x7b>
400F91 B8 85 01 00 00 .mov $0x185,%eax
400F96 EB 26 JMP 400fbe <phase_3+0x7b>
400F98 B8 CE 00 00 00 .mov $0xce,%eax
400F9D EB 1F JMP 400fbe <phase_3+0x7b>
400F9F B8 AA 02 00 00 .mov $0x2aa,%eax
400fa4 EB 18 JMP 400fbe <phase_3+0x7b>
400FA6 B8 47 01 00 00 .mov $0x147,%eax
400fab EB 11 JMP 400fbe <phase_3+0x7b>
400mod E8 88 04 00 00 Apel 40143a <explode_bomb>
400fb2 B8 00 00 00 00 .mov $0x0,%eax
400fb7 EB 05 JMP 400fbe <phase_3+0x7b>
400FB9 B8 37 01 00 00 .mov $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 Apel 40143a <explode_bomb>
400FC9 48 83 C4 18 adăuga $0x18,%rsp
400FCD C3 Retq

Pe 0x400f51 vedem că o anumită valoare este stocată pe esi , eax se inițializează și


apoi se apelează scanf .

Dacă nu vă amintiți din faza anterioară, sscanf este o funcție care scanează intrarea
în funcție de un format care îi este dat ca argument. Un astfel de format trebuie să
fie ceea ce este stocat pe esi .

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

Deci trebuie să introducem 2 numere întregi. Acest lucru ar putea fi confirmat și


prin examinarea următoarelor instrucțiuni care compară dacă am introdus mai
mult de un întreg la

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/15/03/dezamorsarea-unei-bombe-binare-cu-gdb-part-
3.html+&cd... 6/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 3 · carlosgaldino

Continuați executarea celei de-a treia faze, altfel bomba va exploda.

400F60: 83 f8 01 CMP $0x1,%eax


400F63: 7f 05 Jg 400F6A <phase_3+0x27>
400F65: E8 d0 04 00 00 Apel 40143a <explode_bomb>

S-ar putea să vă întrebați cum a obținut sscanf primul său argument, care este șirul
folosit ca sursă pentru scanarea valorilor dorite. După cum am explicat în postările
anterioare, primul argument pentru funcții este de obicei plasat pe registrul rdi și
orice instrucțiune poate interacționa cu orice registru, în același mod în care ați
interacționa cu o variabilă globală într-un program. Dacă vă uitați la 0x400e6f în
funcția principală , șirul pe care îl introducem ca intrare pentru phase_3 este copiat
în rdi pentru a fi apoi folosit ca prim argument pentru sscanf :

400E6F: 48 89 C7 .mov %rax,%CDI


400E72: E8 cc 00 00 00 Callq 400F43 <phase_3>

Ok, continuarea execuției phase_3 următoarea instrucțiune care trebuie executată


se află la 0x400f6a (presupunând că am introdus două numere întregi, desigur). În
acea locație, programul compară primul număr întreg pe care l-am dat ca intrare.
Ar trebui să fie mai mică sau egală cu 7 , altfel execuția va continua pe 0x400fad .

400F6a: 83 7c 24 08 07 CMPL $0x7,0x8(%RSP)


400F6F: 77 3c Ja 400fad <phase_3+0x6a>

Și 0x400fad știm ce ne așteaptă:

400mod: E8 88 04 00 00 Callq 40143A <explode_bomb>

Presupunând că am introdus un întreg mai mic sau egal cu 7 , programul continuă:

400F71: 8b 44 24 08 .mov 0x8(%rsp),%eax


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

Prima instrucțiune de mai sus va copia primul număr întreg în eax și apoi pe a
doua instrucțiune va sări într-o locație bazată pe acest întreg. Să presupunem că
am introdus 0 ca primul nostru întreg. În acest caz, programul ar sări la locația

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/16/03/dezamorsarea-unei-bombe-binare-cu-gdb-part-
3.html+&cd... 6/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 3 · carlosgaldino

adresei stocate la 0x402470 . Regula pentru calcularea adresei este următoarea:

*(%rax * 8 + 0x402470)

Adică: înmulțiți valoarea stocată pe rax cu 8 , adăugați-o la 0x402470 și apoi citiți


valoarea stocată în locația rezultatului. Inspectând valoarea de pe 0x402470 vedem
că aceasta este adresa următoarei linii:

(gdb) x 0x402470 0x402470: 0x00400f7c

Deci, introducerea lui 0 ca prim număr ar executa următoarele instrucțiuni:

400F7C: B8 cf 00 00 00 .mov $0xcf,%eax


400F81: EB 3b JMP 400fbe <phase_3+0x7b>

Aceasta stochează 0xcf (zecimal 207) pe eax și apoi sare la 0x400fbe care face
următoarele:

400fbe: 3b 44 24 0c CMP 0xc(%rsp),%eax


400FC2: 74 05 JE 400fc9 <phase_3+0x86>
400fc4: E8 71 04 00 00 Apel 40143a <explode_bomb>
400FC9: 48 83 c4 18 adăuga $0x18,%rsp
400FCD: C3 Retq

Cu alte cuvinte, pe 0x400fbe programul va compara al doilea număr cu ceea ce a


fost stocat pe eax , în acest caz imaginar de introducere a 0 ca primul nostru
număr, s-ar compara apoi dacă al doilea număr al nostru a fost 207 . Dacă acesta
este cazul, înseamnă că am dezamorsat phase_3 :

0 207
La jumătatea drumului!

Deci asta este?! Destul de simplu, nu? Dar cum rămâne cu toate celelalte
instrucțiuni de peste 400fbe ? Care este scopul lor?

Toate aceste instrucțiuni fac parte dintr-o instrucțiune de comutare . De aceea, pe


0x400f75 adresa la care va sări programul va fi calculată pe baza a ceea ce am
introdus, spre deosebire de ceea ce s-a întâmplat înainte când locația la care să sari

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/17/03/dezamorsarea-unei-bombe-binare-cu-gdb-part-
3.html+&cd... 6/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 3 · carlosgaldino

a fost codificată în instrucțiunea însăși1. Aruncând o privire mai atentă la


instrucțiunile înainte de 0x400fbe vedem că toate urmează același model: stocați o
anumită valoare pe eax și apoi săriți la 0x400fbe pentru a compara al doilea număr
cu această valoare stocată pe eax . Deci, phase_3 are mai multe răspunsuri, să le
vedem pe toate:

(GDPR) X/8G 0x402470


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

Comanda de mai sus spune gdb să examineze memoria începând de la adresa


0x402470 și să afișeze opt blocuri ( 8 în comandă) de opt octeți (g în comandă, g ca
în cuvinte gigantice). Ieșirea arată apoi două valori pe linie, astfel încât să putem
construi un tabel referitor la primul număr de intrare, adresa la care sare
comutatorul și care ar trebui să fie al doilea număr de intrare:

Prim Adresă Al doilea așteptat Al doilea


pentru a așteptat
intrare Număr intrare Număr intrare
număr sări
spre (hex) (zecimal)

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/dezamorsarea-unei-bombe-binare-cu-gdb-part-
3.html+&cd... 6/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 3 · carlosgaldino

7 0x400fa6 0x147 327

Oricare dintre combinațiile de mai sus va funcționa.

Note

1. În acest caz, folosind adresarea relativă PC. ↩

http://webcache.googleusercontent.com/search?q=cache:T7QwiqsqtVEJ:blog.carlosgaldino.com/2015/12/03/dezamorsarea-unei-bombe-binare-cu-gdb-part-
3.html+&cd... 6/6
5/29/2016 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 4
25 aprilie 2016

Acest post face parte dintr-o serie în care vă arăt cum să dezamorsați o bombă
binară citind codul de asamblare și folosind gdb . S-ar putea să doriți să citiți
prima parte dacă nu ați făcut-o încă.

Ne-am întors la dezamorsarea celei de-a patra faze a bombei binare.

Codul pentru phase_4 este următorul:

000000000040100c <phase_4>:
40100C: 48 83 CE 18
401010: 48 8d 4c 24 0c sub lea $0x18,%rsp
401015: 48 8d 54 24 08 BE CF 25 lea 0xc(%rsp),%rcx
40101a: 40 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 Apel 40143a <explode_bomb>
40103a: Ba 0e 00 00 00 .mov $0xe,%EDX
40103F: fi 00 00 00 00 .mov $0x0,%esi
401044: 8b 7c 24 08 .mov 0x8(%rsp),%edi
401048: E8 81 ff ff Ff Apel 400fce <func4>
40104D: 85 c0 testa %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 Apel 40143a <explode_bomb>
40105D: 48 83 C4 18 adăuga $0x18,%rsp
401061: C3 Retq

Exact așa cum s-a întâmplat în faza 3 , putem vedea că această fază așteaptă două

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 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino

numere întregi ca intrare. Pe 0x40101a același format folosit înainte este stocat pe
esi , care este apoi utilizat de sscanf pe 0x401024 .

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

Pe 0x401029 putem confirma, de asemenea, că, dacă introducem mai mult de 2


numere întregi, codul va sări la 0x401035 care apelează explode_bomb :

401029: 83 f8 02 CMP $0x2,%eax


40102C: 75 07 JNE401035 <phase_4+0x29>

Deci, ce numere exacte ar trebui să introducem? Trebuie să fie un număr mai mic
de 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 Apel 40143a <explode_bomb>

CMPL compară 0xe care este 14 cu primul întreg1 pe care l-am introdus pentru
această fază. Apoi jbe ("salt sub sau egal") va sări peste explozia bombei dacă
valoarea este mai mică sau egală cu 14.

După aceea, putem vedea că se face o anumită configurare înainte de a apela o


nouă funcție, func4 :

40103a: Ba 0e 00 00 00 .mov $0xe,%EDX


40103F: fi 00 00 00 00 .mov $0x0,%esi
401044: 8b 7c 24 08 .mov 0x8(%rsp),%edi
401048: E8 81 Ff Ff Ff Apel 400fce <func4>

EDI este de obicei folosit ca registru pentru a ține primul argument, ESI deține al
doilea și EDX deține al treilea argument. Primul argument este primul număr pe
care l-am furnizat, al doilea și al treilea sunt 0 și 14 , respectiv.

Să aruncăm o privire la 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 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino

0000000000400fce
400fce: <func4>:
48 83 CE 08 sub $0x8,%rsp
400fd2: 89 d0 .mov %edx,%eax
400fd4: 29 f0 sub %ESI,%EAX
400fd6: 89 C1 .mov %eax,%ecx
400FD8: C1 E9 1f Shr $0x1f,%ecx
400FDB: 01 c8 adăuga %ecx,%eax
400fdd: d1 F8 Sar %eax
400FDF: 8D 0c 30 pășune (%rax,%rsi,1),%ecx
400FE2: 39 F9 CMP %EDI,%ECX
400FE4: 7e 0c JLE 400ff2 <func4+0x24>
400fe6: 8D 51 Ff pășune -0x1(%rcx),%edx
400fe9: E8 E0 ff ff ff Apel 400fce <func4>
400fee: 01 c0 adăuga %EAX,%EAX
400ff0: Eb 15 JMP 401007 <func4+0x39>
400ff2: b8 00 00 00 00 .mov $0x0,%eax
400ff7: 39 F9 CMP %EDI,%ECX
400ff9: 7D 0c JGE 401007 <func4+0x39>
400 și urm: 8D 71 01 pășune 0x1(%rcx),%esi
400ffe: E8 Cb ff ff ff Apel 400fce <func4>
401003: 8D 44 00 01 pășune 0x1(%rax,%rax,1),%eax
401007: 48 83 C4 08 adăuga $0x8,%rsp
40100b: C3 Retq

Privind primele câteva instrucțiuni, putem încerca să scriem ce se întâmplă exact


cu argumentele care au fost date acestei funcții. Instrucțiunile până când 0x400fe2
fac de fapt ceva de genul următor:

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


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

Apoi se compară y cu a (primul nostru număr de intrare pentru această fază) și


dacă y <= a va sări la 0x400ff2 . În caz contrar, se numește din nou func4 , dar de
data aceasta c va fi y - 1 (setat la 0x400fe6 ). Deci, pe 0x400fe9 ne putem gândi la
invocație ca:

func4(a, b, y - 1);
După ce îl apelați, puteți vedea că 0x400fee va dubla rezultatul acelei invocații
"interioare" ( eax deține valoarea returnată din acea execuție) și apoi veți sări la
0x401007 care curăță cadrul stivei pentru această invocare. Deci rezultatul acestui
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 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino

apel recursiv este de fapt:

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

Dacă y >= a codul va continua executarea pe 0x400ff2 . La acea linie setează


rezultatul posibil ca 0 și apoi compară același y cu a din nou. De data aceasta dacă y
>= a sare la 0x401007 și returnează 0 , de aceea eax a obținut valoarea 0 prin
instrucțiunea anterioară. Dacă y < a , atunci func4 va fi apelat din nou, dar în acest
caz b va fi y + 1 (această atribuire are loc pe 0x400ffb ) și următoarea invocare are
loc pe 0x400ffe :

func4(a, y + 1, c);

După revenirea de la acest apel recursiv, valoarea returnată este setată pe 0x401003
utilizând rezultatul apelului recursiv, astfel încât rezultatul este de fapt:

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

Cu tot acest context, putem încerca acum să ghicim ce se întâmplă exact cu această
funcție:

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;

dacă (y <= a) {
dacă (y >= a) { returnează 0;
} altceva {
returnează 2 * func4(a, y + 1, c) + 1;
}
} altceva {
returnare 2 * func4(a, b, y - 1);

Amintiți-vă că apelul inițial la func4 este func4 (ourFirstInputNumber, 0, 14) și că


ourFirstInputNumber < = 14 . Să încercăm să vedem ce se întâmplă dacă introducem
1 ca prim număr:
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 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino
func4(1, 0, 14) { int x = 14 - 0;
int y = 14 >> 31; x = 14 + 0;
x = 14 >> 1;
y = 7 + 0;
}

Atunci putem vedea că func4 va fi numit prin clauza else a primei


dacă :

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

Primul apel recursiv va fi:

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

Din nou, aceeași ramură va fi luată:

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

Execuția va fi:

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

int y = 2 >> 31;


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

De data aceasta y == 1 deci atât dacă ramurile vor fi luate, cât și 0 vor fi returnate
din această invocație recursivă. Amintiți-vă că am invocat această funcție de două
ori, astfel încât rezultatul final va fi:

returnează func4(1, 0, 14);


returnare 2 * func4(1, 0, 6);
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 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino
returnare 2 * func4(1, 0, 2);
returnare 0;

Deoarece ultimul apel la func4 a returnat 0 rezultatul final va fi tot 0 si executia va


continua de aceasta data pe phase_4 la 0x40104d :

401048: E8 81 ff ff ff Apel 400fce <func4>


40104D: 85 c0 testa %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 Apel 40143a <explode_bomb>
40105D: 48 83 c4 18 adăuga $0x18,%rsp
401061: C3 Retq

Această linie și linia de mai jos testează dacă rezultatul acelei invocări func4 a
returnat sau nu 0 , dacă a făcut-o prima noastră intrare este corectă și execuția
continuă la 0x401051 . Această instrucțiune verifică pur și simplu dacă a doua
intrare este 0 și dacă este funcția returnează și faza 4 este dezamorsată:

10
Deci l-ai luat pe acela. Încercați-l pe acesta.

Avem ceva interesant aici, amintiți-vă că există două verificări despre y și a ? A


doua verificare utilizează instrucțiunea jge care verifică dacă valoarea este mai
mare sau egală cu (destul de evident dacă vă gândiți la ce ar putea însemna ge în
numele instrucțiunii). Faptul interesant aici este că verificarea anterioară a testat și
egalitatea cu jle . Deci, dacă y < = a și apoi verificați dacă y > = a există un singur
caz care ar satisface ambele condiții și acesta este y == a . Nu sunt sigur dacă
compilatorul a ales jge, chiar dacă codul a fost scris ca și cum (y == a) sau dacă
codul a fost scris ca și cum (y > = a) .

Un alt lucru interesant despre această fază este modul în care compilatorul
gestionează rezultatele apelurilor recursive. Deoarece eax este un registru,
rezultatele fiecărei invocări recursive vor fi disponibile cadrului stivei care a
invocat-o și apoi poate fi pur și simplu returnată fără a salva rezultatul în alt loc.
De asemenea, vedeți că după apelarea din nou a func4 , nu există nimic care să
gestioneze variabilele locale x și y , motiv pentru care acestea sunt stocate și în
registre în loc să fie salvate în interiorul fiecărui cadru de stivă.
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 Dezamorsarea unei bombe binare cu gdb - Partea 4 · carlosgaldino

Un exercițiu lăsat cititorului este încercarea de a găsi celelalte soluții posibile


pentru această fază, inclusiv o intrare care nici măcar nu numește func4 recursiv.
De asemenea, încercați să vedeți ce numere sunt nevalide pentru această fază și
rezultatul pe care func4 îl returnează atunci când se utilizează aceste numere.

Note

1. 0x8(%rsp) și 0xc(%rsp) stochează ambele numere de intrare ca variabile


locale în cadrul stivei 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 Dezamorsarea unei bombe binare cu gdb - Partea 5 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 5
28 aprilie 2016

Acest post face parte dintr-o serie în care vă arăt cum să dezamorsați o bombă
binară citind codul de asamblare și folosind gdb . S-ar putea să doriți să citiți
prima parte dacă nu ați făcut-o încă.

După dezamorsarea celei de-a patra faze , programul continuă cu faza următoare:

400EA2: E8 F7 05 00 00 Apel 40149e <read_line>


400ea7: 48 89 c7 .mov %rax,%CDI
400EAA: E8 B3 01 00 00 Apel 401062 <phase_5>

Codul pentru phase_5 este următorul:

0000000000401062 <phase_5>:
401062: 53 împinge %rbx
401063: 48 83 CE 20 sub $0x20,%rsp
401067: 48 89 FB .mov %rdi,%rbx
40106a: 64 48 8b 04 25 28 00 .mov %FS:0x28,%RAX
401071: 00 00
401073: 48 89 44 24 18 .mov %rax,0x18(%rsp)
401078: 31 c0 Xor %EAX,%EAX
40107a: E8 9C 02 00 00 Apel 40131b <string_length>
40107F: 83 f8 06 CMP $0x6,%eax
401082: 74 4e Je 4010d2 <phase_5+0x70>
401084: E8 B1 03 00 00 Apel 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 .mov %cl,(%rsp)
401092: 48 8b 14 24 .mov (%rsp),%rdx
401096: 83 e2 0f și $0xf,%edx
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx
4010a0: 88 54 04 10 .mov %dl,0x10(%rsp,%rax,1)
4010a4: 48 83 c0 01 adăuga 0x1,%rax
4010A8: 48 83 f8 06 CMP 0x6,%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 Dezamorsarea unei bombe binare cu gdb - Partea 5 · carlosgaldino
4010ac: 75 DD JNE 40108b <phase_5+0x29>
4010ae: C6 44 24 16 00 movb $0x0,0x16(%rsp)
4010b3: să fie 5e 24 40 00 .mov $0x40245e,%esi
4010b8: 48 8d 7c 24 10 pășune 0x10(%rsp),%CDI
4010bd: E8 76 02 00 00 Apel 401338 <strings_not_equal>
4010C2: 85 c0 testa %EAX,%EAX
4010C4: 74 13 Je 4010d9 <phase_5+0x77>
4010C6: E8 6f 03 00 00 Apel 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 .mov $0x0,%eax
4010d7: EB B2 JMP 40108b <phase_5+0x29>
4010d9: 48 8b 44 24 18 .mov 0x18(%rsp),%rax
4010de: 64 48 33 04 25 28 00 Xor %FS:0x28,%RAX
4010e5: 00 00
4010e7: 74 05 Je 4010ee <phase_5+0x8c>
4010e9: E8 42 FA FF FF Apel 400B30 <__stack_chk_fail@p
lt>
4010ee: 48 83 c4 20 adăuga $0x20,%rsp
4010F2: 5b pop %rbx
4010F3: C3 Retq

Primele câteva linii configurează stiva pentru această funcție și pe 0x40106a este
configurat protectorul stivei1.

Pe 0x40107a o nouă funcție string_length este apelată pentru a verifica lungimea


intrării pe care am dat-o phase_5 . Rețineți că argumentul pentru phase_5 este stocat
în registrul rdi și aceeași valoare este disponibilă atunci când
string_length se numește. Intrarea trebuie să aibă exact șase caractere, așa cum
arată comparația de pe 0x40107f . Dacă lungimea de intrare este corectă, atunci
sare la
0x4010d2 care setează rax la 0 și apoi sare la 0x40108b pentru a continua
executarea acestei faze.

La 0x40108b primul octet din șirul de intrare este copiat în ecx . Observați că la
începutul acestei funcții șirul de intrare stocat pe rdi a fost copiat în rbx la 0x401067
. Instrucțiunea de la 0x40108b folosește atât rbx, cât și rax, dar din moment ce rax
are o valoare de 0, adresa de date utilizată ca sursă va fi exclusiv adresa stocată pe
rbx . O putem confirma cu:

(gdb) p (caracter *) $rbx


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

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 Dezamorsarea unei bombe binare cu gdb - Partea 5 · carlosgaldino

Și pentru a vedea fiecare octet ca hex:

(GDPR) x/6xb $rbx


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

Trecând la următoarea instrucțiune, putem confirma, de asemenea, că octetul din


primul caracter este stocat pe ecx :

(gdb) i r $ecx
ECX 0x69 105

0x69 este i în tabelul ASCII.

Apoi, în următoarele două instrucțiuni, acest octet este copiat în rdx și pe 0x401096
la nivel de biți ȘI este efectuat împotriva acestui octet. Valoarea după AND la nivel
de biți este apoi utilizată ca decalaj pentru a copia o valoare dintr-o anumită locație
în același registru edx pe 0x401099 . Aceeași valoare de 1 octet este apoi stocată
într-o variabilă locală pe 0x4010a0 . Următoarea instrucțiune incrementează rax ,
care este apoi verificată de următoarea instrucțiune pentru a vedea dacă acest
proces a fost executat pentru toate caracterele din intrarea noastră. Dacă procesul
nu a fost efectuat pentru toate caracterele, atunci sare din nou la 0x40108b pentru a
citi următorul caracter și a repeta pașii de mai sus.

La sfârșitul acestui proces, o variabilă locală va conține un nou șir care este creat
prin utilizarea caracterelor noastre de intrare ca un decalaj la un șir misterios.

Dacă procesul a fost executat pentru toate caracterele, atunci pregătește


argumentele pentru următorul apel de funcții, începând de la 0x4010ae . Acest nou
șir despre care vorbim va fi folosit ca argument pentru funcția strings_not_equal pe
care am văzut-o înainte în această serie. Celălalt șir cu care va fi comparat al nostru
este situat la 0x40245e după cum puteți vedea pe 0x4010b3 .

După apelarea strings_not_equal rezultatul va fi testat pe 0x4010c2 și, dacă sunt


egale, codul va sări la sfârșitul phase_5 la 0x4010d9 care va verifica dacă stiva nu a
fost coruptă și va reveni. Dacă corzile sunt diferite, știi ce se va întâmpla.

Acum că știm fluxul pentru această fază, este timpul să vedem ce șir de intrare

trebuie să producă.

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 Dezamorsarea unei bombe binare cu gdb - Partea 5 · carlosgaldino

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

Acum tot ce avem nevoie este să ne uităm la șirul intermediar pentru a vedea care
sunt compensările pe care trebuie să le introducem, astfel încât șirul final să fie
fluturași .

(gdb) p (caracter *) 0x4024b0


$3 = 0x4024b0 <array> "maduiersnfotvbylDeci crezi că poți opri bomba cu ctrl-c, nu-i așa?"

Privind ieșirea de mai sus, putem ghici că șirul intermediar real trebuie să fie doar
maduiersnfotvbyl . Privind poziția fiecărui caracter, putem verifica apoi dacă
compensările corecte trebuie să fie:

scriso Comp
are ensa
f 0x9

l 0xf
y
0xe

e 0x5

r 0x6

s 0x7

Deci, răspunsul este de fapt orice secvență de caractere ale căror reprezentări de
octeți se termină în 9FE567 .

Având în vedere doar caracterele imprimabile din tabelul ASCII, putem concepe
următorul tabel:

Compe caractere
nsa posibile
0x9 )9IYiyy

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

Orice combinație a unui singur caracter pentru fiecare decalaj va dezamorsa


phase_5 .
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 Dezamorsarea unei bombe binare cu gdb - Partea 5 · carlosgaldino

A șasea și ultima fază va fi acoperită în următoarea postare.

Note

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 6
19 mai 2016

Acest post face parte dintr-o serie în care vă arăt cum să dezamorsați o bombă
binară citind codul de asamblare și folosind gdb . S-ar putea să doriți să citiți
prima parte dacă nu ați făcut-o încă.

Iată-ne ajunși la ultima fază. Aceasta este cea mai interesantă fază de până acum.
Codul pentru phase_6 este următorul:

00000000004010f4 <phase_6>:
4010F4 41 56 împinge %r14
4010F6 41 55 împinge %r13
4010F8 41 54 împinge %r12
4010FA 55 împinge %rbp
4010FB 53 împinge %rbx
4010FC 48 83 Ce 50 sub $0x50,%rsp
401100 49 89 E5 .mov %rsp,%r13
401103 48 89 E6 .mov %rsp,%rsi
401106 E8 51 03 00 00 Apel 40145c <read_six_numbers>
40110b 49 89 E6 .mov %rsp,%r14
40110E 41 î.Hr 00 00 00 00 .mov 0x0,%r12d
401114 4c 89 Ed .mov %r13,%rbp
401117 41 8b 45 00 .mov 0x0(%R13),%EAX
40111b 83 E8 01 sub $0x1,%eax
40111E 83 F8 05 CMP $0x5,%eax
401121 76 05 JBE 401128 <phase_6+0x34>
401123 E8 12 03 00 00 Apel 40143a <explode_bomb>
401128 41 83 C4 01 adăuga 0x1,%r12d
40112c 41 83 Fc 06 CMP 0x6,%r12d
401130 74 21 Je 401153 <phase_6+0x5f>
401132 44 89 E3 .mov %R12D,%EBX
401135 48 63 C3 movslq %ebx,%rax
401138 8b 04 84 .mov (%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 Apel 40143a <explode_bomb>
401145 83 C3 01 adăuga $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 Dezamorsarea unei bombe binare cu gdb - Partea 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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

40114B 7e e8 JLE 401135 <phase_6+0x41>


40114d 49 83 c5 04 adăuga 0x4 dolari,%r13
401151 EB C1 JMP 401114 <phase_6+0x20>
401153 48 8d 74 24 18 pășune 0x18(%rsp),%rsi
401158 4C 89 f0 .mov %r14,%rax
40115b B9 07 00 00 00 .mov $0x7,%ecx
401160 89 ca .mov %ecx,%edx
401162 2b 10 sub (%rax),%edx
401164 89 10 .mov %edx,(%rax)
401166 48 83 c0 04 adăuga 0x4,%rax
40116a 48 39 f0 CMP %rsi,%rax
40116d 75 F1 JNE 401160 <phase_6+0x6c>
40116F să fie 00 00 00 00 .mov $0x0,%esi
401174 EB 21 JMP 401197 <phase_6+0xa3>
401176 48 8b 52 08 .mov 0x8(%rdx),%rdx
40117a 83 c0 01 adăuga $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 .mov $0x6032d0,%EDX
401188 48 89 54 74 20 .mov %rdx,0x20(%rsp,%rsi,2)
40118d 48 83 c6 04 adăuga $0x4,%rsi
401191 48 83 februarie 18 CMP $0x18,%rsi
401195 74 14 Je 4011ab <phase_6+0xb7>
401197 8b 0c 34 .mov (%rsp,%rsi,1),%ecx
40119a 83 f9 01 CMP $0x1,%ecx
40119d 7e E4 JLE 401183 <phase_6+0x8f>
40119F B8 01 00 00 00 .mov $0x1,%eax
4011a4 BA D0 32 60 00 .mov $0x6032d0,%EDX
4011a9 EB CB JMP 401176 <phase_6+0x82>
4011Ab 48 8b 5c 24 20 .mov 0x20(%rsp),%rbx
4011b0 48 8d 44 24 28 pășune 0x28(%rsp),%rax
4011b5 48 8d 74 24 50 pășune 0x50(%rsp),%rsi
4011BA 48 89 d9 .mov %rbx,%rcx
4011bd 48 8b 10 .mov (%rax),%rdx
4011c0 48 89 51 08 .mov %rdx,0x8(%rcx)
4011C4 48 83 c0 08 adăuga 0x8,%rax
4011c8 48 39 f0 CMP %rsi,%rax
4011CB 74 05 Je 4011d2 <phase_6+0xde>
4011cd 48 89 d1 .mov %rdx,%rcx
4011d0 EB EB 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 .mov $0x5,%EBP
4011DF 48 8b 43 08 .mov 0x8(%rbx),%rax
4011e3 8b 00 .mov (%RAX),%EAX
4011e5 39 03 CMP %eax,(%rbx)
4011e7 7d 05 JGE 4011ee <phase_6+0xfa>
4011e9 E8 4C 02 00 00 Apel 40143a <explode_bomb>
4011ee 48 8b 5b 08 .mov 0x8(%rbx),%rbx
4011f2 83 ed 01 sub $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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino
4011F5: 75 E8 JNE 4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 adăuga $0x50,%rsp
4011FB: 5b pop %rbx
4011FC: 5D pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: C3 Retq

Este mai lung decât celelalte faze și pare mai complicat, așa că îl vom împărți în
părți pentru a explica ce face fiecare parte.

Prima parte la care ne putem uita este unde se inițializează funcția. Începe prin
salvarea unor valori ale registrelor, deoarece acestea vor fi utilizate ca variabile
locale în această funcție, apoi făcând loc altor variabile locale și apoi citind intrarea
care va fi utilizată pentru a dezamorsa faza. La 0x401106 putem vedea că intrarea
pentru această fază trebuie să fie șase numere:

4010F4: 41 56 împinge %r14


4010F6: 41 55 împinge %r13
4010f8: 41 54 împinge %r12
4010fa: 55 împinge %rbp
4010FB: 53 împinge %rbx
4010FC: 48 83 CE 50 sub $0x50,%rsp
401100: 49 89 E5 .mov %rsp,%r13
401103: 48 89 E6 .mov %rsp,%rsi
401106: E8 51 03 00 00 Apel 40145c <read_six_numbers>
40110b: 49 89 E6 .mov %rsp,%r14
40110E: 41 BC 00 00 00 00 .mov 0x0,%r12d
401114: 4c 89 Ed .mov %r13,%rbp
401117: 41 8b 45 00 .mov 0x0(%R13),%EAX
40111b: 83 E8 01 sub $0x1,%eax
40111E: 83 F8 05 CMP $0x5,%eax
401121: 76 05 JBE 401128 <phase_6+0x34>
401123: E8 12 03 00 00 Apel 40143a <explode_bomb>

După citirea celor șase numere și plasarea primului pe rsp , codul copiază adresa
care indică primul în r14 , apoi stabilește alte variabile și, în cele din urmă, pe
0x40111e verifică dacă primul număr pe care l-am furnizat este sau nu mai mic sau
egal cu 6 . Cum a făcut asta?

rsi este folosit pentru a reține al doilea argument pentru un apel de funcție și
înainte de apelarea read_six_numbers (cel 0x401103 ) adresa RSP a fost copiată în
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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

a se utiliza de către read_six_numbers . Acolo au fost stocate numerele noastre, într-


o matrice care începe de la adresa care este pe rsi . Aceeași adresă este stocată și pe
rsp și r13 . Putem să ne uităm la registre pentru a vedea care este adresa:

(GDPR) i r RSP RSI R13


RSP RSI 0x7fffffffdd60 0x7fffffffdd60
0x7fffffffdd60 140737488346464

R13 0x7fffffffdd60 140737488346464

După întoarcerea de la read_six_numbers aceeași adresă este stocată pe r14 la


0x40110b și pe 0x40114 este stocată și pe rbp .

Apoi, la 0x401117 valoarea stocată în adresa de pe r13 , primul nostru număr, este
copiat în eax și apoi codul verifică dacă este mai mic sau egal cu 6 .

Deci, acum că înțelegem cum a fost făcută verificarea, să trecem la următoarea


parte:

401128: 41 83 c4 01 adăuga 0x1,%r12d


40112C: 41 83 FC 06 CMP 0x6,%r12d
401130: 74 21 Je 401153 <phase_6+0x5f>
401132: 44 89 E3 .mov %R12D,%EBX
401135: 48 63 c3 movslq %ebx,%rax
401138: 8b 04 84 .mov (%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 Apel 40143a <explode_bomb>

Amintiți-vă că pe 0x40110e registrul r12d a stocat valoarea 0 , astfel încât primele


trei linii sunt doar pentru a verifica dacă codul a trecut deja prin 6 iterații. Să
continuăm 0x401132 unde noua valoare a r12d (care este 1 pentru prima iterație)
este copiată în ebx, care apoi este copiată în rax prin extinderea semnului de la
cuvânt dublu (4 octeți) la cuvânt quad (8 octeți), deoarece ebx este un registru pe
32 de biți, în timp ce rax este un registru pe 64 de biți.

După aceea, următorul număr pe care l-am introdus este verificat cu primul. Al
doilea număr este copiat în eax prin această instrucțiune:

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

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


Ceea ce face de fapt această linie este: înmulțiți cu 4 valoarea de pe rax ( 1 deoarece
a venit de la r12d ) și adăugați acea valoare la valoarea stocată pe rsp (adresa de
pornire a matricei care deține numerele noastre de intrare). Pentru prima iterație,
adresa rezultată va fi:

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

Valoarea stocată la această adresă rezultată va fi apoi copiată în eax . Pentru prima
iterație înseamnă al doilea număr de intrare.

Apoi, a doua noastră valoare (pe eax ) este comparată cu prima pentru a vedea
dacă nu sunt egale și sare la următoarea parte:

401145: 83 c3 01 adăuga $0x1,%EBX


401148: 83 FB 05 CMP 0x5,%EBX
40114b: 7e e8 JLE 401135 <phase_6+0x41>
40114D: 49 83 c5 04 adăuga 0x4 dolari,%r13
401151: EB C1 JMP 401114 <phase_6+0x20>

Primele trei linii vor verifica dacă am făcut această verificare pentru toate cele șase
numere, ceea ce înseamnă că nu putem introduce numere repetate. După aceea, pe
0x40114d , r13 este schimbat pentru a păstra adresa celui de-al doilea număr de
intrare prin adăugarea a 4 octeți ( sizeof(int) ) la adresa pe care r13 o stochează în
prezent. Apoi se întoarce la 0x401114 să facem aceleași verificări față de celelalte
numere pe care le-am furnizat.

Acum știm câteva fapte despre contribuția așteptată:

• Trebuie să fie șase numere;


• Acestea trebuie să fie mai mici sau egale cu 6 ;
• Nu se pot repeta.

Să continuăm să vedem ce alte caracteristici trebuie să aibă aceste numere.

După efectuarea acestor verificări inițiale, codul va sări la 0x401153 :

401153: 48 8d 74 24 18 pășune 0x18(%rsp),%rsi


401158: 4C 89 f0 .mov %r14,%rax
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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

40115b: B9 07 00 00 00 .mov $0x7,%ecx


401160: 89 ca .mov %ecx,%edx
401162: 2b 10 sub (%rax),%edx
401164: 89 10 .mov %edx,(%rax)
401166: 48 83 c0 04 adăuga 0x4,%rax
40116a: 48 39 f0 CMP %rsi,%rax
40116D: 75 F1 JNE 401160 <phase_6+0x6c>
40116F: să fie 00 00 00 00 .mov $0x0,%esi
401174: EB 21 JMP 401197 <phase_6+0xa3>

Prima linie a acestei părți definește pur și simplu adresa, ceea ce înseamnă că am
iterat peste toate cele șase numere. Primul număr este stocat pe adresa pe care o
deține rsp , iar al șaselea număr va fi pe $rsp + 0x14 (adresa de început + decalaj de
5 int ).

R14 deține, de asemenea, adresa pentru primul număr, deci va fi copiată în Rax
pe 0x401158 pentru a fi utilizată în această iterație. Apoi, pe următoarele două linii,
atât ecx cât și edx stochează valoarea 7 . După configurare, iterația reală va începe
scăzând mai întâi din edx valoarea stocată de adresa în rax (primul nostru număr
din prima iterație). Cel 0x401164 rezultatul acestei scăderi va suprascrie valoarea
pe rax și apoi pe 0x401166 codul va trece la următorul int pe care l-am furnizat,
comparați pe 0x40116d dacă am iterat peste toate cele șase numere și săriți înapoi
la 0x401160 dacă nu am făcut-o, altfel ieșiți din buclă și continuați execuția pe
0x401197 .

Să simulăm ce se întâmplă după executarea acestei bucle. Să presupunem că am


introdus 1 2 3 4 5 6 ca numere de intrare pentru această fază. Apoi, după iterarea în
această buclă, matricea noastră va avea următoarele valori noi: 6 5 4 3 2 1 . Bucla
doar schimbă toate numerele din matrice pentru a fi abs (n-7) .

După ieșirea din buclă continuăm pe 0x401197 ceea ce ne aduce la următoarea


parte din această fază:

401176: 48 8b 52 08 .mov 0x8(%rdx),%rdx


40117a: 83 c0 01 adăuga $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 .mov $0x6032d0,%EDX
401188: 48 89 54 74 20 .mov %rdx,0x20(%rsp,%rsi,2)
40118D: 48 83 c6 04 adăuga $0x4,%rsi
401191: 48 83 februarie 18 CMP $0x18,%rsi

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

401195: 74 14 Je 4011ab <phase_6+0xb7>


401197: 8b 0c 34 .mov (%rsp,%rsi,1),%ecx
40119a: 83 F9 01 CMP $0x1,%ecx
40119d: 7e E4 JLE 401183 <phase_6+0x8f>
40119F: b8 01 00 00 00 .mov $0x1,%eax
4011a4: Ba d0 32 60 00 .mov $0x6032d0,%EDX
4011a9: Eb Cb JMP 401176 <phase_6+0x82>

Deși prima linie a acestei părți este la 0x401176 , execuția începe de fapt la
0x401197 . După executarea acestei linii, ecx va deține primul număr din matricea
noastră, deoarece valoarea stocată pe rsi este 0 (din 0x40116f ), iar instrucțiunea de
pe 0x401197 înseamnă: copiați valoarea stocată de adresa $rsi*0x1 + $rsp în ecx .
Această operație înseamnă în mod clar că face parte dintr-o iterație și putem ghici
că rsi va fi actualizat în acest proces pentru a trece peste celelalte numere din
matrice.

401197: 8b 0c 34 .mov (%rsp,%rsi,1),%ecx


40119a: 83 F9 01 CMP $0x1,%ecx
40119d: 7e E4 JLE 401183 <phase_6+0x8f>
40119F: b8 01 00 00 00 .mov $0x1,%eax
4011a4: Ba d0 32 60 00 .mov $0x6032d0,%EDX
4011a9: Eb Cb JMP 401176 <phase_6+0x82>

Dacă numărul curent pe ecx este mai mic sau egal cu 1 , codul va sări la 0x401183 ,
altfel va sări la 0x401176 .

În ultima parte matricea noastră a devenit: 6 5 4 3 2 1 . Deci, codul va sări la


0x401176 . Să vedem ce se întâmplă acolo.

401176: 48 8b 52 08 .mov 0x8(%rdx),%rdx


40117a: 83 c0 01 adăuga $0x1,%eax
40117D: 39 c8 CMP %ecx,%eax
40117F: 75 f5 JNE 401176 <phase_6+0x82>
401181: EB 05 JMP 401188 <phase_6+0x94>

Observați că înainte de a sări la 0x401176 , adresa 0x6032d0 a fost stocată pe edx .


Apoi, valoarea stocată după primii 8 octeți ai acestei adrese va fi copiată în rdx pe
0x401176 . După această operație, eax va fi incrementată și comparată cu ecx
pentru a sări apoi condiționat într-un alt loc din această parte sau din nou pentru a
0x401176 . Valoarea inițială a eax în acest caz este 1 care a fost setată pe 0x40119f

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

înainte de a sări la 0x401176 . ecx deține valoarea 6, așa că ne întoarcem la


0x401176 și copiem valoarea pe $rdx + 0x8 la rdx , incrementați eax și verificați cu
ecx .

Valorile de pe ecx și eax se vor potrivi numai după șase iterații: în exemplul nostru,
ecx începe cu 6 și eax cu 1 . În acest caz, înainte de a sări la 0x401188 , rdx va
avea orice valoare este stocată în $rdx + 0x48 (de șase ori adăugând 0x8 la adresa
inițială și copiind valoarea din noua adresă în rdx ).

Apoi codul sare la 0x401188 :

401183: BA D0 32 60 00 .mov $0x6032d0,%EDX


401188: 48 89 54 74 20 .mov %rdx,0x20(%rsp,%rsi,2)
40118D: 48 83 c6 04 adăuga $0x4,%rsi
401191: 48 83 februarie 18 CMP $0x18,%rsi
401195: 74 14 Je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 .mov (%rsp,%rsi,1),%ecx
40119a: 83 f9 01 CMP $0x1,%ecx
40119d: 7e E4 JLE 401183 <phase_6+0x8f>
40119F: B8 01 00 00 00 .mov $0x1,%eax
4011a4: BA D0 32 60 00 .mov $0x6032d0,%EDX
4011a9: EB CB JMP 401176 <phase_6+0x82>

La această linie, adresa pe care rdx o deține va fi copiată la adresa care rezultă din:
$rsi*0x2 + $rsp + 0x20 . RSI este indicele peste iterația care se întâmplă:

(GDPR) i r rsi RSI 0x0 0

Apoi, rsi este incrementat cu 4 ( sizeof(int) ) și comparat cu 0x18 pentru a vedea


dacă am iterat peste toate cele șase numere. Dacă nu am făcut-o atunci pe
0x401197 , ecx primește următorul număr din matricea noastră și începe
următoarea iterație.

Acum, că știm despre ce este vorba despre această iterație, să vedem exact ce este
stocat de adresa inițială pe rdx :

(GDPR) x 0x6032d0
0x6032d0 <nod1>: 0x0000014c

Huh, nod1 , nume interesant, nu? Să vedem ce conține această adresă plus 8 octeți:
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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino
(gdb) x 0x6032d0+0x8
0x6032d8 <nod1+8>: 0x006032e0

Privind la ceea ce este pe 0x6032e0 :

(GDPR) x 0x6032e0
0x6032e0 <nod2>: 0x000000a8

Aha! Aceasta arată ca o listă legată. Pentru a vedea adresa nodului3 :

(GDPR) x 0x6032e0+0x8
0x6032e8 <nod2+8>: 0x006032f0

Și ce stochează node3 :

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

Avem o listă legată care conține o valoare int , identificatorul nodului și indicatorul
către următorul nod, ceva de genul următor:

nod struct {
int x;
int i;
nodul struct *următorul;
};

Deci, atunci când codul sare la 0x401188 , rdx va avea adresa valorii stocate de
node6 , deoarece matricea noastră este 6 5 4 3 2 1 și a trecut

0x401176 de șase ori:

(GDB) I R RDX
Rdx 0x603320 6304544
(GDPR) x 0x6032d0+0x48
0x603318 <nod5+8>: 0x00603320
(GDPR) x $rdx
0x603320 <nod6>: 0x000001bb

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

Adresa rdx deține, care stochează valoarea 0x1bb , va fi plasată în prima poziție a
unei noi matrice începând de la $rsp + 0x20 . Deoarece acest cod iterează peste
toate cele șase numere, după executarea acestei părți pentru toate numerele,
această nouă matrice va stoca de fapt adresele care dețin valorile pe care nodul
corespunzător le stochează, pe baza matricei noastre de intrare transformate.

Explicând: din 0x401176 până în 0x401181 codul caută nodul corespunzător pentru
iterația curentă. La 0x401188 adresa valorii x pe care o deține nodul este apoi
copiată în indicele curent de iterație din noua matrice. Apoi începe următoarea
iterație.

Să vedem care sunt valorile pe care fiecare nod le stochează și adresele acestora.
Mai întâi definim o comandă pentru a imprima valorile nodului și a trece la
următorul nod:

Definire Plist
set var $n = $arg 0
în timp ce $n
printf "nod%d (%p): valoare = %#.3x, next=%p\n", *($n+0x4), $n, *$n,
*($n+0x8)
set var $n = *($n+0x8)
capăt
capăt

Imprimarea valorilor:

(GDPR plist 0x6032d0


)
Nod1 (0x6032d0): valoare = 0x14c, următor = 0x6032e0
Nod2 (0x6032e0): valoare = 0x0a8, următor = 0x6032f0
Nod3 (0x6032f0): valoare = 0x39c, următor = 0x603300
nod4 (0x603300): valoare = 0x2b3, următor = 0x603310
nod5 (0x603310): valoare = 0x1dd, următor = 0x603320
Nod6 (0x603320): valoare = 0x1bb, următor = (zero)
După iterarea celor șase numere folosind matricea noastră de intrare care a fost
transformată în 6 5 4 3 2 1 , noua matrice (începând de la $rsp + 0x20 ) va păstra
adresele lui x în următoarea ordine: nod6 nod5 nod4 nod3 nod2 nod1 .

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


0x7fffffffdd80: 0x0000000000603320 0x0000000000603310
0x7fffffffdd90: 0x0000000000603300 0x00000000006032f0
0x7fffffffdda0: 0x00000000006032e0 0x00000000006032d0

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

După crearea acestei noi matrice, codul continuă execuția la 0x4011ab care este
următoarea parte:

4011ab: 48 8b 5C 24 20 .mov 0x20(%rsp),%rbx


4011b0: 48 8D 44 24 28 pășune 0x28(%rsp),%rax
4011b5: 48 8D 74 24 50 pășune 0x50(%rsp),%rsi
4011ba: 48 89 d9 .mov %rbx,%rcx
4011bd: 48 8b 10 .mov (%rax),%rdx
4011c0: 48 89 51 08 .mov %rdx,0x8(%rcx)
4011c4: 48 83 C0 08 adăuga 0x8,%rax
4011c8: 48 39 f0 CMP %rsi,%rax
4011CB: 74 05 Je 4011d2 <phase_6+0xde>
4011CD: 48 89 d1 .mov %rdx,%rcx
4011d0: Eb Eb 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 .mov $0x5,%EBP
4011df: 48 8b 43 08 .mov 0x8(%rbx),%rax
4011e3: 8b 00 .mov (%RAX),%EAX
4011e5: 39 03 CMP %eax,(%rbx)
4011e7: 7D 05 JGE 4011ee <phase_6+0xfa>
4011e9: E8 4c 02 00 00 Apel 40143a <explode_bomb>
4011ee: 48 8b 5b 08 .mov 0x8(%rbx),%rbx
4011f2: 83 Ed 01 sub $0x1,%EBP
4011F5: 75 E8 JNE 4011df <phase_6+0xeb>

La prima linie a acestei părți rbx primește valoarea primului element al noii
matrice, care este adresa lui x pentru nod6 . În linia următoare rax primește al
doilea element al noii matrice și în a treia linie rsi primește o adresă care tocmai a
trecut de ultimul element al acestei noi matrice, cel mai probabil pentru a verifica
mai târziu dacă am iterat peste întreaga matrice nouă.

Pe 0x4011ba , rcx va deține valoarea primului element al noii matrice, apoi rdx va
obține a doua valoare și în linia următoare, 0x4011c0 , această valoare va fi copiată
în $rcx + 0x8 . Să facem o copie de rezervă pentru un minut și să vedem valorile din
ambele registre după executarea instrucțiunii la 0x4011c0 :

(GDB) I R RCX RDX


RCX 0x603320 6304544
Rdx 0x603310 6304528

$rcx + 0x8 este adresa care deține indicatorul către următorul element al listei și

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

după executarea 0x4011c0 va indica valoarea stocată de rdx :

(GDPR) x $rcx+0x8
0x603328 <nod6+8>: 0x0000000000603310

După aceea, pe 0x4011c4 următoarea valoare din noua matrice este plasată în rax
pentru următoarea iterație, care este verificată față de rsi în linia următoare și
procesul se repetă. La sfârșitul acestuia, următorul indicator pentru fiecare nod va fi
modificat în funcție de valorile noii matrice. După cum am văzut mai sus, noua
matrice are următoarele valori:

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


0x7fffffffdd80: 0x0000000000603320 0x0000000000603310
0x7fffffffdd90: 0x0000000000603300 0x00000000006032f0
0x7fffffffdda0: 0x00000000006032e0 0x00000000006032d0

Aceste valori corespund nodului6 nod5 nod4 nod3 nod2 nod1 deci după iterația de
mai sus indicatorii vor fi modificați pentru a reflecta această ordine. O putem
confirma cu comanda noastră plist după executarea instrucțiunii pe 0x4011d2 :

(GDPR
) plist 0x603320
Nod6 (0x603320): valoare = 0x1bb, următor = 0x603310
nod5 (0x603310): valoare = 0x1dd, următor = 0x603300
nod4 (0x603300): valoare = 0x2b3, următor = 0x6032f0
Nod3 (0x6032f0): valoare = 0x39c, următor = 0x6032e0
Nod2 (0x6032e0): valoare = 0x0a8, următor = 0x6032d0
Node1 (0x6032d0): valoare = 0x14c, next = (zero)

Cu introducerea inițială a 1 2 3 4 5 6 codul a inversat lista. Rețineți că acum am


folosit adresa nodului6 ca adresă de pornire pentru plist , deoarece aceasta este
ordinea din matricea situată la $rsp + 0x20 . De asemenea, observați că pe 0x4011d2
următorul indicator pentru ultima iterație primește valoarea NULL și în cazul
nostru este nod1->următorul .

4011da: bd 05 00 00 00 .mov $0x5,%EBP


4011df: 48 8b 43 08 .mov 0x8(%rbx),%rax
4011e3: 8b 00 .mov (%RAX),%EAX
4011e5: 39 03 CMP %eax,(%rbx)
4011e7: 7d 05 JGE 4011ee <phase_6+0xfa>
4011e9: E8 4C 02 00 00 Apel 40143a <explode_bomb>
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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

4011ee: 48 8b 5b 08 .mov 0x8(%rbx),%rbx


4011f2: 83 ed 01 sub $0x1,%EBP
4011F5: 75 E8 JNE 4011df <phase_6+0xeb>

Acum că lista a fost modificată, execuția continuă la 0x4011da prin stocarea valorii
5 în ebp . Apoi, adresa valorii x a următorului nod este stocată pe rax și apoi în linia
următoare valoarea reală x este stocată pe eax (registru pe 32 de biți, deoarece
avem de-a face cu int ). Pe 0x4011e5 valoarea x din primul nod (la rbx ) este
comparată cu valoarea x a celui de-al doilea și dacă prima valoare este mai mare
sau egală cu a doua, codul sare la 0x4011ee care va actualiza valoarea rbx pentru a
indica următoarea valoare x și, de asemenea, va actualiza valoarea ebp care este
apoi comparată pentru a vedea dacă am iterat întreaga listă.

Deci, această iterație verifică dacă valoarea x a nodului curent este mai mare sau
egală cu următorul x pentru toate nodurile din listă. Dacă nu sunt, bomba
explodează după cum putem vedea la 0x4011e9 .

Cealaltă parte a acestei funcții, începând de la 0x4011f7 , curăță cadrul stivei


pentru phase_6 și returnează.

Acum, că am văzut tot ce face această funcție, știm că numerele noastre de


intrare sunt folosite pentru a sorta lista legată în ordine
descrescătoare.

Nu uitați că înainte de a fi utilizat pentru a reordona lista, fiecare număr de


intrare va fi schimbat în abs (n-7) .

Valorile fiecărui nod sunt:

X
nod # x (hex)
(decembri
1 0x14c 332

2 0x0a8 168
3
0x39c 924
4
0x2b3 691
5
0x1dd 477

6 0x1bb 443

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 Dezamorsarea unei bombe binare cu gdb - Partea 6 · carlosgaldino

Valorile lui x pentru lista finală trebuie să fie în următoarea ordine:

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

Ceea ce înseamnă că lista trebuie reordonată astfel:

nod3 -> nod4 -> nod5 -> nod6 -> nod1 -> nod2

Apoi, soluția pentru această fază este:

432165
Felicitări! Ai dezamorsat bomba!

În sfârșit! Bomba a fost dezamorsată!

Sau nu? Există ceva ciudat în fișierul C. Funcția principală se termină astfel:

intrare = read_line();
phase_6(intrare);
phase_defused();

/* Uau, au înțeles! Dar nu este ceva... absent? Poate


* Ceva ce au trecut cu vederea? Mua ha ha ha ha! */

returnare 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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino

Dezamorsarea unei bombe binare


cu gdb
- Partea 7
24 Mai 2016

Acest post face parte dintr-o serie în care vă arăt cum să dezamorsați o bombă
binară citind codul de asamblare și folosind gdb . S-ar putea să doriți să citiți
prima parte dacă nu ați făcut-o încă.

Asta este. Suntem în sfârșit în ultimul post al seriei.

În ultima postare , bomba a fost dezamorsată, dar era ceva ciudat în fișierul C.
Acesta a fost sfârșitul funcției principale :

intrare = read_line();
phase_6(intrare);
phase_defused();

/* Uau, au înțeles! Dar nu este ceva... absent? Poate


* Ceva ce au trecut cu vederea? Mua ha ha ha ha! */

returnare 0;

Și am lăsat un indiciu în ultima postare despre un apel la o funcție de secret_phase


de la phase_defused .

401630: E8 0d FC FF FF Callq 401242 <secret_phase>

phase_defused este o funcție care se numește de fiecare dată când o fază este
dezamorsată, așa că haideți să aruncăm o privire la ea:

00000000004015c4 <phase_defused>:
4015C4: 48 83 CE 78 sub $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 Dezamorsarea unei bombe binare cu gdb - Partea 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 <num_input_ șiruri de
4015df: 75 5e caractere> JNE 40163f <phase_defused+0x7b
>
4015e1: 4c 8d 44 24 10 pășune 0x10(%rsp),%r8
4015E6: 48 8d 4c 24 0C pășune 0xc(%rsp),%rcx
4015EB: 48 8d 54 24 08 pășune 0x8(%rsp),%rdx
4015f0: să fie 19 26 40 00 .mov $0x402619,%esi
4015F5: BF 70 38 60 00 .mov $0x603870,%EDI
4015fa: E8 F1 F5 ff ff Apel 400bf0 <__isoc99_sscanf@pl
t>
4015 și 83 f8 03 CMP $0x3,%eax
următoar
401602: 75 31 JNE 401635 <phase_defused+0x71
>
401604: să fie 22 26 40 00 .mov $0x402622,%esi
401609: 48 8d 7c 24 10 pășune 0x10(%rsp),%CDI
40160e: E8 25 FD ff ff Apel 401338 <strings_not_equal>
401613: 85 c0 testa %EAX,%EAX
401615: 75 1e JNE 401635 <phase_defused+0x71
>
401617: BF F8 24 40 00 .mov $0x4024f8,%EDI
40161C: E8 EF F4 ff ff Apel 400B10 <puts@plt>
401621: BF 20 25 40 00 .mov $0x402520,%EDI
401626: E8 E5 F4 ff ff Apel 400B10 <puts@plt>
40162B: B8 00 00 00 00 .mov $0x0,%eax
401630: E8 0d FC ff ff Apel 401242 <secret_phase>
401635: BF 58 25 40 00 .mov $0x402558,%EDI
40163a: E8 D1 F4 ff ff Apel 400B10 <puts@plt>
40163F: 48 8b 44 24 68 .mov 0x68(%rsp),%rax
401644: 64 48 33 04 25 28 00 Xor %FS:0x28,%RAX
40164B: 00 00
40164D: 74 05 Je 401654 <phase_defused+0x90
>
40164F: E8 DC F4 ff ff Apel 400B30 <__stack_chk_fail@p
lt>
401654: 48 83 c4 78 adăuga $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

Primele câteva linii până la 0x4015d8 sunt pentru setarea protectorului stivei1 și
apoi salvarea rax înainte de a-l seta la 0 pe 0x4015d6 . Apoi, pe 0x4015d8

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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino
compară dacă am trecut deja prin toate cele șase faze uitându-ne la numărul de
șiruri de intrare. Această comparație va fi adevărată numai după dezamorsarea
celor șase faze, astfel încât, înainte de ultima postare, codul a sărit întotdeauna la
0x40163f care a restabilit valoarea rax și a verificat protectorul stivei înainte de a
reveni.

Acum că a șasea fază a fost dezamorsată, codul va continua pe 0x4015e1 . În


următoarele trei linii, registrele r8 , rcx și rdx vor stoca adresele pentru a păstra
variabilele locale și apoi pe 0x4015f0 și 0x4015f5 , esi și edi primesc două adrese. Să
ne uităm la ele pentru a vedea ce este în fiecare adresă:

(gdb) p (caracter *) 0x402619


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

Cum aș putea ghici că erau corzi? Uită-te la următoarea linie:

4015FA: E8 F1 F5 FF FF Callq 400BF0 <__isoc99_sscanf@plt>

SSanf are următoarea semnătură:

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

Atât edi cât și esi sunt folosite pentru a susține primul și, respectiv, al doilea
argument. Apoi, singurul lucru pe care ambele registre l-au putut stoca au fost
adresele careindicau șirurile 2.

Valoarea 1 0 pe edi pare cunoscuta? Ar trebui, deoarece acesta este răspunsul


pentru a patra fază.

Sscanf este apoi folosit pentru a scana din nou intrarea celei de-a patra faze, dar
cu un format diferit acum, așteptând un șir după a doua valoare. Puteți vedea că pe
0x4015ff dacă nu vede 3 valori, sare la 0x401635 care va imprima următorul mesaj
și va returna:

(gdb) p (caracter *) $edi

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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino
$3 = 0x402558 "Felicitări! Ai dezamorsat bomba!"

În caz contrar, această funcție se va compara dacă am introdus șirul corect pentru
a activa faza secretă. Privind instrucțiunile de pe 0x401604 putem vedea care este
adresa șirului de activare:

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

Dacă intrarea pentru faza 4 include DrEvil la sfârșit, codul va apela apoi faza
secretă pe 0x401630 :

401630: E8 0d FC FF FF Callq 401242 <secret_phase>

Acum știm cum să ajungem la punctul de a apela secret_phase . Să aruncăm o privire


la codul pentru aceasta:

0000000000401242 <secret_phase>:
401242: 53 împinge %rbx
401243: E8 56 02 00 00 Apel 40149e <read_line>
401248: Ba 0a 00 00 00 .mov $0xa,%EDX
40124D: fi 00 00 00 00 .mov $0x0,%esi
401252: 48 89 C7 .mov %rax,%CDI
401255: E8 76 F9 Ff Ff Apel 400bd0 <strtol@plt>
40125a: 48 89 C3 .mov %rax,%rbx
40125d: 8D 40 Ff pășune -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 Apel 40143a <explode_bomb>
40126C: 89 de .mov %ebx,%esi
40126e: Bf f0 30 60 00 .mov $0x6030f0,%EDI
401273: E8 8c Ff Ff Ff Apel 401204 <distracție7>
401278: 83 F8 02 CMP $0x2,%eax
40127b: 74 05 Je 401282 <secret_phase+0x40>
40127D: E8 b8 01 00 00 Apel 40143a <explode_bomb>
401282: Bf 38 24 40 00 .mov $0x402438,%EDI
401287: E8 84 F8 Ff Ff Apel 400B10 <puts@plt>
40128C: E8 33 03 00 00 Apel 4015c4 <phase_defused>
401291: 5b pop %rbx
401292: C3 Retq
401293: 90 Nop
401294: 90 Nop

401295: 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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino
401296: 90 Nop
401297: 90 Nop
401298: 90 Nop
401299: 90 Nop
40129a: 90 Nop
40129B: 90 Nop
40129C: 90 Nop
40129d: 90 Nop
40129E: 90 Nop
40129F: 90 Nop

După citirea intrării pentru această fază secretă pe 0x401243 , edx va stoca valoarea
10 , esi va stoca NULL și rdi va stoca intrarea pe care am dat-o. Apoi strtol 3 va fi
apelat pe 0x401255 și judecând după valorile din registre, înseamnă că intrarea
noastră va fi convertită într-un număr în baza 10. După aceea, pe 0x40125a
numărul deja convertit va fi stocat pe rbx . Pe 0x40125d valoarea va fi modificată
scăzând 1 și plasată din nou pe eax . Apoi, o comparație cu 0x3e8 care este 1000 în
baza 10 . Dacă intrarea noastră este mai mică de 1000 , codul va sări la 0x40126c
pentru a continua și, dacă nu, bomba va exploda.

La 0x40126c valoarea noastra este plasata pe esi si edi primeste o adresa. Ambele
valori vor fi utilizate in urmatoarea functie fun7 care se numeste pe 0x401273 .
Rezultatul că fun7 trebuie să se întoarcă este 2 după cum puteți vedea pe 0x401278 .

Inainte de a ne uita la fun7 sa ne uitam la ce este in adresa pe care edi a primit-o si


este folosita ca prim argument pentru fun7 :

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

Hmm, n1 . Acest nume nu oferă niciun indiciu despre ce este exact acest lucru. Să
ne uităm la distracție7 atunci:

0000000000401204 <distracție7>:
401204: 48 83 CE 08 sub $0x8,%rsp
401208: 48 85 Ff testa %rdi,%CDI
40120b: 74 2b Je 401238
40120D: 8b 17 .mov <distracție7+0x34>
(%rdi),%edx
40120f: 39 F2 CMP %ESI,%EDX
401211: 7e 0d JLE 401220 <distracție7+0x1c>
401213: 48 8b 7f 08 .mov 0x8(%rdi),%CDI
401217: E8 E8 FF FF Apel 401204 <distracție7>
40121C: 01 c0 adăuga %EAX,%EAX
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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino
40121e: EB 1D JMP 40123d <distracție7+0x39>
401220: b8 00 00 00 00 .mov $0x0,%eax
401225: 39 f2 CMP %ESI,%EDX
401227: 74 14 Je 40123d <distracție7+0x39>
401229: 48 8b 7f 10 .mov 0x10(%rdi),%CDI
40122d: E8 d2 ff ff ff Apel 401204 <distracție7>
401232: 8d 44 00 01 pășune 0x1(%rax,%rax,1),%eax
401236: EB 05 JMP 40123d <distracție7+0x39>
401238: B8 ff ff ff ff .mov $0xffffffff,%eax
40123d: 48 83 c4 08 adăuga $0x8,%rsp
401241: C3 Retq

Mai întâi verifică dacă rdi este NULL ( 0x0 ) și dacă este funcția va returna valoarea
-1 ( 0xffffffff la 0x401238 ). Dacă nu, valoarea stocată în adresa rdi stocată va fi
plasată pe edx și apoi comparată (pe 0x40120f ) cu numărul nostru de intrare. Dacă
valoarea de pe edx este mai mică sau egală cu numărul nostru, codul merge la
0x401220 , dacă nu, continuă pe 0x401213 . Să continuăm 0x401213 apoi să ne
întoarcem să vedem ce se întâmplă în cealaltă ramură.

Pe 0x401213 rdi va stoca orice este 8 octeți după adresa deja pe rdi și apela fun7 din
nou.

În cealaltă ramură, când numărul de pe edx este mai mic sau egal cu numărul
nostru, codul merge la 0x401220 care setează eax la 0 , compară ceea ce este pe edx
cu numărul nostru și dacă sunt egale, merge la 0x40123d care se întoarce. Dacă
numerele sunt diferite, atunci instrucțiunea de la 0x401229 va schimba rdi pentru a
stoca orice este de 16 octeți după adresa curentă pe care o are și apoi apelați fun7
așa cum face cealaltă ramură.

În fiecare ramură, CDI este modificat pentru a menține noua adresă localizată fie
8, fie 16 octeți după adresa curentă. Primul lucru pe care îl deține RDI este un
număr, celelalte două sunt indicatori, deci acesta ar putea fi un arbore binar:

nod struct { int data; nodul struct *stânga; nodul struct *dreapta;

};

Nodul rădăcină, situat la adresa inițială cu care este apelat fun7 , este următorul:

(GDPR) x 0x6030f0
0x6030f0 <n1>: 0x00000024
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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino
(GDPR) x 0x6030f0+0x8
0x6030f8 <n1+8>: 0x00603110
(GDPR) x 0x6030f0+0x10
0x603100 <n1+16>: 0x00603130

După ce urmăm indicatorii nodului, putem vedea că structura arborescentă este


următoarea:

Știm cum este structurat copacul, dar nu știm ce trebuie să facem pentru a ajunge
la răspunsul corect. secret_phase apelează fun7 și se așteaptă să returneze valoarea 2
:

401273: E8 8c Ff Ff Ff Apel 401204 <distracție7>


401278: 83 F8 02 CMP $0x2,%eax
40127b: 74 05 Je 401282 <secret_phase+0x40>
40127D: E8 b8 01 00 00 Apel 40143a <explode_bomb>
401282: Bf 38 24 40 00 .mov $0x402438,%EDI
401287: E8 84 F8 Ff Ff Apel 400B10 <puts@plt>
40128C: E8 33 03 00 00 Apel 4015c4 <phase_defused>
401291: 5b pop %rbx
401292: C3 Retq

Deci, să vedem ce distracție7 se întoarce. Știm că este o funcție recursivă. Să vedem


care este cazul de bază, care sunt de fapt două:

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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino

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

Și:

401225: 39 f2 CMP %ESI,%EDX


401227: 74 14 Je 40123d <distracție7+0x39>

Ambele arată că funcția revine atunci când am ajuns la un indicator NULL (primul
caz) sau dacă numărul pe care l-am dat este egal cu cel din nodul curent (al doilea
caz).

Dar, în primul caz, codul sare la 0x401238 care setează valoarea returnată la
-1 :

401238: B8 ff ff ff ff mov
$0xffffffff,%eax
40123D: 48 83 C4 08 adaug
$0x8,%rsp
401241: C3 ă retq

Al doilea caz sare direct la 0x40123d dar înainte de a compara


numere la care setează valoarea 0 la 0x401220 :
returnată

401220: B8 00 00 00 00 .mov $0x0,%eax


401225: 39 f2 CMP %ESI,%EDX
401227: 74 14 Je 40123d <distracție7+0x39>

Deci, dacă furnizăm un număr care nu este prezent în arbore, codul va ajunge la un
indicator NULL și va returna -1 , iar dacă numărul nostru este prezent, acesta va
returna 0 .

Acum trebuie să ne uităm la fiecare apel recursiv la distracție7 și să vedem ce va


face apelul curent cu rezultatul apelului interior. Să vedem ce se întâmplă după ce
revine apelul interior fun7 :

40120f: 39F2 CMP %ESI,%EDX


401211: 7e0d JLE 401220
401213: 48 8b 7F 08 <distracție7+0x1c>
401217: E8E8 Ff ff ff .mov 0x8(%rdi),%CDI
Apel 401204 <distracție7>
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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino adăuga %EAX,%EAX
40121C: 01 C0
JMP 40123d <distracție7+0x39>
40121E: EB 1d

Acesta este cazul când numărul nostru este mai mic decât valoarea curentă a nodului.
Pur și simplu dublează valoarea returnată (pe 0x40121c ) și sare la 0x40123d pentru a
returna.

În cealaltă ramură, când numărul nostru este mai mare sau egal cu valoarea curentă a
nodului, merge la 0x401220 :

401220: B8 00 00 00 00 .mov $0x0,%eax


401225: 39 f2 CMP %ESI,%EDX
401227: 74 14 Je 40123d <distracție7+0x39>
401229: 48 8b 7F 10 .mov 0x10(%rdi),%CDI
40122d: E8 D2 Ff Ff Ff Apel 401204 <distracție7>
401232: 8d 44 00 01 pășune 0x1(%rax,%rax,1),%eax
401236: EB 05 JMP 40123d <distracție7+0x39>

Aici, dacă valorile sunt egale, funcția va returna 0 așa cum am văzut mai devreme, dar
dacă sunt diferite, fun7 va fi apelat din nou și valoarea returnată din apelul interior va
fi dublată ca în cealaltă ramură, dar în acest caz va adăuga și 1 la ea:

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

Deși lea înseamnă adresă eficientă de încărcare , această instrucțiune este


adesea folosită pentru operațiile aritmetice4 și exact acesta este cazul aici.
Instrucțiunea de mai sus înseamnă:

eax = 1 * rax + rax + 1

Simplificarea:

EAX = 2*RAX + 1

Ceea ce ne conduce apoi la următorul cod pentru distracție7 :

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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino

int fun7(nod *n, valoare int ) {


dacă (n == NULL) { return -1;
}

dacă (n->data <= valoare) { if (n->date == valoare) {


returnare 0;
}
returnare 2 * fun7(n->dreapta, valoare) + 1;
} altceva {
returnare 2 * fun7(n->stânga, valoare);
}
}

Privind din nou structura arborescentă, putem încerca să ghicim ce valoare va oferi
răspunsul corect vizitând nodurile corecte.

O opțiune este să vizitați 0x8 și 0x16 . Înlocuind adresele nodului cu datele reale pe
care le au, am avea următoarele apeluri la distracție7 :

întoarcere distracție7(0x24, 0x16); de la "secret_phase"


întoarcere 2 * fun7(0x8, 0x16);
întoarcere 2 * fun7(0x16, 0x16) + 1;
returnare 0;

Aceasta va da răspunsul corect:

Blesteme, ai găsit faza secretă!


Dar găsirea și rezolvarea ei sunt destul de diferite ... 22
Wow! Ai dezamorsat scena secretă!
Felicitări! Ai dezamorsat bomba!

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 Dezamorsarea unei bombe binare cu gdb - Partea 7 · carlosgaldino

Există un alt răspuns posibil pentru această fază și găsirea ei este lăsată ca un
exercițiu cititorului.

Note

1. Presupunând că acesta este un program corect. ↩

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

3. Pentru mai multe informații despre strtol : http://man7.org/linux/man-


pages/man3/strtol.3.html ↩

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

Funcția strtol() convertește partea inițială a șirului în nptr într-o valoare


întreagă lungă în funcție de baza dată, care trebuie să fie între 2 și 36
inclusiv, sau să fie valoarea specială 0.

4. Dacă doriți să aflați mai multe despre lea , diferența sa cu mov , cum și de ce
operațiile aritmetice pot fi efectuate cu lea puteți începe prin citirea următoarei
pagini:
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

S-ar putea să vă placă și