什么叫缓冲区溢出( 二 )


下面举个例子:
example1.c:
------------------------------------------------------------
voidfunction(inta,intb,intc){
charbuffer1[5];
charbuffer2[10];
}
voidmain(){
function(1,2,3);
}
-----------------------------------------------------------
为了理解程序是怎样调用函数function()的,使用-S选项,在Linux下,用gcc进行编译,产生汇编代码输出:
$gcc-S-oexample1.sexample1.c
看看输出文件中调用函数的那部分:
pushl$3
pushl$2
pushl$1
callfunction
这就将3个参数压到堆栈里了,并调用function() 。指令call会将指令指针IP压入堆栈 。在返回时,RET要用到这个保存的IP 。在函数中,第一要做的事是进行一些必要的处理 。每个函数都必须有这些过程:
pushl%ebp
movl%esp,%ebp
subl$20,%esp
这几条指令将EBP,基址指针放入堆栈 。然后将当前SP拷贝到EBP 。然后,为本地变量分配空间,并将它们的大小从SP里减掉 。由于内存分配是以字为单位的,因此,这里的buffer1用了8字节(2个字,一个字4字节) 。Buffer2用了12字节(3个字) 。所以这里将ESP减了20 。这样,现在,堆栈看起来应该是这样的 。
低端内存高端内存
buffer2buffer1sfpretabc
<------[][][][][][][]
栈顶栈底
缓冲区溢出就是在一个缓冲区里写入过多的数据 。那怎样利用呢,看
一下下面程序:
example2.c
-----------------------------------------------------------
voidfunction(char*str){
charbuffer[16];
strcpy(buffer,str);
}
voidmain(){
charlarge_string[256];
inti;
for(i=0;i<255;i++)
large_string[i]='A';
function(large_string);
}
------------------------------------------------------------
这个程序是一个经典的缓冲区溢出编码错误 。函数将一个字符串不经过边界检查,拷贝到另一内存区域 。当调用函数function()时,堆栈如下:
低内存端buffersfpret*str高内存端
<------[][][][]
栈顶栈底
很明显,程序执行的结果是"Segmentationfault(coredumped)"或类似的出错信息 。因为从buffer开始的256个字节都将被*str的内容'A'覆盖,包括sfp,ret,甚至*str 。'A'的十六进值为0x41,所以函数的返回地址变成了0x41414141,这超出了程序的地址空间,所以出现段错误 。可见,缓冲区溢出允许我们改变一个函数的返回地址 。通过这种方式,可以改变程序的执行顺序 。
【什么叫缓冲区溢出】

推荐阅读