找回密码
 注册
搜索
热搜: 回贴

“PE文件格式”1.9版 完整译文,PE文件,系统底层

2010-1-30 18:16| 发布者: admin| 查看: 65| 评论: 0|原作者: 心然


“PE文件格式”1.9版 完整译文,PE文件,系统底层
2008年06月23日 星期一 下午 01:46
$Id: pe.txt,v 1.9 1999/03/20 23:55:09 LUEVELSMEYER Exp $



PE文件格式系列译文之一----

【翻译】“PE文件格式”1.9版 完整译文(附注释)

=========================================================

原着:Bernd. Luevelsmeyer

翻译:ah007

附件:下载



[注意:本译文的所有大小标题序号都是译者添加,以方便大家阅读。圆圈内的数字是注释的编号,其中注释②译自微软的《PECOFF规范》,其它译自网络。----译者]





一、前言(Preface)

------------------



PE(“portable executable”,可移植的可执行文件)文件格式,是微软WindwosNT,Windows95和Win32子集①中的可执行的二进制文件的格式;在WindowsNT中,驱动程序也是这种格式。它还能被应用于各种目标文件②和库文件中。



这种文件格式是由微软设计的,并于1993年被TIS(tool interface standard,工具接口标准)委员会(由Microsoft,Intel,Borland,Watcom,IBM,等等组成)所批准,它明显的基于COFF文件格式的许多知识。COFF(“common object file fromat”,通用目标文件格式)是应用于好几种UNIX系统③和VMS④系统中的目标文件和可执行文件的格式。



Win32 SDK⑤中包含一个名叫的头文件,其中含有很多用于PE格式的#define和typedef定义。我将逐步地提到其中的很多结构成员名字和#define定义。



你也可能发现DLL文件“imagehelp.dll”很有用途,它是WindowNT的一部分,但其书面文件却很缺乏。它的一些功用在“Developer Network”(开发者网络)中有所描述。







二、总览(General Layout)

-------------------------



在一个PE文件的开始处,我们会看到一个MS-DOS可执行体(英语叫“stub”,意为“根,存根”);它使任何PE文件都是一个有效的MS-DOS可执行文件。



在DOS-根之后是一个32位的签名以及魔数0x00004550 (IMAGE_NT_SIGNATURE)(意为“NT签名”,也就是PE签名;十六进制数45和50分别代表ASCII码字母E和P----译者注)。



之后是文件头(按COFF格式),用来说明该二进制文件将运行在何种机器之上、分几个区段、链接的时间、是可执行文件还是DLL、等等。(本文中可执行文件和DLL文件的区别在于:DLL文件不能被启动,但能被别的二进制文件使用,而一个二进制文件则不能链接到另一个可执行文件。)



那些之后,是可选头(尽管它一直都存在,却仍被称作“可选”----因为COFF文件格式仅为库文件使用一个“可选头”,却不为目标文件使用一个“可选头”,这就是为什么它被称为“可选”的原因)。它会告诉我们该二进制文件怎样被载入的更多信息:开始的地址呀、保留的堆栈数呀、数据段的大小呀、等等。



可选头的一个有趣的部分是尾部的“数据目录”数组;这些目录包含许多指向各“节”数据的指针。例如:如果一个二进制文件拥有一个输出目录,那么你就会在数组成员“IMAGE_DIRECTORY_ENTRY_EXPORT”(输出目录项)中找到一个指向那个目录的指针,而该指针指向文件中的某节。



跟在各种头后面我们就发现各个“节”了,它们都由“节头”引导。本质上讲,各节中的内容才是你执行一个程序真正需要的东西,所有头和目录这些东西只是为了帮助你找到它们。

每节都含有和对齐、包含什么样的数据(如“已初始化数据”等等)、是否能共享等有关的一些标记,还有就是数据本身。大多数(并非所有)节都含有一个或多个可通过可选头的“数据目录”数组中的项来参见的目录,如输出函数目录和基址重定位目录等。无目录形式的内容有:例如“可执行代码”或“已初始化数据”等。



-------------------

