Chinaunix首页 | 论坛 | 博客
  • 博客访问: 197326
  • 博文数量: 77
  • 博客积分: 1749
  • 博客等级: 上尉
  • 技术积分: 810
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-28 18:27
文章分类
文章存档

2012年(28)

2011年(49)

分类: WINDOWS

2012-10-13 21:09:27

zz: 深入剖析 Win32 可移植可执行文件格式 by Matt Pietrek

64 位 Windows 需要做的只是修改 PE 格式的少数几个域。这种新的格式被称为 PE32+。它并没有增加任何新域,
仅从 PE 格式中删除了一个域。其余的改变就是简单地把某些域从 32 位扩展到 64 位。在大部分情况下,你都能写出同时适用于 32 位和 64 位 PE 文件的代码。Windows 头文件有这种魔力可以使这些区别对于大多数基于 C++的代码都不可见。

EXE 文件与 DLL 文件的区别完全是语义上的。它们使用的是相同的 PE 格式。惟一的不同在于一个位,这个位用来指示文件应该作为 EXE 还是 DLL。甚至 DLL 文件的扩展名也完全也是人为的。你可以给 DLL 一个完全不同的扩展名,例如.OCX 控件和控制面板小程序(.CPL)都是 DLL。

PE 文件一个非常好的地方就是它的数据结构在磁盘上与在内存中一样。加载一个可执行文件到内存(例如通过调用 LoadLibrary 函数)主要就是把 PE 文件中的某个部分映射到地址空间中。数据结构在磁盘上和在内存中是一样的。
如果你知道如何在一个 PE 文件中找到某些内容,你几乎可以确定当文件被加载进内存时可以找到同样的信息。

注意到 PE 文件并不是作为单一的内存映射文件被映射进内存的。Windows 加载器查看 PE 文件并确定文件中的哪些部分需要被映射。当映射进内存时,文件中的高偏移相对于内存中的高地址。
某项内容在磁盘文件中的偏移可能与它被加载进内存之后的偏移不同,但是将磁盘文件中的偏移转换成内存偏移需要的所有信息都存在。

当 PE 文件由 Windows 加载器加载进内存时,它在内存中被称为模块(module)。文件被映射到的内存的起始地址被称为 HMODULE。这是需要记住的一点:给你一个 HMODULE,你就知道在那个地址处到底有什么样的数据结构,并且你可以根据 PE 文件的知识找到内存中所有其它的数据结构。这个强大的功能可以被用作其它用途,例如拦截 API。

内存中的模块代表一个进程所需的可执行文件中的所有代码、数据和资源。PE 文件中的其它部分可能会被读取,但并不被映射进内存(例如重定位节)。一些部分可能根本就不被映射,例如放在文件末尾的调试信息。PE 文件头中的一个域告诉系统将这个可执行文件映射进内存时需要占用多少内存。不被映射的数据放在文件末尾,位于所有需要被映射的部分之后。描述 PE 文件(和 COFF 文件)的关键位置是 WINNT.H 文件。在这个头文件中,你能找到几乎
所有结构的定义、枚举类型以及使用 PE 文件或它在内存中的等价结构所需的定义。当然在其他地方有这方面的文档,例如 MSDN 中有“Microsoft 可移植可执行文件和通用目标文件格式文件规范”(2001 年十月 MSDN 的 Specifications 下)。但是 WINNT.H 确定了 PE 文件最终的样子。

有许多工具可以用来查看PE文件。Visual Studio附带的Dumpbin和Platform SDK附带的Depends就是其中的两个。
我特别喜欢Depends,它以一种非常简洁的方式查看文件的导入表和导出表。另一个很好的PE文件查看工具是由Smidgeonsoft()发行的PEBrowse Professional。本文中包含的PEDUMP程序也是一个非常全面的工具,几乎能做Dumpbin所能做到的一切。

从 API 的观点来看,Microsoft 提供的读取和修改 PE 文件的主要途径是 IMAGEHLP.DLL 文件。

在开始看 PE 文件的细节之前,先复习一下贯穿于整个 PE 文件方面的几个基本概念是非常值得的。在以下的部分中,我将讨论 PE 文件的节(section)、相对虚拟地址(RVA)、数据目录(Data Directory)以及如何导入函数。





阅读(1453) | 评论(0) | 转发(0) |
0

上一篇:recursive

下一篇:【Backup】Software testing

给主人留下些什么吧!~~