例子代码如下:
#include <stdio.h> #include <stdlib.h> void return_input() { char array[20]; gets(array); printf("%s\n", array); } int main(int argc, char **argv) { return_input(); }
gcc -fno-stack-protector -g overflow.c -o overflow
(gdb) list 4 void return_input() 5 { 6 char array[20]; 7 gets(array); 8 printf("%s\n", array); 9 } 10 11 int main(int argc, char **argv) 12 { 13 return_input(); (gdb) break 13 Breakpoint 1 at 0x8048428: file overflow.c, line 13. (gdb) run Starting program: /home/charles/overflow Breakpoint 1, main (argc=1, argv=0xbffff354) at overflow.c:13 13 return_input();观察汇编:
(gdb) disassemble Dump of assembler code for function main: 0x08048422 <+0>: push %ebp 0x08048423 <+1>: mov %esp,%ebp 0x08048425 <+3>: and $0xfffffff0,%esp => 0x08048428 <+6>: call 0x8048404 <return_input> 0x0804842d <+11>: leave 0x0804842e <+12>: ret End of assembler dump. (gdb) disassemble return_input Dump of assembler code for function return_input: 0x08048404 <+0>: push %ebp 0x08048405 <+1>: mov %esp,%ebp 0x08048407 <+3>: sub $0x38,%esp 0x0804840a <+6>: lea -0x1c(%ebp),%eax 0x0804840d <+9>: mov %eax,(%esp) 0x08048410 <+12>: call 0x8048310 <gets@plt> 0x08048415 <+17>: lea -0x1c(%ebp),%eax 0x08048418 <+20>: mov %eax,(%esp) 0x0804841b <+23>: call 0x8048320 <puts@plt> 0x08048420 <+28>: leave 0x08048421 <+29>: ret End of assembler dump.开始单步调试,观察sp的值:
(gdb) print /x $esp $1 = 0xbffff2b0 (gdb) print /x $eip $2 = 0x8048428 (gdb) stepi return_input () at overflow.c:5 5 { (gdb) print /x $esp $3 = 0xbffff2ac (gdb) x $esp 0xbffff2ac: 0x0804842d (gdb)
从return_input的汇编代码可以看到,这个函数的 stack frame 大小为 64字节,。
单步执行到 call gets的指令,再观察:
gdb) print /x &array $6 = 0xbffff28c (gdb) x $esp 0xbffff270: 0xbffff28c (gdb) x $eax 0xbffff28c: 0x08048451此时,eax指向了 array的首地址。 array可用的区域是28字节,加上末尾的栈上保存的 EBP和 返回地址,array刚好处于64字节的中点。
(gdb) x /32xw 0xbffff28c 0xbffff28c: 0x08048451 0xffffffff 0xb7e4e196 0xb7fc0ff4 0xbffff29c: 0xb7e4e225 0xb7fed280 0x00000000 0xbffff2b8 0xbffff2ac: 0x0804842d 0x08048430 0x00000000 0x00000000 0xbffff2bc: 0xb7e344d3 0x00000001 0xbffff354 0xbffff35c这个时候,如果输入 超过 28个字符,就会覆盖stack 上的 EBP和函数返回地址:
(gdb) next AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 8 printf("%s\n", array); (gdb) x /32xw 0xbffff28c 0xbffff28c: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff29c: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff2ac: 0x41414141 0x08048400 0x00000000 0x00000000 0xbffff2bc: 0xb7e344d3 0x00000001 0xbffff354 0xbffff35c 0xbffff2cc: 0xb7fdc858 0x00000000 0xbffff31c 0xbffff35c 0xbffff2dc: 0x00000000 0x0804822c 0xb7fc0ff4 0x00000000 0xbffff2ec: 0x00000000 0x00000000 0xa4ce7c3a 0x9da2d82a 0xbffff2fc: 0x00000000 0x00000000 0x00000000 0x00000001 (gdb)
(gdb) next 0x41414141 in ?? () (gdb) info registers eax 0x25 37 ecx 0xffffffff -1 edx 0xb7fc28b8 -1208211272 ebx 0xb7fc0ff4 -1208217612 esp 0xbffff2b0 0xbffff2b0 ebp 0x41414141 0x41414141 esi 0x0 0 edi 0x0 0 eip 0x41414141 0x41414141 eflags 0x286 [ PF SF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
(gdb) bt #0 0x41414141 in ?? () #1 0x08048400 in frame_dummy () Backtrace stopped: previous frame inner to this frame (corrupt stack?)