论坛风格切换切换到宽版
  • 14484阅读
  • 17回复

深入剖析 Win32 可移植可执行文件格式(一) [复制链接]

上一主题 下一主题
离线大牛
 

发帖
3299
金钱
1760
威望
176
只看楼主 倒序阅读 0 发表于: 2010-08-15
— 本帖被 大牛 执行置顶操作(2010-08-15) —
                   深入剖析 Win32 可移植可执行文件格式  
                                  第一部分  

                               作者:Matt Pietrek  

                                        

    很久以前,我开始为Microsoft Systems Journal(现在的MSDN(R) Magazine)写文章,其中

有一篇名为“探索PE文件内幕——Win32可移植可执行文件格式之旅”的文章很受欢迎,大大超

出了我的意料。直到现在,我还听说有人(甚至在Microsoft)仍然在使用那篇文章,它依旧被

收录在MSDN Library中。不幸的是,文章的最大问题是它们是静止的。但是Win32(R)的世界在这些

年已经发生了很大的变化,因此那篇文章已经严重过时了。我要从本月开始用两部分系列的文章

来补救这种情况。  

      

    你可能想知道为什么要关注可执行文件的格式。答案永远是:操作系统的可执行文件格式和

数据结构展现了操作系统内部许多信息。通过理解 EXE和 DLL 的内部情况,你会发现你已经变成

你周围一个更优秀的程序员。  

      

    当然,通过阅读 Microsoft的 PECOFF 规范你可以获得许多我将要告诉你的内容。但是与大

多数规范一样,它更注重完整性而不是可读性。在本文中,我把精力集中于解释整个故事中最重

要的部分,同时填补那些并不适合出现在官方规范中的怎么样(How)以及为什么(Why)的问题。

另外,在本文中我还会讲到一些非常有用的内容,它们并未出现在任何 Microsoft官方文档中。  

    让我先举一些例子来说明自从1994年我写那篇文章以来有关可执行文件方面都发生了哪些

变化。由于16位 Windows(R)已经成为历史,因此没有必要再与Win16的 NE(New Executable)格

式相比较了。另一个已经脱离人们视野的是 Win32s(R)。在 Windows 3.1 上运行Win32 程序非常不

稳定是最令人讨厌的事。  

    回到当时,Windows 95(当时代号为“Chicago”)甚至还未发行。Windows NT(R)还是3.5

版。Microsoft 链接器还未进行非常有效地优化。值得一提的是当时已经在MIPS和 DEC Alpha

上实现了 Windows NT。  

    自从那篇文章以来都出现了什么新内容呢?64位Windows引进了它自己的变种的PE文件格

式。Windows CE 添加了许多的新型处理器。诸如 DLL延迟加载、节合并以及绑定之类的优化已

经铺天盖地。有许多新东西要加入到这个故事中。  

    让我们不要忘了 Microsoft(R) .NET。该把它放在什么位置呢?对于操作系统来说,.NET 可

执行文件只不过是普通的Win32 可执行文件。但是.NET 运行时能够识别出这些可执行文件中的

数据并把它作为元数据(metadata)和中间语言(Intermediate Language,IL),它们对.NET

来说非常重要。在本文中,我要敲开.NET 元数据结构的大门,但把对它全部光彩的彻底挖掘留

给下一篇文章。  

    如果Win32 世界中的所有这些加加减减还不足以成为我重新写那篇文章的理由的话,那么

我只有列出原来那篇文章中的一些令我害怕的错误了。例如我对线程局部存储(TLS)支持情况

的描述是错误的。同样,通篇我对日期/时间戳这个DWORD 的描述仅在太平洋时区才是精确的!  
   另外,有许多内容在当时是正确的,但现在已经不正确了。我说过.rdata 节并没有太大的

作用。今天,诚然是这样。我也说过.idata 节是可读/可写的节,但现在却有许多试图拦截 API

