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