poniedziałek, 26 stycznia 2015

Penetrujemy aplikacje napisane w języku C - narzedzie GDB cz.3

To już ostatni wpis do wstępu z narzędziem GDB. Wydaje mi się, że jest to wiedza po której można ta aplikacje dalej poznawać, bo jest ona naprawde duża.
Wracając do tematu, chciałbym się skupić na tym czy jesteśmy w stanie określić co znajduje się w adresie rip i takim oto sposobem omówię kilka instrukcji, by sprawdzić jak wygląda nasz kod maszynowy, który wcześniej był zapisany w aplikacji C.
 (gdb) x/10i $rip  
 =&gt; 0x400564 <main>:     movl  $0x0,-0x4(%rbp)  
   0x40056b <main>:     jmp  0x40057b <main>  
   0x40056d <main>:     mov  $0x400634,%edi  
   0x400572 <main>:     callq 0x400440 <puts plt="">  
   0x400577 <main>:     addl  $0x1,-0x4(%rbp)  
   0x40057b <main>:     cmpl  $0x9,-0x4(%rbp)  
   0x40057f <main>:     jle  0x40056d <main>  
   0x400581 <main>:     mov  $0x0,%eax  
   0x400586 <main>:     leaveq   
   0x400587 <main>:     retq    
 (gdb)   

Kod robi podwójny skok pamięci do instrukcji
 cmpl  $0x9,-0x4(%rbp)  

Jest to instrukcja porównawcza, która sprawdza czy warunek jest spełniony, jeśli wartości są mniejsze lub równe to jest ponowy skok do pamięci 0x40056d, a w przeciwnym wypadku idzie do kolejnej instrukcji. Nasŧepnie możemy wykonywać kolejne instrukcje i zauważyć, że w pewnym momęcie zobaczymy instrukcje puts.
 (gdb) nexti   
 0x000000000040056b     5          for(i = 0; i < 10; i++) {   
 (gdb) x/i %rip  
 A syntax error in expression, near `%rip'.  
 (gdb) x/i $rip  
 => 0x40056b <main+15>:     jmp  0x40057b <main+31>  
 (gdb) nexti   
 0x000000000040057b     5          for(i = 0; i < 10; i++) {   
 (gdb) x/i $rip  
 => 0x40057b <main+31>:     cmpl  $0x9,-0x4(%rbp)  
 (gdb) nexti   
 0x000000000040057f     5          for(i = 0; i < 10; i++) {   
 (gdb) x/i $rip  
 => 0x40057f <main+35>:     jle  0x40056d <main+17>  
 (gdb) nexti   
 6               puts("Hello, world!\n");   
 (gdb)   

Teraz sprawdzę na jaki adres pamięci wskazuje teraz program:
 (gdb) i r rip  
 rip      0x40056d     0x40056d <main+17>  
 (gdb) x/2i $rip  
 => 0x40056d <main+17>:     mov  $0x400634,%edi  
   0x400572 <main+22>:     callq 0x400440 <puts@plt>  
 (gdb)   

Ciekawe co kryje edi i mogę to spokojnie także podglądnąć:
 (gdb) i r edi  
 edi      0x1     1  
 (gdb) x/6cb $0x400634  
 Value can't be converted to integer.  
 (gdb) x/6cb 0x400634  
 0x400634:     72 'H'     101 'e'     108 'l'     108 'l'     111 'o'     44 ','  
 (gdb)   
Znalazłem Hello world, aby wygadało lepiej można wydrukować to tak:
 (gdb) x/12cb 0x400634  
 0x400634:     72 'H'     101 'e'     108 'l'     108 'l'     111 'o'     44 ','     32 ' '     119 'w'  
 0x40063c:     111 'o'     114 'r'     108 'l'     100 'd'  
GDB to wspaniałe narzędzie, gdzie ja nie pokazałem jego wszystkich możliwości i aby się lepiej go nauczyć, trzeba popatrzeć jak każda instrukcja wygląda po skompilowaniu na kod maszynowy - czyli życzę miłej zabawy, w analizowaniu programów napisanych w C. Nasŧepny post będzie omawiał wsŧep do projektu jaki z kumplami zaczynamy, a po jego zakończeniu powrócimy do C i może postaramy się zrobić jakiś nabzdurzyć pamięci.

niedziela, 4 stycznia 2015

Penetrujemy aplikacje napisane w języku C - narzedzie GDB cz.2

Ostatnio nie skończyłem omawiać tego narzędzia - to znów będę męczył coś na jego temat. Ostatnio bawiłem się wyświetlaniem rejestru RIP w różnych systemach liczbowych, a dziś będziemy analizować jego zawartość. Poniżej pokazuje instrukcje, która określa liczbę badanych jednostek w docelowym adresie.
 (gdb) x/12x $rip 

 0x400564 <main+8>:     0x00fc45c7     0xeb000000     0x0634bf0e     0xc9e80040 

 0x400574 <main+24>:     0x83fffffe     0x8301fc45     0x7e09fc7d     0x0000b8ec 

 0x400584 <main+40>:     0xc3c90000     0x00841f0f     0x00000000     0x246c8948 


Dodatkowo możemy zmienić rozmiar jednostki, bo aktualnie jest ustawiona na 4bajty i możemy je formatować na pojedynczy bajt, pół słowo(2bajty), słowo o rozmiarze 4 bajtów i słowo podwójne.
 (gdb) x/12x $rip 

 0x400564 <main+8>:     0x00fc45c7     0xeb000000     0x0634bf0e     0xc9e80040 

 0x400574 <main+24>:     0x83fffffe     0x8301fc45     0x7e09fc7d     0x0000b8ec 

 0x400584 <main+40>:     0xc3c90000     0x00841f0f     0x00000000     0x246c8948 

 (gdb) x/8xb $rip 

 0x400564 <main+8>:     0xc7     0x45     0xfc     0x00     0x00     0x00     0x00     0xeb 

 (gdb) x/8xh $rip 

 0x400564 <main+8>:     0x45c7     0x00fc     0x0000     0xeb00     0xbf0e     0x0634     0x0040     0xc9e8 

 (gdb) x/8xw $rip 

 0x400564 <main+8>:     0x00fc45c7     0xeb000000     0x0634bf0e     0xc9e80040 

 0x400574 <main+24>:     0x83fffffe     0x8301fc45     0x7e09fc7d     0x0000b8ec 

 (gdb) x/8xg $rip 

 0x400564 <main+8>:     0xeb00000000fc45c7     0xc9e800400634bf0e 

 0x400574 <main+24>:     0x8301fc4583fffffe     0x0000b8ec7e09fc7d 

 0x400584 <main+40>:     0x00841f0fc3c90000     0x246c894800000000 

 0x400594 <__libc_csu_init+4>:     0x8d48e02464894cd8     0x258d4c002008672d 

Powyżej można zauważyć pewne udziwnienia w danych. Przy zmianie adnotacji ze słowa na pół słowa czy też na pojedynczy bajt, każda adnotacja jakby pokazywała coś innego. Pierwszy wydruk pokazuje jednak, że pierwsze dwa bajty to 0xc7 i 0x45, ale gdy badamy po pół słowie, w tym samym miejscu pamięci, pokazywana jest wartość 0x45c7. Spokojnie jest to tylko odwrócona kolejność bajtów i ten sam efekt jest przy całym słowie. Jest to logiczne z punktu widzenia procesora, bo wartości są przechwytywane w kolejności little endian.
To tyle na ten post, w następnym postaram się troszkę posprawdzać co kryje aplikacja po skompilowaniu i czy rzeczywiście jest to co w niej zawieraliśmy.