为什么每次运行时函数的地址都会改变?

时间:2013-04-25 12:16:15

标签: c++ function-pointers

我正在努力将地址映射到符号以进行调试(获取callstack)。 MS dbghelp.dll可以通过地址告知符号(请参阅SymFromAddrMSDN)。但是,它不起作用,我想知道这是如何工作的,因为地址似乎随着程序的每次运行而改变:

#include <iostream>
void Foo() {}

int _tmain(int argc, _TCHAR* argv[])
{
    const long unsigned int addr = reinterpret_cast<long unsigned int>(&Foo);
    std::cout << "Address: " << std::hex << addr << std::endl;
    return 0;
}

输出:

D:\dev\Sandbox\Debug>Sandbox.exe
Address: 901320
D:\dev\Sandbox\Debug>Sandbox.exe
Address: ce1320
D:\dev\Sandbox\Debug>Sandbox.exe
Address: 3a1320
D:\dev\Sandbox\Debug>Sandbox.exe
Address: 3f1320

一个不同的程序如何从堆栈跟踪中读取地址并将其映射到函数?这对我来说听起来很神奇。我没有在链接文档中找到任何内容,说我必须从地址或其他内容中减去一些东西。

在我的理解中,因为我们克服了实模式,所以每个进程都有一个虚拟内存空间,所以不需要再为掷骰子加载地址了。我会理解DLL的绝对地址的不确定性,但不是主要的可执行文件。

使用VS2008在Win7上尝试。

4 个答案:

答案 0 :(得分:6)

答案 1 :(得分:3)

因为您的代码被编译为使用地址空间布局随机化,这使得代码不易受到“StackOverflows”攻击。

如果你真的想改变它,那就有linker option

答案 2 :(得分:3)

有一个security feature that randomises some addresses,因此潜在的攻击者无法利用已知的固定相对位置。

答案 3 :(得分:2)

正如其他人已经提到的那样ASLR正在行动中。

看起来您需要做的是在调用SymLoadModuleEx()时指定可执行文件的图像库。这是BaseOfDll参数。

我不知道它在崩溃转储中存储的确切位置(如果这是其他程序必须使用的东西),但正在运行的程序可以使用GetModuleHandle()获取自己的图像基地址(讨论{ {3}})。

您可能希望保存加载到进程中的所有DLL的名称和基址,而不仅仅是EXE本身的名称和基址。