-1

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

事实是,我知道当您在 C 程序中调用 exec 函数时,堆和堆栈中的内存会被清零并丢失。但是,如果我在堆(malloc)中分配一个缓冲区,然后将指向该缓冲区的指针作为参数传递给使用 exec 函数执行的程序,则缓冲区(在堆中)内的数据将保存在堆栈中。所以在 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 调试宾果程序,我可以看到放入堆中的缓冲区(所有 As)的内容实际上在 execl 函数期间被复制到堆栈上。因此,在程序执行结束时,堆归零,但缓冲区的内容已完全复制到堆栈上。我的解释是发生这种情况是因为这样缓冲区的内容将可用于执行的程序(测试)。我只是想知道这种行为是否正常。我的疑问是:当我调用 execl 函数时,我实际上将指针作为参数传递给执行的程序(测试)。因为缓冲区是一个指针。所以我的(可能是愚蠢的)问题是:不应该只将指针传递给执行的程序,而不是指针指向的内容?

谢谢

4

1 回答 1

3

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

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

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

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

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

相对寻址示例:

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

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

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

于 2013-10-07T16:13:55.953 回答