| DOS-stub | --DOS-头

-------------------

| file-header | --文件头

-------------------

| optional header | --可选头

|- - - - - - - - - -|

| |

| data directories | --数据目录

| |

-------------------

| |

| section headers | --节头

| |

-------------------

| |

| section 1 | --节1

| |

-------------------

| |

| section 2 | --节2

| |

-------------------

| |

| ... |

| |

-------------------

| |

| section n | --节n

| |

-------------------







三、DOS-根和签名(DOS-stub and Signature)

-----------------------------------------



DOS-根的概念很早从16位windows的可执行文件(当时是“NE”格式⑥)时就广为人知了。根原来是用于OS/2⑦系统的可执行文件的,也用于自解压档案文件和其它的应用程序。对于PE文件来说,它是一个总是由大约100个字节所组成的和MS-DOS 2.0兼容的可执行体,用来输出象“this program needs windows NT”之类的错误信息。



你可以通过确认DOS-头部分是否为一个IMAGE_DOS_HEADER(DOS头)结构来认出DOS-根,它的前两个字节必须为连续的两个字母“MZ”(有一个#define IMAGE_DOS_SIGNATURE的定义是针对这个WORD单元的)。



你可以通过跟在后面的签名来将一个PE二进制文件和其它含有根的二进制文件区分开来,跟在后面的签名可由头成员'e_lfanew'(它是从字节偏移地址60处开始的,有32字节长)所设定的偏移地址找到。对于OS/2系统和Windows系统的二进制文件来说,签名是一个16位的word单元;对于PE文件来说,它是一个按照8位字节边界对齐的32位的longword单元,并且IMAGE_NT_SIGNATURE(NT签名)的值已由#defined定义为0x00004550(即字母“PE/0/0”----译者)。







四、文件头(File Header)

-------------------------



要到达IMAGE_FILE_HEADER(文件头)结构,请先确认DOS-头“MZ”(起始的2个字节),然后找出DOS-根的头部的成员“e_lfanew”,并从文件开始处跳过那么多的字节。在核实你在那里找到的签名后,IMAGE_FILE_HEADER(文件头)结构的文件头就紧跟其后开始了,下面我们将从头至尾的介绍其成员。



1)第一个成员是“Machine(机器)”,一个16位的值,用来指出该二进制文件预定运行于什么样的系统。已知的合法的值有:



IMAGE_FILE_MACHINE_I386 (0x14c)

Intel 80386 处理器或更高



0x014d

Intel 80386 处理器或更高



0x014e

Intel 80386 处理器或更高



0x0160

R3000 (MIPS⑧)处理器,大尾⑨



IMAGE_FILE_MACHINE_R3000 (0x162)

R3000 (MIPS)处理器,小尾



IMAGE_FILE_MACHINE_R4000 (0x166)

R4000 (MIPS)处理器,小尾



IMAGE_FILE_MACHINE_R10000 (0x168)

R10000 (MIPS)处理器,小尾



IMAGE_FILE_MACHINE_ALPHA (0x184)

DEC Alpha AXP⑩处理器



IMAGE_FILE_MACHINE_POWERPC (0x1F0)

IBM Power PC,小尾



2)然后是“NumberOfSections(节数)”成员,16位的值。它是紧跟在头后面的节的数目。我们以后将讨论节的问题。



3)下一个成员是时间戳“TimeDateStamp”(32位),用来给出文件建立的时间。即使它的“官方”版本号没有改变,你也可通过这个值来区分同一个文件的不同版本。(除了同一个文件的不同版本之间必须唯一,时间戳的格式没有明文规定,但似乎是按照UTC 时间“从1970年1月1日00:00:00算起的秒数值”----也就是大多数C语言编译器给time_t标志使用的格式。)

这个时间戳是用来绑定各个输入目录的,我们稍后再讨论它。

警告:有一些链接器往往将时间戳设为荒唐的值,而不是如前所述的time_t格式的链接时间。



4-5)成员“PointerToSymbolTable(符号表指针)”和成员“NumberOfSymbols(符号数)”(都是32位)都用于调试信息的。我不知道该怎样去解读它,并且我发现该指针的值总为0。



