地址随机化:在C语言中打印静态变量的地址

5

我正在阅读一本操作系统教材,其中有一个示例可以验证系统是否支持虚拟地址,并且说以下程序每次都应该打印相同的结果。然而在我的MacBook Pro上,我看到了一些差异。

#include <stdio.h>

int var = 0;
int main(void)
{
  var += 1;
  printf("Address: %x, value: %d\n", &var, var);
  return 0;
}

当我运行它时,我看到地址在某些字节中发生了变化(但并非所有字节):
./main
Address: e8c6018, value: 1
./main
Address: 9032018, value: 1
./main
Address: 1bc7018, value: 1

当我在GDB中运行时,我总是看到1018:
(gdb) r
Starting program: /Users/xilan/temp/main
Address: 1018, value: 1
[Inferior 1 (process 19631) exited normally]
(gdb) r
Starting program: /Users/xilan/temp/main
Address: 1018, value: 1
[Inferior 1 (process 19636) exited normally]
(gdb) r
Starting program: /Users/xilan/temp/main
Address: 1018, value: 1
[Inferior 1 (process 19654) exited normally]

那么直接运行和在GDB中运行有什么不同?为什么直接运行时我看到的地址不同?


3
这本书已经过时了,它没有考虑到地址空间布局随机化(Address space layout randomization)这一技术。 - unwind
它确实提到了ASLR,那么我的系统是否会随机化静态变量的位置? - user2018791
在实现ASLR的层面上,我认为操作系统并不关心正在进入其创建映射的内存页面中的确切内容。一个“静态变量”基本上只是“可写内存中的某些东西”。 - unwind
@user2018791,静态变量是相对于操作系统加载可执行文件的地址而言的,所以如果操作系统将可执行文件加载在随机地址上,它也会影响到静态变量。 - Arash
我相信ASLR是作为虚拟内存映射的一部分应用的。物理地址(如bss、data等)将保持不变,但您将获得随机化的虚拟地址。 - Lundin
@user2018791 它不会随机化变量的位置。它会随机化整个程序加载时的位置。这就是为什么打印的地址在最后三位十六进制数字时不会改变的原因。 - Art
2个回答

2

你的书太旧了。如今许多操作系统都会随机分配程序和库的加载位置,以增加一些安全性来防范某些攻击。

MacOS 会在内存中随机分配程序的加载位置。但它会在 gdb 中禁用该随机化功能,这就是为什么在 gdb 中地址始终看起来相同的原因。


2
GDB 中,即使使用不同的进程运行,我们始终会得到相同的地址,但是如果直接在 Linux 中运行,则正常行为应该如下所示。
./main
Address: e8c6018, value: 1
./main
Address: 9032018, value: 1
./main
Address: 1bc7018, value: 1

这是因为在 GDB 中,默认情况下打开了 disable-randomization。如果我们希望获得正常的输出,它应该被关闭:

set disable-randomization off

参考链接:http://visualgdb.com/gdbreference/commands/set_disable-randomization


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接