#include "stdio.h"
int shellcode()
{
int value = 0;
printf("%x\n", &value);
printf("Overflow Successful!\n");
/* __asm__(
"addl $0x24,%esp\n\t"
"popl %ecx\n\t"
"popl %ebp\n\t"
"leal -0x4(%ecx),%esp\n\t"
"ret"
);*/
return 0;
}
int test()
{
int i;
unsigned int stack[10];
printf("%x\n", &stack);
for (i = 0; i < 10; i++)
stack[i] = 0;
for (i = 0; i < 20; i++)
{
printf("Index = %d:%x\n", i,stack[i]);
}
stack[12] = 0x80483b1;
return 0;
}
int main()
{
int value = 0;
printf("%x\n", &value);
test();
printf("Overflow Failed\n");
return 0;
}
运行结果:
bfc1c130
bfc1c0dc
Index = 0:0
Index = 1:0
Index = 2:0
Index = 3:0
Index = 4:0
Index = 5:0
Index = 6:0
Index = 7:0
Index = 8:0
Index = 9:0
Index = 10:a
Index = 11:bfc1c138
Index = 12:804847d
Index = 13:8048560
Index = 14:bfc1c130
Index = 15:bfc1c128
Index = 16:80482c8
Index = 17:b7f0fff4
Index = 18:8049684
Index = 19:bfc1c148
bfc1c134
Overflow
下面我们来介绍为何是在 stack[12] 插入 0x80483b1:
micklongen@micklongen-desktop:~/桌面/overflow/初级缓冲溢出实验/系列1$ gdb overflow.o
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) disas main
Dump of assembler code for function main:
0x0804844d <main+0>: lea 0x4(%esp),%ecx
0x08048451 <main+4>: and $0xfffffff0,%esp
0x08048454 <main+7>: pushl -0x4(%ecx)
0x08048457 <main+10>: push %ebp
0x08048458 <main+11>: mov %esp,%ebp
0x0804845a <main+13>: push %ecx
0x0804845b <main+14>: sub $0x24,%esp
0x0804845e <main+17>: movl $0x0,-0x8(%ebp)
0x08048465 <main+24>: lea -0x8(%ebp),%eax
0x08048468 <main+27>: mov %eax,0x4(%esp)
0x0804846c <main+31>: movl $0x8048560,(%esp)
0x08048473 <main+38>: call 0x80482fc <printf@plt>
0x08048478 <main+43>: call 0x80483d7 <test>
0x0804847d <main+48>: movl $0x8048588,(%esp)
0x08048484 <main+55>: call 0x804830c <puts@plt>
0x08048489 <main+60>: mov $0x0,%eax
0x0804848e <main+65>: add $0x24,%esp
0x08048491 <main+68>: pop %ecx
0x08048492 <main+69>: pop %ebp
0x08048493 <main+70>: lea -0x4(%ecx),%esp
0x08048496 <main+73>: ret
End of assembler dump.
由反汇编代码可知call test的下一条指令的地址是 0x0804847d ,再看运行结果,可见 Index = 12:804847d ,即在stack[12]存放的是返回地址,这就是我们选这 stack[12] 的原因。
小结:
缓冲溢出原理其实就是内存操作。该程序能够在溢出的同时正常退出,主要原因是在内存操作方面做了一点手脚。我看过的一些缓冲溢出的文章在修改函数返回地址的同时都破坏了esp的值,这样往往在函数返回的时候会出现 段错误 。而在该程序中,仅仅修改了返回地址,并没有破快esp的值。
另外,看到一些朋友在实验的过程中,经常受困于gcc添加的一些关于缓冲溢出保护的语句的困扰。或许我们可以在C代码中添加嵌入式汇编语句,提早ret(个人想法,还未充分证明是否可行)以避开这些语句。
|