User Tools

Site Tools


laboratoare:laborator-08

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator-08 [2015/12/02 04:34]
adrian.bogatu
laboratoare:laborator-08 [2015/12/02 12:31] (current)
vladimir.diaconescu OCD change
Line 1: Line 1:
-====== Laborator 8: Interfața în linia de comandă, analiza statică și dinamică ======+====== Laborator 08: Interfața în linia de comandă, analiza statică și dinamică ======
  
 După un scurt breviar care va explica noțiunile introduse în acest laborator, va urma o parte practică care alternează între secțiuni de tip tutorial, cu parcurgere pas cu pas și prezentarea soluției, și exerciții care trebuie să fie rezolvate. După un scurt breviar care va explica noțiunile introduse în acest laborator, va urma o parte practică care alternează între secțiuni de tip tutorial, cu parcurgere pas cu pas și prezentarea soluției, și exerciții care trebuie să fie rezolvate.
Line 27: Line 27:
 ===== Tutoriale și exerciții ===== ===== Tutoriale și exerciții =====
  
-În cadrul exercițiilor vom folosi arhiva de laborator.+În cadrul exercițiilor vom folosi ​{{laboratoare:​lab-08-tasks.zip|arhiva de laborator}}.
  
 Descărcați arhiva, decomprimați-o și accesați directorul aferent. Descărcați arhiva, decomprimați-o și accesați directorul aferent.
Line 151: Line 151:
 === Lansarea în execuție a programului === === Lansarea în execuție a programului ===
  
-Pentru a lansa programul urmărit în execuție există două comenzi:+Pentru a lansa programul urmărit în execuție există două comenzi ​disponibile:
   * **run** - această comandă va lansa în execuție programul   * **run** - această comandă va lansa în execuție programul
   * **start** - spre deosebire de ''​run'',​ această comandă va începe execuția programului,​ însă se va opri imediat după intrarea în main   * **start** - spre deosebire de ''​run'',​ această comandă va începe execuția programului,​ însă se va opri imediat după intrarea în main
Line 181: Line 181:
  
 Pentru continuarea programului după eventuala sa oprire într-un breakpoint, puteți folosi comanda ''​continue''​. Pentru continuarea programului după eventuala sa oprire într-un breakpoint, puteți folosi comanda ''​continue''​.
 +
 +Un alt lucru interesant în GDB este comanda ''​commands'',​ care poate asocia unui breakpoint un bloc de comenzi GDB ce vor fi executate la fiecare oprire în breakpoint-ul respectiv.
 +
 +Exemplu:
 +<​code>​
 +(gdb) break *0x004013af
 +Breakpoint <n> at 0x4013af
 +(gdb) commands <n>
 +Type commands for breakpoint(s) <n>, one per line.
 +End with a line saying just "​end"​
 +> print $eax
 +> x/i $eip
 +> end
 +</​code>​
 +
 +Pentru a nu rămâne blocat în breakpoint (spre exemplu dacă scrieți un script de gdb), puteți adăuga în blocul de instrucțiuni și comanda ''​continue''​.
 +
 +Haideți să adăugăm un breakpoint la label-ul ''​ok''​. Dacă dăm ''​continue'',​ vom observa că programul s-a oprit în breakpoint-ul tocmai creat.
 +<​note>​
 +Variaţii:​\\ ​
 +**break label** - breakpoint la labelul **label**\\ ​
 +**break *(label + <​offset>​)** - breakpoint la **label + offset**\\ ​
 +</​note>​
  
 === Parcurgerea instrucțiunilor === === Parcurgerea instrucțiunilor ===
Line 188: Line 211:
   * **stepi** - care practic trimite o instrucțiune spre execuție și după execuția acesteia întoarce control-ul la debugger (programul se oprește)   * **stepi** - care practic trimite o instrucțiune spre execuție și după execuția acesteia întoarce control-ul la debugger (programul se oprește)
   * **nexti** - comandă similară cu ''​stepi'',​ însă dacă instrucțiunea curentă este un apel de funcție, debugger-ul nu va intra în funcție (va chema funcția și se va opri la următoarea instrucțiune după ''​call''​)   * **nexti** - comandă similară cu ''​stepi'',​ însă dacă instrucțiunea curentă este un apel de funcție, debugger-ul nu va intra în funcție (va chema funcția și se va opri la următoarea instrucțiune după ''​call''​)
 +
 +Dacă emitem comanda ''​stepi'',​ putem observa că se afișează instruction pointer-ul instrucțiunii următoare dupa cea la care am făcut break (prima de la label-ul ''​ok''​).
  
 === Dezasamblarea programului === === Dezasamblarea programului ===
