2012-10-22 12 views
9

L'articolo può essere trovato here.Smashing the stack esempio3.c confusione

Sto leggendo per distruggere lo stack e mi sono ritrovato bloccato su example3.c.

0x80004a3 <main+19>: call 0x8000470 <function> 
0x80004a8 <main+24>: addl $0xc,%esp 
0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp) 
0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax 

L'autore indica che vogliamo passare 0x80004a8-0x80004b2 e che questo salto è di 8 byte; come è stato determinato dall'autore questo è di 8 byte? Ho ricreato il codice e lo ha inviato attraverso objdump e ha scoperto che non è 8 byte (io sono su una macchina a 64 bit, ma ho fatto in modo di compilare utilizzando 32 bit):

8048452: e8 b5 ff ff ff   call 804840c <function> 
8048457: c7 44 24 1c 01 00 00 movl $0x1,0x1c(%esp) 
804845e: 00 
804845f: 8b 44 24 1c    mov 0x1c(%esp),%eax 
8048463: 89 44 24 04    mov %eax,0x4(%esp) 
8048467: c7 04 24 18 85 04 08 movl $0x8048518,(%esp) 

L'autore ha anche detto " Come sappiamo di aggiungere 8 all'indirizzo di ritorno? Abbiamo utilizzato un valore di test per primo (ad esempio 1) "Dove ha utilizzato questo valore di test in?

+0

Trasferirsi in StackOverflow su richiesta dell'utente. (+1, buona domanda.) –

+0

Se sottrai gli indirizzi proprio come in quell'articolo, ottieni 10 byte :) controlla i collegamenti alla fine della mia risposta, l'offset è sbagliato. – iabdalkader

+1

C'era una risposta che diceva che ora è stata rivista. Ecco l'ultima [revisione] (https://avicoder.me/2016/02/01/smashsatck-revived/) – NathanOliver

risposta

-1

Dopo tanto tempo e pensieri, ho finalmente risolto il problema. La risorsa che mi ha aiutato a risolvere questo problema è Stack smashing code not working on Linux kernel 2.6.38.7... Please help

Il più grande cambiamento che mi ha aiutato a risolvere questo era usando disassembly-flavor intel per gdb.

codice

Disassembled (per riferimento):

0804840c <function>: 
804840c: 55      push ebp 
804840d: 89 e5     mov ebp,esp 
804840f: 83 ec 10    sub esp,0x10 
8048412: 8d 45 f7    lea eax,[ebp-0x9] 
8048415: 83 c0 14    add eax,0x14 
8048418: 89 45 fc    mov DWORD PTR [ebp-0x4],eax 
804841b: 8b 45 fc    mov eax,DWORD PTR [ebp-0x4] 
804841e: 8b 00     mov eax,DWORD PTR [eax] 
8048420: 8d 50 05    lea edx,[eax+0x5] 
8048423: 8b 45 fc    mov eax,DWORD PTR [ebp-0x4] 
8048426: 89 10     mov DWORD PTR [eax],edx 
8048428: c9      leave 
8048429: c3      ret  

0804842a <main>: 
804842a: 55      push ebp 
804842b: 89 e5     mov ebp,esp 
804842d: 83 e4 f0    and esp,0xfffffff0 
8048430: 83 ec 20    sub esp,0x20 
8048433: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0 
804843a: 00 
804843b: c7 44 24 08 03 00 00 mov DWORD PTR [esp+0x8],0x3 
8048442: 00 
8048443: c7 44 24 04 02 00 00 mov DWORD PTR [esp+0x4],0x2 
804844a: 00 
804844b: c7 04 24 01 00 00 00 mov DWORD PTR [esp],0x1 
8048452: e8 b5 ff ff ff   call 804840c <function> 
8048457: c7 44 24 1c 01 00 00 mov DWORD PTR [esp+0x1c],0x1 
804845e: 00 
804845f: 8b 44 24 1c    mov eax,DWORD PTR [esp+0x1c] 
8048463: 89 44 24 04    mov DWORD PTR [esp+0x4],eax 
8048467: c7 04 24 18 85 04 08 mov DWORD PTR [esp],0x8048518 
804846e: e8 7d fe ff ff   call 80482f0 <[email protected]> 
8048473: c9      leave 
8048474: c3      ret  
8048475: 66 90     xchg ax,ax 
8048477: 66 90     xchg ax,ax 
8048479: 66 90     xchg ax,ax 
804847b: 66 90     xchg ax,ax 
804847d: 66 90     xchg ax,ax 
804847f: 90      nop 

C'erano due problemi con la mia comprensione su questo:

A) Il mio primo problema era trovare la quantità di byte di invadere ret all'interno function . Ancora; Ho fatto questo utilizzando la sintassi Intel per lo smontaggio e ha scoperto che:

