1 |
可移植可执行 (PE) 文件是一种 Windows 可执行格式。您可能已经将它们识别为 .exe、.dll 或其他扩展名。可执行文件不仅仅是源代码的总和,还有还有很多元信息告诉操作系统如何正确运行它。每个PE文件由几个部分组成,这些部分在下面概述并在本文中进行描述。深入研究不同的格式是一项宝贵的技能,学习 PE 和 ELF 文件会给你 当你想学习其他格式时,你会知道要寻找什么。请注意,这将是对于 win32 可移植可执行文件,但 64 位将不难掌握。 |
每个 PE 文件的第一部分是 DOS 头。之后还有 DOS 存根。这是为了确保向后兼容(你会在 Windows 中看到很多),以防万一 PE 文件在 MS-DOS 机器上运行。在 MS-DOS 上运行时,这将运行一个小自我包含 MS-DOS 程序,它输出说明 PE 程序不能在 DOS 模式下运行的文本。当可执行文件被链接时,链接器会添加一个默认存根程序。如果您希望覆盖默认的 DOS 存根,您可以使用 -STUB 链接器选项来实现。还要注意头结构的 e_lfanew 成员直接指向 PE 头的开头。
PE 头包含关于 PE 本身的信息,很像 DOS 头包含关于 DOS 存根的信息,以便它可以在 MS-DOS 上运行。同样类似,PE 文件以 PE 开头很像 DOS 标头总是可以用 MZ 识别。通常,PE 标头中最有价值的信息位于可选标头中,这可能会让您感到意外。为了真正深入研究,首先我们需要讨论 RVA,它代表相对虚拟地址。请记住,我们的可执行文件是加载到内存中运行的文件,分配了虚拟内存。如果你从一个对象中减去文件图像的基地址,你应该留下它的偏移量。另一种表述方式可能是,如果您知道偏移量,您可以从基地址计算到它的字节数。例如入口点地址这个可执行文件是0x13e6。如果它在 0x00400000 处加载到内存中,那么这个地址将在0x004013e6,如果它在 x01700000 处加载到内存中,它将在 0x017013e6 处。如果我们注意偏移量、对齐方式和大小,下面的几个字段允许我们计算围绕可执行文件的方式。
节表是节结构的数组,每个成员都是它自己的节。虽然这里有几个部分,但请注意,这完全有可能是一个部分数组。
1 |
有许多不同的节类型可以在 PE 的 MS 开发文档中查找 |