Line 195: Line 220:
 <​note>​ <​note>​
 Default, sintaxa folosită de GDB la dezasamblare este cea "​AT&​T"​. Pentru a folosi sintaxa cunoscută vouă (sintaxa intel), executați în GDB comanda ''​set disassembly-flavor intel''​. Default, sintaxa folosită de GDB la dezasamblare este cea "​AT&​T"​. Pentru a folosi sintaxa cunoscută vouă (sintaxa intel), executați în GDB comanda ''​set disassembly-flavor intel''​.
 +</​note>​
 +
 +În cadrul exemplului nostru, dacă cerem dezasamblarea funcției curente (folosind ''​disassemble''​ fără parametri) putem observa că ne aflăm la label-ul ''​ok''​. Observație:​ GDB iterpretează label-ul ''​ok''​ ca o funcție din cauza codului inițial, care este scris în limbaj de asamblare.
 +
 +Pentru a vedea mai clar efectul ''​stepi''/''​nexti''​ putem rula commanda ''​disassemble''​ înainte și după stepping.
 +
 +<​note>​
 +Dacă ați intrat într-o funcție lungă și nu vreți să dați de ''​nexti''​ de foarte multe ori, vă recomandăm instrucțiunea GDB ''​finish'',​ care "​termină"​ o funcție. **Atenție** la funcțiile recursive.
 +</​note>​
 +<​note>​
 +**disassemble label, +<​length>​** - afişează <​length>​ bytes de cod dezasamblat începând de la labelul **label**.
 </​note>​ </​note>​
  
 === Inspectarea memoriei și a registrelor === === Inspectarea memoriei și a registrelor ===
  
-Pentru a afișa diferite valori ​accesiblie ​GDB-ului se folosește comanda ''​print''​. De exemplu, pentru a afișa ​ valoarea unui registru (de exemplu eax), vom folosi ​contrucția ''​print $eax''​.+Pentru a afișa diferite valori ​accesibile ​GDB-ului se folosește comanda ''​print''​. De exemplu, pentru a afișa ​ valoarea unui registru (de exemplu eax), vom folosi ​construcția ''​print $eax''​.
  
 Pentru inspectarea memoriei se folosește comanda ''​x''​ (examine). Modul de folosire al acestei comenzi este următorul: Pentru inspectarea memoriei se folosește comanda ''​x''​ (examine). Modul de folosire al acestei comenzi este următorul:
Line 209: Line 245:
   * ''​f''​ este formatul de afișare (x pentru hexa, d pentru zecimal, s pentru șir de caractere și i pentru instrucțiuni)   * ''​f''​ este formatul de afișare (x pentru hexa, d pentru zecimal, s pentru șir de caractere și i pentru instrucțiuni)
   * ''​u''​ este dimensiunea unui element (b pentru 1 octet, h pentru 2, w pentru 4 și g pentru 8 octeți)   * ''​u''​ este dimensiunea unui element (b pentru 1 octet, h pentru 2, w pentru 4 și g pentru 8 octeți)
 +
 +De exemplu, o funcționalitate similară cu ''​disassemble''​ o putem obține și folosind ''​x''​ unde formatul este instrucțiune. Astfel, putem afișa, de exemplu, 10 instrucțiuni începând de la instrucțiunea curentă cu construcția ''​x/​10i $eip''​.
  
 ==== [0.5p] 7. Afișarea unor informații la fiecare trecere printr-un breakpoint ==== ==== [0.5p] 7. Afișarea unor informații la fiecare trecere printr-un breakpoint ====
