Newsgroup: it.comp.lang.c
Titolo: non capisco l'assembler..

Ciao a tutti,
Compilando con l'opzione -S di gcc il seguente codice (che sfrutta un buffer
overflow per saltare l'assegnazione x=1 nel main):
g4b0@slack: more ex3b.c
void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;
   printf ("%x - %x - %x - %x\n",&ret,buffer2,buffer1,*(buffer1+9));
   ret = buffer1 + 9;
   (*ret) += 10;
}
void main() {
  int x;
  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}
Non capisco perchč il codice assembler risultante, nel prologo di function,
aumenta di 40byte lo stack pointer:
function:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40, %Esp
Segue il codice asm completo:
g4b0@slack: more ex3b.asm
        .file   "ex3b.c"
        .section        .rodata
.LC0:
        .string "%x - %x - %x - %x\n"
        .text
.globl function
        .type   function, @function
function:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $40, %Esp
        leal    -5(%ebp), %eax
        addl    $20, %eax
        movb    (%eax), %al
        movsbl  %al,%eax
        subl    $12, %esp
        pushl   %eax
        leal    -5(%ebp), %eax
        pushl   %eax
        leal    -15(%ebp), %eax
        pushl   %eax
        leal    -20(%ebp), %eax
        pushl   %eax
        pushl   $.LC0
        call    printf
        addl    $32, %esp
        leal    -5(%ebp), %eax
        addl    $12, %eax
        movl    %eax, -20(%ebp)
        movl    -20(%ebp), %edx
        movl    -20(%ebp), %eax
        movl    (%eax), %eax
        addl    $10, %eax
        movl    %eax, (%edx)
        leave
        ret
        .size   function, .-function
        .section        .rodata
.LC1:
        .string "%d\n"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        subl    $20, %esp
        movl    $0, -8(%ebp)
        subl    $4, %esp
        pushl   $3
        pushl   $2
        pushl   $1
        call    function
        addl    $16, %esp
        movl    $1, -8(%ebp)
        subl    $8, %esp
        pushl   -8(%ebp)
        pushl   $.LC1
        call    printf
        addl    $16, %esp
        movl    -4(%ebp), %ecx
        leave
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.1.2"
        .section        .note.GNU-stack,"",@progbits
Secondo i mie calcoli function dovrebbe allocare 4byte per ret, 10 byte per
buffer2 e 5 byte per buffer1, quindi 19byte in totale. Dato che il
compilatore garantisce l'allineamneto alla word, SP doverbbe essere
aumentato di 20 byte, e non di 40!!
Sommando 9byte (5 di buffer1 + 4 di SFP, che sono adiacenti) all'indirizzo
di buffer1 ottengo l'indirizzo dell EIP, ed infatti il codice (sul mio
`Linux slack 2.6.21.1-smp #2 SMP Sat May 5 22:00:00 CDT 2007 i686 prescott
i386 GNU/Linux`) funziona alla perfezione:
g4b0@slack:~/test/testC/bow$ ./ex3b.o
bf84ab34 - bf84ab39 - bf84ab43 - ffffffc0
0
Infatti lo stack č questo:
[12345][123456789A][12345][1234][1234]
 ret      buf2      buf1   SFP    EIP
La mia domanda č allora quella dell'inizio: Perchč il compilatore, con `subl   
$40, %Esp`, aumenta di 40byte lo stack pointer?
Scusate se sono stato prolisso, e scusate anche se non ho postato in
i.c.o.l.d, ma seguo di piů questo ng, diciamo che lo preferisco :)
 
-- 
g4b0, linux user n. 369000
http://gabo.homelinux.com

$40, %Esp`, aumenta di 40byte lo stack pointer?
La risposta piu' semplice e' che stai compilando per
compatibilita' a 64 bit... ma non e' cosi'. ;)
Intanto noto che l'allineamento alla DWORD (32 bit e non WORD)
non e' rispettato, in quanto i buffer da 5 e 10 byte non vengono
allocati nello stack con dimensioni di 8 e 12 byte.
Sono un po' arrugginito, ma facciamo un po' di calcoli. Nello
stack vengono allocate le variabili locali (10+5+4 = 19, che sono
i due buffer e il puntatore ret). Quindi c'e' la chiamata alla
printf che alloca 5 parametri e la call (24 byte). Dovremmo
quindi essere a 43 (24+19) di stack necessario alla funzione, ma
in realta' esp viene modificato 3 volte:
-40 all'entrata
-12 prima della chiamata alla printf
+32 dopo la chiamata
e i conti continuano a non tornare...
E' inoltre bizzarra l'operazione
addl    $12, %eax
all'istruzione
buffer1 + 9

 
 [... snip ...]
La cosa bizzarra è che compilando su un gcc 3.3.6 l'assembler cambia
completamente (anche se forse non è così strano :)), ma resta comunque non
coerente (almeno secondo me).
Un'altra questione che mi è sorta è la seguente:
Leggendo 'Smashing The Stack For Fun And Profit` di aleph1, sono giunto al
punto in cui parla del fatto che ciascun processo ha lo stack che inizia
allo stesso indirizzo virtuale.
[cit]
The problem we are faced when trying to overflow the buffer of another
program is trying to figure out at what address the buffer (and thus our
code) will be.  The answer is that for every program the stack will
start at the same address.  Most programs do not push more than a few
hundred or a few thousand bytes into the stack at any one time.  Therefore
by knowing where the stack starts we can try to guess where the buffer we
are trying to overflow will be. 
[/cit]
Questa affermazione non è più vera o mi sono preso un abbaglio? Da quel che
ho capito, anche se ho trovato pochissima documentazione (ho cercato male?)
i compilatori moderni modificano il base pointer iniziale proprio per
rendere più difficile lo sfruttamento dei buffer overflow..
Come faccio da un processo (del quale conosco l'indirizzo dello sp) a
conoscere (anche solo approssimativamente) dove sarà lo sp di un'altro
processo (sempre in termini di memoria virtuale)??
grazie


processo (sempre in termini di memoria virtuale)??
Lo cerchi con fatica. Comunque ti rammento che attacchi di buffer
overflow non hanno bisogno di sapere l'indirizzo dello stack, ma
sfruttano codice scritto male.
Ho trovato questo link di risorse:
http://community.corest.com/~juliano/

 sfruttano codice scritto male.
Però quando riscrivo l'istruction pointer come faccio a sapere verso quale
indirizzo di memoria farlo puntare? Ho notato che la base dello stack varia
anche di 4.000.000 di indirizzi da un esecuzione all'altra.. Hai per caso
qualche link dove si parli di buffer overflow in modo approfondito (in
particolar modo di questo argomento)?


particolar modo di questo argomento)?
Il link in fondo al mio ultimo messaggio non era la firma... ;)
Altro non so...

 Il link in fondo al mio ultimo messaggio non era la firma... ;)
Me lo ero perso :)
grazie, ci do un'occhiata
