Stack Smashing



  • Nabend zusammen!

    Ich beschäftige mich momentan mit dem berühmten "How to smash the stack for fun and profit" Artikel aus dem Phrack Magazine (Issue 49).
    (falls jmd noch den Hintergrund interessiert: http://pulltheplug.org/wargames/vortex/level01.html )

    Nun gut, ich versuche Beispiel 3 nachzuvollziehen:

    void function(int a, int b, int c) {
       char buffer1[5];	// 8 byte im stack (DW)
       char buffer2[10];	// 12 byte im stack
       int *ret;
    
       ret = buffer1 + 12;	// ende von buffer1 + 4 byte FP
       (*ret) += 8;		// return-adresse um 8 erhöhen
    }
    
    int main() {
      int x;
    
      x = 0;
      function(1,2,3);
      x = 1;		// diese anweisung überspringen (8 byte)
      printf("%d\n",x);
    }
    

    Die Kommentare sind von mir.

    Nun sollte ich nach dem Artikel folgendes disassemblat vom gdb bekommen (disassemble main):

    Dump of assembler code for function main:
    0x8000490 <main>:       pushl  %ebp		; ebp retten,
    0x8000491 <main+1>:     movl   %esp,%ebp	
    0x8000493 <main+3>:     subl   $0x4,%esp	; 4 byte stack?
    0x8000496 <main+6>:     movl   $0x0,0xfffffffc(%ebp)	; x = 0; scheiß at&t-syntax!
    0x800049d <main+13>:    pushl  $0x3		; params pushen
    0x800049f <main+15>:    pushl  $0x2
    0x80004a1 <main+17>:    pushl  $0x1
    0x80004a3 <main+19>:    call   0x8000470 <function> 
    0x80004a8 <main+24>:    addl   $0xc,%esp	; 12 zu esp addieren? sind das die 3 params? (3 * DW)
    0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp) ; x = 1? wer soll sowas lesen können? 0xfffffffc(%ebp)??
    0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax ; x als param nach eax,
    0x80004b5 <main+37>:    pushl  %eax		; param für printf pushen
    0x80004b6 <main+38>:    pushl  $0x80004f8	; was ist das?
    0x80004bb <main+43>:    call   0x8000378 <printf> 
    0x80004c0 <main+48>:    addl   $0x8,%esp        ; aufräumarbeiten?
    0x80004c3 <main+51>:    movl   %ebp,%esp
    0x80004c5 <main+53>:    popl   %ebp
    0x80004c6 <main+54>:    ret
    0x80004c7 <main+55>:    nop
    

    (Kommentare wieder von mir)

    Da werfen sich für mich schon ein paar Fragen auf.
    - Ich finde "movl $0x0,0xfffffffc(%ebp)" furchtbar kryptisch zu lesen. Was wäre "0xfffffffc(%ebp)" nach der Intel-Syntax?
    - Was macht die Zeile:
    0x80004a8 <main+24>: addl $0xc,%esp
    12 auf den stackpointer addieren? Warum? Wegen meinen 3 int-params? (int ist doch doubleword groß)
    - Woher berechnen sich die 8 byte die ich überspringen will in:

    (*ret) += 8;		// return-adresse um 8 erhöhen
    

    Ist das 0x80004b2 - 0x80004a8?? Da komm ich aber auf 10 (resp. A).

    Nunja... das eigentliche Problem ist allerdings, dass es nicht funktioniert.
    Ich erhalte folgendes Disassemblat:

    Dump of assembler code for function main:
    0x0804840e <main+0>:    lea    0x4(%esp),%ecx     ; was
    0x08048412 <main+4>:    and    $0xfffffff0,%esp   ; ist
    0x08048415 <main+7>:    pushl  0xfffffffc(%ecx)   ; das???
    0x08048418 <main+10>:   push   %ebp               ; bp retten, usw
    0x08048419 <main+11>:   mov    %esp,%ebp
    0x0804841b <main+13>:   push   %ecx
    0x0804841c <main+14>:   sub    $0x24,%esp         ; oh, krieg ich 24byte stack?
    0x0804841f <main+17>:   movl   $0x0,0xfffffff8(%ebp) ; x = 0;
    0x08048426 <main+24>:   movl   $0x3,0x8(%esp)     ; parameter übergeben. pushl ist anscheinend out :(
    0x0804842e <main+32>:   movl   $0x2,0x4(%esp)     ; kann doch kein mensch lesen
    0x08048436 <main+40>:   movl   $0x1,(%esp)
    0x0804843d <main+47>:   call   0x80483d4 <function>
    0x08048442 <main+52>:   movl   $0x1,0xfffffff8(%ebp) ; x = 1;
    0x08048449 <main+59>:   mov    0xfffffff8(%ebp),%eax ; x nach eax
    0x0804844c <main+62>:   mov    %eax,0x4(%esp)        ; eax auf den stack
    0x08048450 <main+66>:   movl   $0x804853c,(%esp)     ; was auch immer das ist? ret-adresse? müsste das nicht 0x0804845c sein?
    0x08048457 <main+73>:   call   0x8048308 <printf@plt>
    0x0804845c <main+78>:   add    $0x24,%esp         ; was auch immer jetzt wieder kommt?
    0x0804845f <main+81>:   pop    %ecx
    0x08048460 <main+82>:   pop    %ebp
    0x08048461 <main+83>:   lea    0xfffffffc(%ecx),%esp
    0x08048464 <main+86>:   ret    
    End of assembler dump.
    

    Leider verstehe ich den asm-dump wesentlich schlechter.
    Hier stellt sich aber schon meine Hauptfrage. Warum gehts nicht?
    Wie sieht mein Stack jetzt aus?
    Nach dem Beispiel hätte er folgendermaßen sein sollen:

    bottom of                                                            top of
    memory                                                               memory
               buffer2       buffer1   sfp   ret   a     b     c
    <------   [            ][        ][    ][    ][    ][    ][    ]
    
    top of                                                            bottom of
    stack                                                                 stack
    

    (jedes leerzeichen steht daei für ein byte)

    Vielleicht kann mir ja jmd auf die Sprünge helfen.

    Besten Dank

    Ike



  • Was du da machst, läuft knapp an den Grenzen der Legalität vorbei. Das hat nichts mehr mit ANSI-C zu tun, sondern nutzt die Art aus, wie ein ganz bestimmter Compiler den Callstack organisiert. Und damit lässt sich die Hauptfrage gleich beantworten:

    Ike schrieb:

    Hier stellt sich aber schon meine Hauptfrage. Warum gehts nicht?

    Vermutlich weil dein Compiler anders arbeitet als der, den der Autor verwendet hat 😉


Anmelden zum Antworten