我正在尝试了解堆栈损坏时会发生什么。这是我试图理解的示例程序。我已将缓冲区的大小定义为1个字节。但是在我输入第13个字节后发生堆栈损坏。为什么在第13个字节后被破坏?
C代码:
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[]){
char buffer[1];
strcpy(buffer,argv[1]);
printf("\n buffer : %s \n",buffer);
return 0;
}
汇编代码:
.file "buffer_overflow.c"
.section .rodata
.LC0:
.string "\n buffer : %s \n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl 12(%ebp), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, 4(%esp)
leal 31(%esp), %eax
movl %eax, (%esp)
call strcpy
movl $.LC0, %eax
leal 31(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
答案 0 :(得分:1)
堆栈在英特尔处理器上向下增长。变量放在堆栈上。在函数调用之后,ABI(应用程序二进制接口)也可能占用几个字节来存储诸如帧指针,指向变量块的指针以及它所需的任何其他内容。你可以在程序集中看到它在开头推动ebp。
那你为什么只在第13个字节后看到堆栈损坏?好吧,1个字节是可以的,因为你有1个字节的内存。接下来的12个是好的,因为ABI将其他变量推入该房间。由于覆盖它可能会有奇怪的结果,但你不会崩溃。然后你进入下一个变量,即返回地址。覆盖它,你几乎肯定会崩溃(没有非凡的运气)。
答案 1 :(得分:1)
最重要的 - 当你超过第一个字节时,堆栈已损坏。 :)但我离题了。
在主要被调用之前,堆栈可能会被推到它上面。
此函数的返回地址为4个字节。
“argc”的4个字节
“argv”的4个字节。
“缓冲区”的1个字节,但编译器可能在4字节边界上对齐
所以堆栈的前12个字节都是变量。一旦你破坏了返回地址,在偏移12或13附近,你就把程序置于错误的状态,并且在试图从这个调用返回时可能会崩溃。
答案 2 :(得分:1)
当CPU进入一个函数时,需要将一些值推入内存堆栈。根据你的代码,在调用'strcpy'之前,堆栈框架在x86系统上显示如下。
------------ offset 13
char buffer[1]
------------ offset 12
char *argv[]
------------ offset 8
int argc
------------ offset 4
ret
------------ offset 0
因此,在您编写了13bytes之后,strcpy
重写了ret区域。当主要完成时,它已被破坏。