10

我正在反汇编一个可执行文件:

(gdb) disas main
Dump of assembler code for function main:
0x004012d0 <main+0>:    push   %ebp
0x004012d1 <main+1>:    mov    %esp,%ebp
...

每次内存地址都是一样的:0x004012d0.

内存地址不是由操作系统动态分配的吗?

更新

现在我看到它是虚拟空间,它可以在某些平台上随机化。

有人可以发布一个改变的 gdb 转储吗?

4

8 回答 8

3

这取决于操作系统。大多数情况下,二进制文件的地址保持不变。这对于利用内存操作错误(例如缓冲区溢出)很重要。Linux 下链接库的地址总是会因为 ASLR 而不同。在 Windows Vista 和 Windows 7 下,二进制文件的虚拟内存空间在每次执行时也是随机的,因此每次运行的函数地址都会不同。

于 2010-03-31T19:38:33.773 回答
3

我认为这里的问题(至少在 Linux 上)可能是 gdb 试图从文档中提供帮助:

设置禁用随机化

设置禁用随机化

此选项(在 gdb 中默认启用)将关闭已启动程序的虚拟地址空间的本机随机化。此选项对于多个调试会话很有用,以使执行具有更好的可重现性,并且内存地址可跨调试会话重用。

此功能仅在 gnu/Linux 上实现。您可以使用相同的行为

         (gdb) set exec-wrapper setarch `uname -m` -R

http://sourceware.org/gdb/current/onlinedocs/gdb/Starting.html

更新:我现在已经检查过了,对我来说似乎确实如此(运行 Linux 2.6.28)。编译一个简单的 Hello World 程序并在没有命令行参数的情况下启动 gdb(我们不想在覆盖 disable-randomization 设置之前加载程序),然后输入:

(gdb) set disable-randomization off
(gdb) file ./a.out
(gdb) break main
(gdb) run
(gdb) disas printf

每次程序运行时printf的地址都不一样。

于 2010-03-31T20:59:51.470 回答
2

是和不是。物理内存由操作系统分配,只有操作系统知道您的程序在物理 RAM 中的位置。您的程序只看到虚拟地址,如果所有内容都以相同的顺序加载,虚拟地址将始终相同。

于 2010-03-31T19:37:08.757 回答
2

可执行重定位

一些可执行文件被设置为总是加载到相同的地址。有些设置为“可重新定位”。在 Visual Studio 链接器中控制此选项的选项称为 /FIXED。即使是这样的可执行文件也最常被加载到首选地址。较新的操作系统(Win7、Vista)随机化某些可执行文件的加载地址以提高安全性(在未知地址加载的攻击进程更难)——这称为ASLR。注意:即使是标记为 /FIXED:NO 的可执行文件也不假定适用于 ASLR。开发人员需要为可执行文件显式允许 ASLR 。

虚拟地址空间

注意:了解进程拥有整个地址空间很重要。多个进程拥有各自的地址空间,因此,如果您多次启动同一个可执行文件,则没有理由每次都无法在同一地址加载它。

于 2010-03-31T19:39:08.297 回答
1

那是一个虚拟地址。物理地址是操作系统已知的,但每个进程都有自己的虚拟地址空间。可重定位映像可能每次都获得相同的映射,尤其是主可执行文件。但不能保证。一个例子是 DLL。DLL 可能以不同的顺序加载,从而导致运行之间的虚拟地址不同,因为在加载 DLL 1 时,DLL 2 无法加载到该虚拟地址中,并且必须获取自己的地址。

于 2010-03-31T19:36:59.517 回答
0

这取决于操作系统。在大多数具有虚拟内存的现代操作系统中,可执行代码不需要可重定位,但在较旧的操作系统中,以及在一些专门的操作系统(例如实时、嵌入式)中,代码覆盖可以与位置无关代码一起使用代码和跳转表。在这种情况下,函数的地址可能会改变,例如,如果它的代码段被换出,然后在不同的地址换回。

于 2010-03-31T19:42:31.070 回答
0

这些是来自计算机安全的术语。过去它是固定地址(< 1996,根据LKML,但直到最近才开始将可执行文件编译为可重定位的,以实现ASLR。(但很久以前,所有库都被编译为可重定位的,所以如有必要,可以将库重新加载到不同的地址 - 读取动态重定位,但由于加载顺序,那些主要的系统调用 API 通常加载到固定地址。)即使在今天,

做一个 gdb /bin/ls 并跟随“运行”,你会发现默认地址没有改变:

(gdb) disassemble __open 函数打开的汇编代码转储: 0xb7f017f0 <+0>: cmpl $0x0,%gs:0xc 0xb7f017f8 <+8>: jne 0xb7f0181c

无论如何,ASLR 起源于PaX - 阅读 wiki,它涵盖了很多实现 ASLR 的要求。

为什么选择 ASLR?为了防止 2 种类型的攻击: http ://en.wikipedia.org/wiki/Return-to-libc_attack和http://en.wikipedia.org/wiki/Return-orienting_programming,因为这两种攻击都假定您的代码区域(如果已修复)在记忆中。

于 2011-10-13T15:22:03.667 回答
-3

为什么操作系统会选择不同的地址?

当操作系统执行一个进程时,它会将一个可执行文件加载到一个虚拟内存空间中。在此过程中,它将解析任何相对和/或符号引用。假设您拥有相同的可执行文件和相同的共享库,并以与上次相同的方式启动它,那么操作系统决定以不同的方式加载可执行文件将是非常奇怪的。

于 2010-03-31T19:36:02.217 回答