-==== [1p] 8. Afișarea adresei de retur a unei funcții ====+ 
 +Folosind executabilul creat la exercițiul anterior (''​gdb-tutorial.asm''​),​ trebuie să setați un breakpoint la intrare în bucla din program (când se mută în subregistrul ''​al''​ un caracter din șirul input). În plus, trebuie să adăugați o serie de comenzi astfel încât la fiecare intrare în buclă, GDB să afișeze valoarea subregistrului ''​al''​ și valoarea counter-ului (în cazul nostru ''​ecx''​). **Hint!** folosiți comanda ''​commands''​. 
 + 
 +==== [1p] 8. Afișarea adresei de retur ale unor funcții ==== 
 + 
 +Folosind tot executabilul de mai înainte, afișați adresele de return ale tuturor funcțiilor din program (gets, atoi, printf, usage). Pentru cazul funcției usage, trebuie să porniți programul fără parametri. 
 ==== [0.5p] 9. Tutorial: Depanarea unui Segfault folosind GDB ==== ==== [0.5p] 9. Tutorial: Depanarea unui Segfault folosind GDB ====
 +
 +Pentru acest tutorial pornim de la fișierul sursă ''​segfault-tutorial.asm''​. Înainte de a începe tutorialul, citiți sursa, înțelegeți ce face și apoi asamblați și link-editați programul.
 +
 +Dacă încercați să rulați programul fără parametri, se poate observa că progamul "​crapă"​. Dacă executăm programul sub gdb, putem observa că programul primește ''​SIGSEGV''​. Pentru a putea determina problema, executăm comanda ''​backtrace'',​ care arată ultimele stack frame-uri prin care execuția programului a trecut. În cazut nostru, doar două:
 +<​code>​
 +(gdb) backtrace
 +#0 0x7607d2c3 in strcat () ...
 +#1 0x00000000 in ?? ()
 +</​code>​
 +
 +Ne dăm seama că frame-ul interesant pentru noi este ''#​0''​. Pentru a schimba frame-ul curent folosim comana ''​frame <nr. frame>''​. Odată ce suntem pe frame-ul ce ne interesează putem să încercăm dezasamblarea programului pentru a identifica problema.
 +
 +După instrucțiunea ''​disassemble'',​ putem observa instruction pointer-ul (notat pe dezasamblarea din GDB cu ''​=>''​ în dreptul unei instrucțiuni) că a rămas la instrucțiunea
 +<​code>​mov eax, DWORD PTR [ecx]</​code>​
 +
 +Deja putem bănui o posibilă cauză a segmentation fault-ului. Inspectați registrul ecx. Ce valoare are? Ce încearcă să facă instrucțiunea cu probleme?
 +
 ==== [1.5p] 10. Rezolvarea unui Segfault ==== ==== [1.5p] 10. Rezolvarea unui Segfault ====
 +
 +Pornind de la executabilul ''​segfault.exe'',​ rulat sub gdb, analizați atât backtrace-ul cât și pas cu pas codul pentru a identifica cauza care duce la Segmentation Fault.
 +
 ==== [1p] 11. Tutorial: IDA ==== ==== [1p] 11. Tutorial: IDA ====
-==== [1.5p] Bonus: Modificarea control-flow-ului unui program folosind GDB ====+ 
 +În această secțiune vom prezenta foarte pe scurt câteva dintre numeroasele aspecte ale programului IDA. 
 + 
 +În primul rând va trebui să descărcați installer-ul de IDA de [[https://​out7.hex-rays.com/​files/​idafree50.exe|aici]] și să-l instalați pe mașinile din laborator. După ce programul s-a instalat, porniți Ida Pro Free. La prompt-ul de welcome alegeți varianta ''​[GO] Work on your own''​. Din meniul de sus dați "​Open..."​ și deschideți fișierul de la exercițiul 10 (''​segfault.exe''​). 
 + 
 +Dintre numeroasele view-uri posibile din IDA, cele mai importante sunt: 
 + 
 +  * Control-flow graph-ul ce conține pentru fiecare bloc dezasamblarea sa 
 +  * **Names** care este o tabelă cu simbolurile din executabil 
 +  * **Functions** care conține toate informațiile despre o funcție (dacă e statică sau dintr-o bibliotecă;​ tipul funcției etc.) 
 + 
 +Deși pot fi multe de spus despre IDA, în cadrul acestui laborator ne vom limita doar la capabilitățile de analiză statică ale sale. 
 +<​note>​ 
 +IDA este destul de avansat încât are posibilitatea de a face tracking şi în Kernelul sistemului de operare. Motiv pentru care trebuie rulat cu drepturi de administrator pentru a putea dreptul la o resursă critică a sistemului. 
 +</​note>​ 
 +==== [2p] Bonus: Modificarea control-flow-ului unui program folosind GDB ==== 
 + 
 +Pornind de la executabilul ''​control-flow.exe''​ rulat sub gdb, trebuie să găsiți o modalitate să se afișeze un flag. Până nu veți rezolva corect problema, se va afișa "No flag for you."​ 
 ==== [2p] Bonus: Decompilarea unui program folosind IDA ==== ==== [2p] Bonus: Decompilarea unui program folosind IDA ====
  
 +Pornind de la fișierul obiect ''​decompile.obj'',​ treaba voastră este să reconstruiți codul sursa (scris în C) din care a provenit binarul. Puteți folosi orice utilitar de analiză statică, însă cel mai indicat pentru acest task este IDA, deoarece reprezintă foarte clar graful de control al execuției.
laboratoare/laborator-08.1449023646.txt.gz · Last modified: 2015/12/02 04:34 by adrian.bogatu