的人发现它在很多情况下都是不正确的。  

    伴随着在这篇文章中完全更新 PE文件格式的故事,我也对用于显示 PE文件内容的PEDUMP

程序进行了彻底修改。PEDUMP 现在可以在 x86和 IA-64 平台上编译和运行,并且能够转储32 位

和 64位PE 文件。最重要的是,PEDUMP的源代码可以从本文开头的链接处下载。这样,你就有

了一个用这里讲的概念和数据结构实际工作的例子。  

PE 文件格式概览  

    Microsoft引进了PE 文件格式,更经常被称为PE 格式,作为最初的 Win32规范的一部分。

然而PE 文件源自VAX/VMS上早期的通用目标文件格式(Common Object File Format,COFF)。

这是由于许多最初的Windows NT 开发团队的成员都来自数字设备公司(Digital Equipment  

Corporation,DEC)。这些开发者很自然就使用现有的代码以便快速开始新的Windows NT 平台。  

     之所以选择术语“可移植可执行”是打算要在所有支持的 CPU 上的所有版本的 Windows 上

使用相同的可执行文件格式。从大的方面来说,这个目标已经实现,因为Windows NT及其后继

操作系统、Windows 95 及其后继操作系统以及Windows CE 都使用相同的可执行文件格式。  

    Microsoft编译器生成的OBJ 文件也使用 COFF 格式。从COFF 格式的一些域使用的竟然是

八进制编码你就能知道它是多么老。COFF格式的OBJ 文件中有许多数据结构和枚举类型与PE 文

件相同,后面我会提到。  

     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 文件中的某个部分映射到地址空间

中。因此像IMAGE_NT_HEADERS(后面我会讲到)这样的数据结构在磁盘上和在内存中是一样的。

如果你知道如何在一个 PE文件中找到某些内容,你几乎可以确定当文件被加载进内存时可以找

到同样的信息。  

    注意到PE 文件并不是作为单一的内存映射文件被映射进内存的这一点非常重要。相反,

Windows 加载器查看PE 文件并确定文件中的哪些部分需要被映射。当映射进内存时,文件中的

高偏移相对于内存中的高地址。某项内容在磁盘文件中的偏移可能与它被加载进内存之后的偏移

不同,但是将磁盘文件中的偏移转换成内存偏移需要的所有信息都存在(见下图)。  
天为什么这么黑, 因为牛在天上飞。
牛为什么飞天上, 因为我在地上吹!
汉化 摄影 音响CAD→→清风工作室
离线baolijun

发帖
24
金钱
210
威望
21
只看该作者 1 发表于: 2010-09-01
我是菜鸟,进来学习的
离线luyigoog

发帖
8
金钱
70
威望
7
只看该作者 2 发表于: 2011-02-02
努力学习汉化技术中!
离线cndmad
发帖
3
金钱
30
威望
3
只看该作者 3 发表于: 2011-02-21
虚心向大虾学习
离线ooook
发帖
6
金钱
50
威望
5
只看该作者 4 发表于: 2011-02-22
感谢版主辛苦整理。












厦门团购网厦门设计公司
离线luanfeng
发帖
5
金钱
40
威望
4
只看该作者 5 发表于: 2011-02-23
学习一下。。。。
www.wdown.cn
离线lm36394

发帖
2
金钱
20
威望
2
只看该作者 6 发表于: 2011-03-08
学习一下
离线tlfeagle
发帖
4
金钱
60
威望
6
只看该作者 7 发表于: 2011-04-27
涉及到了系统底层的一些问题,有些反汇编的意味。
离线ZHOU1990

发帖
4
金钱
40
威望
4
只看该作者 8 发表于: 2011-05-02
不错 学习了
离线kakao
发帖
2
金钱
20
威望
2
只看该作者 9 发表于: 2011-09-05
学习了·
www.zzltyl.cn-www.zzltyl.com儿童玩具淘气堡模型设计