【问题标题】:What parts of a PE file are mapped into memory by the MS loader?MS 加载器将 PE 文件的哪些部分映射到内存中?
【发布时间】:2016-08-31 14:09:58
【问题描述】:

MS 加载器将 PE 文件的哪些部分映射到内存中?

从 PE 文档中,我可以推断出 PE 可执行文件的典型格式(见下文)。

我知道,通过检查,PE 文件的所有内容,包括节头在内,都被映射到内存中,就像存储在磁盘上一样。

接下来会发生什么?

文件的其余部分是否也被映射(这里我指的是下图中的图像页面部分),以便整个文件在内存中就像存储在磁盘上一样,还是加载器比这更有选择性?

在文档中,我发现了以下 sn-p:

另一个例外是属性证书和调试信息 必须放在图像文件的最后,带有属性 紧接在调试部分之前的证书表,因为 loader 不会将这些映射到内存中。属性规则 证书和调试信息不​​适用于目标文件, 但是。

这就是我能找到的关于加载器行为的全部内容;它只是说这两个部分必须放在文件的最后,因为它们不会进入内存。

但是,如果加载器加载除了这两个部分之外的所有内容,并且我将 RVA 部分设置得足够高,那么部分数据实际上会在内存中复制(一次在映射文件中,一次在 RVA 指定的位置)?

如果可能,请链接到我可以进一步了解加载特定于 MS Windows 的地方。

【问题讨论】:

  • 注意加载和映射之间的区别:即使是一个巨大的 exe 在映射到内存时实际上也不必从磁盘读取。您可以映射一个大文件并将其按需分页到内存中。您的问题标题显示“已加载”,但您是在询问程序加载器如何映射它。
  • 已更正,谢谢。
  • 整个 PE 文件使用内存映射文件机制映射到内存中。随后的访问尝试会导致页面错误,从而触发加载。似乎您所询问的大部分内容都是您不应该依赖的实现细节。换句话说,故意无证。目前尚不清楚您要解决什么问题。 RVA 只是相对于文件内存映射位置的偏移量,所以我不明白内存中怎么会有任何重复。
  • @CodyGray - 我不是要解决问题。这只是兴趣。但是,如果您知道整个文件被映射到内存中,这是否意味着可以在内存中复制部分(一次用于文件映射,一次用于指定的 RVA)。另外,如果可能的话,你能否提供一个来源:-)?
  • @nlykkei: “部分可以在内存中复制(一次用于文件映射,一次用于指定的 RVA)” - 我不明白,你想做什么在这里说。但是不,不涉及重复。 “如果可能,您能否提供来源” - 如前所述,这些内容是“故意未记录的”。没有人编写文档的唯一目的是记录任何事物的无证性质。

标签: windows assembly x86 loader portable-executable


【解决方案1】:

查找此信息就像是在寻找彩蛋,因为当 COFF 描述使用 AT&T 术语时,MS 总是坚持使用自己的术语。

MS 加载器将 PE 文件的哪些部分映射到内存中?

这取决于。
节头覆盖的所有节都映射到运行时地址空间。
但是,RVA 为 0 的部分未映射,因此永远不会加载。

每个调试目录条目标识调试信息块的位置和大小。如果调试信息未被节头覆盖(即,它驻留在映像文件中并且未映射到运行时地址空间),则指定的 RVA 可能为 0。如果它被映射,RVA 就是它的地址。

内存包含磁盘上文件的精确副本。
请注意,可执行文件和 dll 被映射到虚拟内存,而不是物理内存!
当您访问它的可执行部分时,它会根据需要交换到 RAM 中。

如果一个部分没有被访问,那么它显然不会被交换到物理 RAM,但是它仍然被映射到虚拟内存中。

您可以阅读您可能想知道的所有内容about PE files (and more) on MSDN

您的报价来自documentation of the COFF file format
关键部分是:

属性证书和调试信息的规则不适用于目标文件。

发件人:https://support.microsoft.com/en-us/kb/121460

Size:可选标头的大小,包含在可执行文件中,但不包含在目标文件中。目标文件的值应为 0。

Ergo:可执行文件或非目标文件,它们是图像文件。
因此,该规则的例外不适用于他们。

【讨论】:

  • “当将页面交换到 RAM 时,操作系统也会修复重定位。” - 这是不正确的。如果模块无法在其首选加载地址加载,则所有重定位都在加载时完成。在此过程中更改的内存页面不再与磁盘上模块的内容匹配,并且需要被调出(而不是被丢弃)以防操作系统需要更多物理内存。当内存被分页时不会执行重定位(它在加载时已经完成,或者没有必要)。
  • @IInspectable,在 Win10 中,重定位是按照描述的 JIT 方式完成的,因为 ASLR 强制重定位。
  • ASLR 不会改变任何东西。它在加载时应用,因此在映射图像时重定位仍然是固定的。进程运行时地址不会动态变化!
  • PECOFF 文件有两种,都使用相同的基本数据结构但具有不同的约束条件,目标文件和图像文件。目标文件是链接器的输入,图像文件(可执行文件和 DLL)是链接器的输出。 PECOFF 规范在定义目标文件是什么时清楚地说明了这一点:“作为输入给链接器的文件。链接器生成一个图像文件,该文件又用作加载程序的输入。”对于像可执行文件这样的映像文件,调试和证书信息必须位于文件末尾,并且不会映射到内存中。
  • @Johan:正如您链接到的文章所解释的,JIT 修复仅适用于内核模式映像使用的动态重定位。对于用户模式 ​​PE 映像,重定位仍然由加载程序完成,加载程序在加载 EXE/DLL 映像的进程的地址空间中以用户模式运行。那时,进程基数已经确定,显然加载器需要接触包含正在重定位的内存引用的页面。这也意味着您的陈述“内存包含磁盘上文件的精确副本”是不正确的。
猜你喜欢
  • 1970-01-01
  • 2014-02-19
  • 1970-01-01
  • 1970-01-01
  • 2015-09-15
  • 2011-03-26
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
相关资源
最近更新 更多