顺便贴上这个, 以供参考。 :)
深度探索Win32可执行文件格式Win32
Matt Pietrek(姜庆东译)
摘要
对可执行文件的深入认识将带你深入到系统深处。如果你知道你的exe/dll里是些什么东东,你就是一个更有知识的程序员。作为系列文章的第一章,将关注这几年来PE格式的变化,同时也简单介绍一下PE格式。经过这次更新,作者加入了PE格式是如何与.NET协作的及PE文件表格(PE FILE SECTIONS),RVA,The DataDirectory,函数的输入等内容。
__====================
很久以前,我给Microsoft Systems Journal(现在的MSDN)写了一篇名为“Peering Inside the PE: A Tour of the Win32 Portable Executable File Format”的文章。后来比我期望的还流行,到现在我还听说有人在用它(它还在MSDN里)。不幸的是,那篇文章的问题依旧存在,WIN32的世界静悄悄地变了好多,那篇文章已显得过期了。从这个月开始我将用这两篇文章来弥补。
你可能会问为什么我应当了解PE格式,答案依旧:操作系统的可执行文件格式和数据结构暴露出系统的底层细节。通过了解这些,你的程序将编的更出色。
当然,你可以阅读微软的文档来了解我将要告诉你的。但是,像很多文档一样,‘宁可晦涩,但为瓦全’。
我把焦点放在提供一些不适合放在正式文档里的内容。另外,这篇文章里的一些知识不见得能在官方文档里找到。
1. 裂缝的撕开
让我给你一些从1994年我写那篇文章来PE格式变化的例子。WIN16已经成为历史,也就没有必要作什么比较和说明了。另外一个可憎的东西就是用在WINDOWS 3.1 中的WIN32S,在它上面运行程序是那么的不稳定。
那时候,WINDOWS 95(也叫Chicago)还没有发行。NT还是3.5版。微软的连接器还没开始大规模的优化,尽管如此,there were MIPS and DEC Alpha implementations of Windows NT that added to the story.
那么究竟,这么些年来,有些什么新的东西出来呢?64位的WINDOWS有了它自己的PE变种,WINDOWS CE 支持各种CPU了,各种优化如DLL的延迟载入,节表的合并,动态捆绑等也已出台。
有很多类似的东西发生了。
让我们最好忘了.NET。它是如何与系统切入的呢?对于操作系统,.NET的可执行文件格式是与旧的PE格式兼容的。虽然这么说,在运行时期,.NET还是按元数据和中间语言来组织数据的,这毕竟是它的核心。这篇文章当中,我将打开.NET元数据这扇门,但不做深入讨论。
如果WIN32的这些变化都不足以让我重写这篇文章,就是原来的那些错误也让我汗颜。比如我对TLS的描述只是一带而过,我对时间戳的描述只有你生活在美国西部才行等等。还有,一些东西已是今是作非了,我曾说过.RDATA几乎没排上用场,今天也是,我还说过.IDATA节是可读可写的,但是一些搞API拦截的人发现好像是错的。
在更新这篇文章的过程当中,我也检查了PEDUMP这个用来倾印PE文件的程序.这个程序能够在0X86和IA-64平台下编译和运行。
2. PE格式概览
微软的可执行文件格式,也就是大家熟悉的PE 格式,是官方文档的一部分。但是,它是从VAX/VMS上的COFF派生出来的,就WINDOWS NT小组的大部分是从DEC转过来的看来,这是可以理解的。很自然,这些人在NT的开发上会用他们以往的代码。
采用术语“PORTABLE EXECUTABLE”是因为微软希望有一个通用在所有WINDOWS平台上和所有CPU上的文件格式。从大的方面讲,这个目标已经实现。它适用于NT及其后代,95及其后代,和CE.
微软产生的OBJ文件是用COFF格式的。当你看到它的很多域都是用八进制的编码的,你会发现她是多么古老了。COFF OBJ文件用到了很多和PE一样的数据结构和枚举,我马上会提到一些。
64位的WINDOWS只对PE格式作了一点点改变。这个新的格式叫做PE32+。没有增加一个字段,且只删了一个字段。其他的改变就是把以前的32位字段扩展成64位。对于C++代码,通过宏定义WINDOWS的头文件已经屏蔽了这些差别。
EXE与DLL的差别完全是语义上的。它们用的都是同样一种文件格式-PE。唯一的区别就是其中有一个字段标识出是EXE还是DLL.还有很多DLL的扩展比如OCX,CPL等都是DLL.它们有一样的实体。
你首先要知道的关于PE的知识就是磁盘中的数据结构布局和内存中的数据结构布局是一样的。载入可执行文件(比如LOADLIBARY)的首要任务就是把磁盘中的文件映射到进程的地址空间.因此像IMAGE_NT_HEADER(下面解释)在磁盘和内存中是一样的。关键的是你要懂得你怎样在磁盘中获得PE文件某些信息的,当它载入内存时你可以一样获得,基本上是没什么不同的(即内存映射文件)。但是知道与映射普通的内存映射文件不同是很重要的。WINDOWS载入器察看PE文件才决定映射到哪里,然后从文件的开始处往更高的地址映射,但是有的东西在文件中的偏移和在内存中的偏移会不一样。尽管如此,你也有了足够的信息把文件偏移转化成内存偏移。见图一: