pe格式

来源:互联网 发布:2015年天猫销售数据 编辑:程序博客网 时间:2024/04/30 11:49

翻译:Jason Sun(笑笑生) QQ:58161330

2004年5月10日

[译注:仅供大家学习使用,您在复制或使用此文档时请保留这个文件头]

Peering Inside the PE: A Tour of the Win32 Portable Executable File Format
Matt Pietrek
1994 年3月
Matt Pietrek 是Windows Internals (Addison-Wesley, 1993)的作者。他就职于Nu-Mega 技术有限公司,可通过CompuServe: 71774,362联系到他。
这篇文章出自1994年3月发行的Microsoft系统期刊。版权所有﹫1994 Miller Freeman, Inc.保留所有权利。未经Miller Freeman同意,这篇文章的任何部分不得以任何形式被复制(除了在评论文章里以摘要引用)。

一个操作系统的可执行文件的格式在很多方面是这个操作系统的一面镜子。虽然学习一个可执行文件格式不是大多数程序员的首要任务,但是从中你可学到大量的知识。这篇文章中,
我将给出Microsoft为他们的基于Win32的系统所设计的PE文件格式的详细说明。可以预知在未来,PE文件格式在Microsoft的所有操作系统包括Windows 2000中都将扮演着很重要的角色。如果你在使用Win32s或WinNT,那么你已经在使用PE文件了。甚至你只是在Windows3.1下用Visual C++编程,你也已在使用PE文件了(Visual C++的32位DOS扩展组件使用此格式)。简而言之,PE格式已得到普遍应用并且在不短的将来也不会取消。现在是时间找出这种新的可执行文件格式为操作系统所带来的影响了。

我不会让你盯住无穷无尽的16进制Dumps和详细讨论页面中每个单独位的重要性。代替的,我将介绍PE文件格式中内含的概念并且把它们和你每天都会遇到的东西联系起来。例如,线程局部变量的概念,比如
declspec(thread) int i;
它使我快要发疯了,直到我明白它是怎样在可执行文件里优雅而简单的实现的。既然你们大多数都有使用16位Windows的背景,我将把Win32 PE文件格式的结构和与其等价的16位的NE文件格式联系起来。
除了一个不同的可执行文件格式之外, Microsoft还引入了一个由它的编译器和汇编器生成的新的目标模块格式。这个新的OBJ文件格式和PE格式有许多相同的东西。为了找到这个新的OBJ文件格式的文档我做了许多徒劳的搜索。所以我以自己的理解来解释它,并且除了PE格式之外我会在这里描述它其中的一部分。
大家都知道Windows NT继承了VAX® VMS® 和 UNIX®。许多Windows NT的创建者在进入Microsoft之前都在那些平台上进行设计和编码。当开始设计Windows NT时, 很自然的他们设法使用以前编写的并经过测试的工具以最小化项目启动时间。这些工具生成的并且与之一起工作的可执行文件和目标模块格式被叫做COFF(Common Object File Format的首字母缩写)。COFF格式自身是一个好的起点,但需要被扩展以满足一个现代操作系统如Windows NT或者Windows 95的所有需要。这个扩展的结果就是PE格式。它被称为“可移植”是因为Windows NT在不同的平台(x86, MIPS®, Alpha, 等等)上的所有实现都使用这个相同的可执行格式。当然,也有不同的地方比如CPU指令的二进制编码。重要的是操作系统加载器和程序设计工具不必为每种CPU完全重写。
Microsoft抛弃了现存的32位工具和文件格式的事实证明了他们想让Windows NT升级并且运行的更快的决心。为16位Windows编写的虚拟设备驱动使用一个不同的32位文件布局-LE 格式-它在Windows NT出现很早以前就存在了。比那更重要的是OBJ格式的改变。在Windows NT 的C编译器以前,所有的Microsoft编译器使用Intel OMF(Object Module Format)规范。以前提到,Microsoft的Win32编译器生成COFF格式的OBJ文件。一些Microsoft的竞争者例如Borland 和 Symantec 选择放弃 COFF 格式的 OBJs 而坚持使用 Intel OMF格式。结果导致生成OBJs或LIBs的公司为了使用不同的编译器就必须回去为不同的编译器发布他们产品的不同版本 (如果他们还没有那么做)。
PE格式在WINNT.H头文件中被文档化了。大约在WINNT.H文件的中间一个标题为“Image Format”的区域。这块区域的开头是我们熟悉的老的MS-DOS MZ格式和NE格式文件头接下来才是更新的PE格式的信息。WINNT.H 提供PE文件用到的原始数据结构的定义,但只包含了很少有用的以助于理解这些结构和标志的意思的注释。当使用WINNT.H编码时, 类似这样的表达式很常见:
pNTHeader->
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
要帮助逻辑地理解WINNT.H中的信息,可以阅读PE和COFF规范。
即刻转到COFF格式的OBJs文件的主题上来,WINNT.H头文件包括COFF格式的OBJ和LIB文件的structure定义和typedefs定义。不幸的是,我还没有找到上面提到的可执行文件格式的类似文档。既然PE文件和COFF OBJ文件是如此的相似,我决定是时候把这些文件拿出来,并且文档化。
阅读了PE文件由什么组成后,你自己也想Dump一些PE文件来看看这些概念。如果你使用Microsoft的工具进行基于Win32的开发,DUMPBIN程序可以分析并把PE文件和COFF OBJ/LIB文件输出为可读的形式。在所有的Dump工具中,DUMPBIN是容易的和最全面的。它甚至有一个极好的选项来反汇编它正在解析的文件的代码节(code sections)。Borland 用户可使用TDUMP查看PE可执行文件,但TDUMP不能解析COFF OBJ文件。这不是一个大的问题因为Borland编译器首先就不生成COFF格式的OBJs文件。
我写了一个PE和COFF OBJ文件的Dump程序,PEDUMP(见表1),我是想提供比DUMPBIN更可理解的输出。虽然它没有反汇编器也不能和LIB文件一起工作,但它在其它方面和DUMPBIN的功能是一样的,并且添加了一些新的特性以使它值得被认同。PEDUMP的源代码在任何MSJ电子公告板都可找到,因此我不把它在这儿全部列出。代替的,我将会列出一些PEDUMP输出的例子以举例说明我描述到的概念。