C++ 为什么每次执行时函数的地址不同?

C++ 为什么每次执行时函数的地址不同?,c++,c,C++,C,可执行代码的地址是在链接时决定的,不是吗 #include <stdio.h> int main () { printf("%p", (void*)&main); return 0; } 示例输出#2: 这是一种安全技术,称为 它在每次执行时故意移动数据,使攻击者更难知道进程中的数据位并对其进行攻击。在许多现代系统上,它会在链接时确定函数相对于基址模块的地址。加载模块(exe、dll等)时,为其提供不同的基址 这是为了安全,这意味着函数的地址是不可预测的

可执行代码的地址是在链接时决定的,不是吗

#include <stdio.h>
int main ()
{
     printf("%p", (void*)&main);
     return 0;
}
示例输出#2:


这是一种安全技术,称为


它在每次执行时故意移动数据,使攻击者更难知道进程中的数据位并对其进行攻击。

在许多现代系统上,它会在链接时确定函数相对于基址模块的地址。加载模块(exe、dll等)时,为其提供不同的基址

这是为了安全,这意味着函数的地址是不可预测的。这意味着某些攻击(例如,可能使堆栈变量溢出以覆盖返回地址或使用其他函数(出于恶意目的)覆盖函数指针)无法轻松预测要用哪个地址覆盖它,运行时会有所不同

重新定位基址的功能还解决了冲突的实际问题,如果加载为同一基址独立编译的a.dll和b.dll,则不会工作,因此重新定位一个基址可以解决冲突

在机器代码级别,这很好,因为大多数跳转和调用使用相对指令偏移量,而不是绝对指令偏移量。尽管某些构造在加载模块时会动态修补,或者使用某种形式的“表”来填充正确的地址


另请参见

。严格来说,代码会引发UB,因为转换说明符仅用于
void
-指针(至少在C中)。因此,任何数字都可能被打印出来。@alk您当然可以在
printf()
中执行显式强制转换到(void*),然后它就不再是UB了。但任何数字都可能被打印出来。。。现在,这意味着什么?@ CTX:C++中仍然是UB。不能使用<代码>主< <代码>的地址。@ C++中的LeNNESS RESBESBA3.0,这是无可争辩的。直到我认为它是程序安装的真实地址?@truthseek这种方法只有在引入“位置独立可执行文件”(position independent executables)之后才起作用。使用标志
-no pie
,这将在固定位置加载主二进制文件,
main()
的地址将不再变化。
0x563ac3667139
0x55e3903a9139