Per impostare ret presso lo spazio corretto in memoria ret deve essere impostato al EIP quando la funzione è stato chiamato. Lo spazio indirizzo 8048412 si sposta in basso nello stack 0x9. Perché questo è un codice a 32 bit; per arrivare a ret aggiungiamo quindi un ulteriore 0x4 byte per la dimensione della parola. Per arrivare a ret significa che ret è impostato su 0x9 + 0x4 che è 13 in decimale.

Questo risolve il primo problema di arrivare a ret.

B) Il secondo problema è saltare la posizione di memoria 0x8048457. Questo viene fatto aggiungendo 7 byte a (*ret) che fa saltare ed eseguire il programma a 0x804845e che è 00 (NUL). Questo è solo inefficiente; così ho aggiunto il byte aggiuntivo ed eseguito 8 byte nello stack; quindi risultante in x = 0;

Ho trovato la quantità esatta di byte 8 (c7 44 24 1c 01 00 00 è 7 byte) e 00 è un byte. Questo ha risolto il mio ultimo problema.

Il mio codice C modificata:

void function(int a, int b, int c) { 
     char buffer1[5]; 
     int *ret; 

     ret = buffer1 + 13; //tried 11, 14, 20, 40, 38, 43 
     (*ret) += 8; // tried 5, 8, 12; 8 is correct value! 
} 

void main() { 
     int x; 
     x = 0; 
     function(1,2,3); 
     x = 1; 
     printf("%d\n", x); 
} 
+0

ti rendi conto che questo risolve il problema sulla tua macchina, e non spiega perché lo spostamento era di 8 byte Nell'articolo ? qual era la tua domanda – iabdalkader

+0

dovresti accettare una risposta se pensi che risponda alla tua domanda :) ovviamente dipende da te, sto solo indicandolo. – iabdalkader

+0

ma la tua risposta non risponde alla domanda, motivo per cui lo spostamento era di 8 byte nell'articolo, che era uno spostamento errato, credo, comunque, qualunque cosa ti aiuti a capire meglio. – iabdalkader

3

Non è così che interpreto l'articolo. Per come la intendo, vuole modificare l'indirizzo di ritorno in modo che l'assegnazione di x = 1; venga saltata, ovvero vuole che function venga restituito a dove verrà eseguito il printf.

Come si può vedere nel disassemblaggio, l'assegnazione è di 8 byte (c7 44 24 1c 01 00 00 00), quindi spostare l'indirizzo di ritorno di 8 byte in avanti lo sposterebbe oltre questa istruzione. Per quanto riguarda il commento "Abbiamo usato un valore di prova per primo", forse significa semplicemente che ha guardato il codice in un disassemblatore per capire la lunghezza, o che ha sperimentato diversi offset (?).

1

Lo spostamento nell'articolo è errato, dovrebbe essere 10 byte. Quando una funzione viene chiamata (o viene eseguito un salto), l'indirizzo di ritorno è impostato per eguagliare il puntatore all'istruzione + la dimensione istruzione corrente:

ret = IP + Curr_Inst_size 

Così, quando la chiamata alla funzione ritorna, il puntatore all'istruzione deve essere uguale 0x80004a8 (0x80004a3 + la dimensione istruzione di chiamata):

0x80004a3 <main+19>: call 0x8000470 <function> 
--> 0x80004a8 <main+24>: addl $0xc,%esp    
    0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp) 
    0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax 

Tuttavia, si desidera impostare il puntatore all'istruzione per 0x80004b2 invece, di saltare l'assegnazione, è anche, inevitabilmente, deve saltare un'altra istruzione (addl $0xc,%esp) t o arriva, o in altre parole, è necessario aggiungere (0x80004b2-0x80004a8) byte o 10 byte, il puntatore all'istruzione di saltare le due istruzioni:

0x80004a3 <main+19>: call 0x8000470 <function> 
    0x80004a8 <main+24>: addl $0xc,%esp    
    0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp) 
--> 0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax 

La dimensione effettiva istruzione dipende operandi, tipo di macchina etc. Ma in questo esempio, lo addl è lungo 3 byte e lo movl è lungo 7 byte. Si potrebbe verificare il x86 Instruction Set Reference per la dimensione di istruzioni esatte, o si può compilare e disassemblare il codice, vedrete che queste due istruzioni sono 10 byte lunghi:

int main() 
{ 
    asm("addl $0xc,%esp\n\ 
     movl $0x1,0xfffffffc(%ebp)"); 

} 

gdb:

0x08048397 <+3>: 83 c4 0c    add $0xc,%esp 
0x0804839a <+6>: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%ebp) 

c'è anche una discussione here e here su questo esatto stesso problema nell'esempio 3.