C - 堆上的缓冲区在 EXEC 后不会丢失,而是保存在堆栈上

标签 c pointers overflow heap-memory

我正在研究堆栈缓冲区溢出,我看到了一些让我思考的事情。首先,操作系统是Damn Vulnerable Linux,内核2.6.20并且禁用ASLR

事实是,我知道当您在 C 程序中调用 exec 函数时,堆和堆栈中的内存会被清零并丢失。但是,如果我在堆中分配一个缓冲区(malloc),然后将指向该缓冲区的指针作为参数传递给使用 exec 函数执行的程序,则缓冲区内(堆中)的数据将保存在堆栈上。因此,在执行结束时,我在堆栈中拥有缓冲区(之前位于堆中)。 为了更清楚地说明这一点,这里有一个例子:

Program: bingo

#include <stdlib.h>

int main(int argc,char* argv[]){
    int i;
    char *buffer=malloc(600);
    for (i=0;i<600;i++){
         buffer[i]='A';
    }
    buffer[600-1]=0;
    execl("./test","test",buffer,0);

    free(buffer);
    return 0;
}

测试将是一个简单的程序。

Program: test

#include <stdlib.h>

int main(int argc,char* argv[]){
    printf("Hello world\n");        

    return 0;
}

现在,如果我使用 GDB 调试 bingo 程序,我可以看到放入堆中的缓冲区内容(所有 As)实际上在 execl 函数期间复制到堆栈上。因此,在程序执行结束时,堆被清零,但缓冲区的内容已完全复制到堆栈上。我的解释是,发生这种情况是因为这样缓冲区的内容将可供执行的程序(测试)使用。我只是想知道这种行为是否正常。 我的疑问是:当我调用 execl 函数时,我实际上将一个指针作为参数传递给执行的程序(测试)。因为缓冲区是一个指针。所以我的(可能是愚蠢的)问题是:是否应该只将指针传递给执行的程序,而不应该将指针指向的内容传递给执行的程序?

谢谢

最佳答案

缓冲区复制到堆栈的原因是它作为参数传递,即 ./test 中的 argv[1]。 buffer 只是一个引用 bingo 中内存位置的变量。当进程发生时,堆分配不会持续存在 退出。

注意:假设缓冲区引用宾果进程内存中的0xfff123。这是一个虚拟(特定于进程)地址。 0xffff123 甚至可能无法映射到 ./test。因此,传递一个指向 0xfff123 的指针并不能保证达到您的预期。

成功调用 execl 后,bingo 将在此时退出,并且与该进程关联的所有内存都会丢失,并且 free(buffer) 永远不会执行。

答案:不会。进程堆分配不会跨进程持续存在。共享内存对象是内核持久的,malloc 调用的结果不是。

我不确定您的所有困惑都在哪里,但这是我最好的猜测。

相对寻址示例:

所有进程都有一个0x00000000(32 位)地址。如果内核将每个进程映射到相同的物理地址,则每个进程将共享0x0000000 这在物理上不可能发生。内核将虚拟地址(0x0000000)更改为真实物理地址,例如0x3535fffa。因此,我的进程中的指针“瞄准”0x00000000 虚拟,但这实际上是 0x3535fffa

这意味着您不能直接在进程之间传递堆指针。这是行不通的。我指向 0x3535fffa 的指针将是与您的 0x3535fffa 用来引用的物理地址不同的物理地址。

execl 只是将 AAAAA 复制到 ./test 内存中的新缓冲区中,如您所见。

关于C - 堆上的缓冲区在 EXEC 后不会丢失,而是保存在堆栈上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19228794/

相关文章:

c - C 中的数组大小错误

c++ - 指针数组和按引用调用

html - CSS:溢出:隐藏删除边框底部?

C UDP组播接收包丢失

c - 在头文件中声明数组

c - 如何在 C 中使用指针传递信息

pcap_loop 的最后一个参数中的编译器警告。指向不同大小的整数

c - 读取纺织品并添加到 C 中的链接列表

Clojure - 重置!原子导致堆栈溢出

CSS 溢出-y : auto does not reach the bottom of div