0

我试图了解堆栈损坏时会发生什么。这是我试图理解的示例程序。我已将缓冲区的大小定义为 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
4

3 回答 3

2

当CPU进入一个函数时,它需要将一些值推入内存堆栈。根据你的代码,在调用'strcpy'之前,堆栈帧在x86系统上是这样显示的。

------------  offset 13
char buffer[1]
------------  offset 12
char *argv[]
------------  offset 8
int argc
------------  offset 4
ret
------------  offset 0

所以在你写了13bytes之后,strcpy已经重写了ret区。当主要完成时,它已损坏。

于 2013-04-01T03:27:17.500 回答
1

堆栈在英特尔处理器上向下增长。并且变量被放置在堆栈上。在函数调用之后,ABI(应用程序二进制接口)也可能占用几个字节来存储帧指针、变量块指针以及它想要的任何其他内容。你可以在你的程序集中看到它在开始时推动 ebp。

那么为什么你只在第 13 个字节之后才看到堆栈损坏呢?好吧,1 个字节是可以的,因为你有 1 个字节的内存。接下来的 12 个没问题,因为 ABI 将其他变量推入了那个房间。由于覆盖它,您可能会得到奇怪的结果,但您不会崩溃。然后进入下一个变量,即返回地址。覆盖它,你几乎肯定会崩溃(缺乏非凡的运气)。

于 2013-04-01T03:22:15.433 回答
1

最重要的是 - 当您经过第一个字节时,堆栈已损坏。:) 但我离题了。

在调用 main 之前,堆栈可能已将以下内容推送到它上面。

此函数的返回地址为 4 个字节。

“argc”为 4 个字节

“argv”为 4 个字节。

“缓冲区”为 1 个字节,但编译器可能将其对齐在 4 字节边界上

所以栈的前 12 个字节都是变量。一旦在偏移量 12 或 13 左右破坏了返回地址,您就会使程序处于错误状态,并且在尝试从该调用返回时可能会崩溃。

于 2013-04-01T03:24:19.220 回答