3

我最近一直在研究 Window 的 PE 格式,我注意到在大多数示例中,人们倾向于将ImageBase偏移值设置optional header为不合理的高值,例如0x400000.

什么会使将图像映射到 offset不利0x0

4

4 回答 4

3

首先,这不是 Windows 或 PE 文件格式的默认设置,它是链接器的 /BASE 选项在您使用它链接 EXE 时的默认设置。DLL 的默认值为 0x10000000。

选择 /BASE:0 将是一个糟糕的选择,没有程序可以在该基地址上运行。地址空间的前 64 KB 被保留,永远不能被映射。主要是为了捕获空指针取消引用错误。并扩展到 64KB 以捕获以 16 位开始并重新编译为 32 位的程序中的指针错误。

为什么 0x40000 而不是 0x10000 是默认值也是一个历史事故,至少可以追溯到 Windows 95。它为“16 位/MS-DOS 兼容性竞技场”保留了前 4 兆字节的地址空间。我不太记得了,Windows 9x 的 16 位 VM 实现与 NT 非常不同。您可以在这篇古老的知识库文章中阅读更多相关信息。现在它肯定不再重要了,64 位操作系统很容易在 0x010000 和 0x400000 之间的空间中分配堆内存。

更改 EXE 的 /BASE 选项没有任何意义。但是,为 DLL 更改它有很多意义。如果它们不重叠,则它们会更有效,因此不必重新定位,它们不会占用页面文件中的任何空间并且可以在进程之间共享。甚至还有一个 SDK 工具,所以你可以在构建后更改它,rebase.exe

于 2012-08-06T19:44:29.633 回答
2

实际上,将 /BASE 设置为 0 的影响取决于图像的地址空间布局随机化 (ASLR)设置(也由链接器放置 - /DYNAMICBASE:NO)。

如果您的图像有 /BASE:0 并且 ASLR 处于打开状态 (/DYNAMICBASE:YES),那么您的图像将启动并运行,因为加载程序会自动将其加载到“有效”地址。

如果您的图像具有 /BASE:0 并且 ASLR 已关闭 (/DYNAMICBASE:NO),那么您的图像将不会启动,因为加载程序不会将其加载到所需的基地址(如上所述,这是无效/保留的)。

于 2012-08-09T08:43:41.937 回答
1

如果将其映射到地址 0,则这意味着代码期望从地址 0 开始运行。

对于操作系统,地址零是NULL,这是一个无效地址。
(不是“从根本上”,但对于现代操作系统来说,它是。)

此外,出于多种原因,一般而言,您不希望在较低的 16 MiB 内存(甚至是虚拟内存)中存在任何内容。

但是有什么选择呢?它必须被映射到某个地方,所以他们选择了0x400000......可能没有特别的理由来指定那个特定的地址。它可能只是方便。

于 2012-08-06T18:43:09.950 回答
1

Microsoft 选择该地址作为链接器指定的默认起始地址,PE 文件将在该地址进行内存映射。链接器假定该地址,并且可以使用该假定优化可执行文件。当文件在该地址被内存映射时,代码可以在不需要修改任何内部偏移量的情况下运行。

如果由于某种原因无法将文件加载到该位置(另一个 exe/dll 已加载到该位置),则需要在可执行文件运行之前进行重定位,这将增加加载时间。

较低的内存地址通常被假定为包含低级系统例程,并且通常被单独保留。ImageBase 地址唯一真正的要求是它是 0x10000 的倍数。

推荐阅读:

于 2012-08-06T18:54:17.147 回答