6)成员“SizeOfOptionalHeader(可选头大小)”(16位)只是“IMAGE_OPTIONAL_HEADER(可选头)”项的大小,你能用它去验证PE文件结构的正确性。



7)成员“Characteristics(特性)”是一个16位的,由许多标志位形成的集合组成,但大多数标志位只对目标文件和库文件有效。具体如下:

位0 IMAGE_FILE_RELOCS_STRIPPED(重定位被剥离文件) 表示如果文件中没有重定位信息,该位置1,这就表明各节的重定位信息都在它们各自的节中;可执行文件不使用该位,它们的重定位信息放在下面将要描述的“base relocation”(基址重定位)目录中。



位1 IMAGE_FILE_EXECUTABLE_IMAGE(可执行映象文件) 表示如果文件是一个可执行文件,也即不是目标文件或者库文件时,置1。如果链接器尝试创建一个可执行文件,却因为一些原因失败了,并保存映像以便下次例如增量链接时使用,此时此标志位也可能置1。



位2 IMAGE_FILE_LINE_NUMS_STRIPPED(行数被剥离文件) 表示如果行数信息被剥除,此位置1;此位也不用于可执行文件。



位3 IMAGE_FILE_LOCAL_SYMS_STRIPPED(本地符号被剥离文件) 表示如果文件中没有关于本地符号的信息时,此位置1(此位也不用于可执行文件)。



位4 IMAGE_FILE_AGGRESIVE_WS_TRIM(强行工作集修剪文件) 表示如果操作系统被假定为:通过将正在运行的进程(它所使用的内存数量)强行的页清除来修剪它的工作集时,此位置1。如果一进程是大部分时间处于等待,且一天中仅被唤醒一次的演示性的应用程序之类时,此位也应该被置1。



位7 IMAGE_FILE_BYTES_REVERSED_LO(低字节变换文件)和 位15IMAGE_FILE_BYTES_REVERSED_HI(高字节变换文件) 表示如果一文件的字节序不是机器所预期的形式,因此它在读入前必须调换字节时,此位置1。这样做对可执行文件是不可靠的(操作系统期望可执行文件都已经被正确地按字节排整齐了)。



位8 IMAGE_FILE_32BIT_MACHINE(32位机器文件) 表示如果使用的机器被期望为32位的机器时,此位置1。现在的应用程序总将此位置1;NT5系统可能工作不同。



位9 IMAGE_FILE_DEBUG_STRIPPED(调试信息被剥离文件) 表示如果文件中没有调试信息,此位置1。此位可执行文件不用。按照其它信息([6])(这里指的是参考书目中的第[6]种----译者注),此位被称作“恒定”,并且当一个映象文件只有在被装入优先的装入地址才能运行(亦即:此文件不可重定位)时,此位置1。



位10 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP(移动介质文件从交换文件运行) 表示如果一个应用程序不可以从可移动的介质,如软盘或CD-ROM上运行时,此位置1。在这种情况下,建议操作系统将文件复制到交换文件并从那里执行。



位11 IMAGE_FILE_NET_RUN_FROM_SWAP(网络文件从交换文件运行) 表示如果一个应用程序不可以从网络上运行时,此位置1。在这种情况下,建议操作系统将文件复制到交换文件并从那里执行。



位12 IMAGE_FILE_SYSTEM(系统文件) 表示如果文件是一个象驱动程序那样的系统文件,此位置1。此位可执行文件不用;我所见过的所有NT系统的驱动程序也不用。



位13 IMAGE_FILE_DLL(DLL文件) 表示如果文件是一个DLL文件时,此位置1。



位14 IMAGE_FILE_UP_SYSTEM_ONLY(仅但处理器系统的文件) 表示如果文件不设计运行在多处理器系统上(也就是说,因为此文件严格地依赖单一处理器的一些方式工作,所以它会发生冲突)时,此位置1。




最新评论

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-30 01:36 , Processed in 0.111752 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

返回顶部