3.3.2 32位系统下的PE结构
在16位系统中,PE头和PE数据部分被当成是冗余数据;
在32位系统中,刚好相反,即 DOS头成为冗余数据。
所谓冗余,是针对DOS头不参与32位系统运行过程而言的。尽管该部分不参与运行,但也不能把这些数据从PE结构中除去。
因为在DOS MZ头中有一个字段非常重要,即IMAGE_DOS_HEADER.e_lfanew,没有它操作系统就定位不到标准的PE头部,可执行程序也就会被操作系统认为是非法的PE映像。
所以经常也用它定位PE头起始地址。
1.定位标准PE头
由于DOS Stub的长度不固定,导致了DOS头也不是一个固定大小的数据结构。那么,在Windows PE中,既然把DOS头放在了PE的起始位置,
如何去定位后面的标准PE头所在的位置呢?
字段e_lfanew即起这个作用。该字段的值是一个相对偏移量,绝对定位时需要加上DOS MZ头的基地址。也就是说,通过以下公式可以得出PE头的绝对位置:
对比本书1.6节中代码清单1-2列出的HelloWorld.exe的字节码,可以看到该位置是以ASCII字符“PE”开头的,所以,通过字段 IMAGE_DOS_HEADER.e_lfanew的值可以定位到PE头的起始位置。
2.PE文件结构
如上图所示,32位系统下的PE文件结构被划分为5个部分,包括:
- DOS MZ头
- DOS Stub
- PE头
- 节表
- 节内容
节表(Section Table)和节内容()两部分其实就是图3-5中所示的PE数据区。DOS MZ头的大小是64个字节,PE头的大小是456个字节(由于数据目录表项不一定是16个,所以准确地说,PE头也是一个不能确定大小的结构,该结构的实际大小由字段IMAGE_FILE_HEADER.SizeOfOptionalHeader来确定)。
节表的大小之所以不固定,是因为每个PE中节的数量是不固定的。每个节的描述信息则是个固定值,共40个字节,节表是由不确定数量的节描述信息组成的,其大小等于节的数量×40,节的数量由字段IMAGE_FILE_HEADER.NumberOfSections来定义。DOS Stub和节内容都是大小不确定的。
节表是PE中所有节的目录,每个目录都是一个“BookStore”,其字节码就是节内容。它按照目录里的指针指向的地址,分别将节的字节码在文件空间中排列起来,从而组成了一个完整的PE文件。PE文件头部等于DOS头+PE头。
3.3.3 程序员眼中的PE结构
如图所示,一个标准的PE文件一般由四大部分组成:
- DOS头
- PE头 ( IMAGE_NT_HEADERS)
- 节表(多个IMAGE_SECTION_HEADER结构)
- 节内容(具体数据段)
其中,PE头的数据结构最为复杂。简单来说,PE头包含:
- 4个字节的标识符号( Signature)
- 20个字节的基本头信息(IMAGE_FILE_HEADER)
- 216个字节的扩展头信息(IMAGE_OPTIONAL_HEADER32)
说明如果按照“头部+身体”的信息组织方式来看:
- PE文件头部 = DOS头+PE头+节表
- PE文件身体=节内容
节内容中会出现各种不同的数据结构,如导入表、导出表、资源表、重定位表等,关于这些数据的组织方式会在后面的章节中陆续接触到。
总结对比
1.PE不同位数特点
PE类型 | 相同 | 不同 |
16位PE | ||
32位PE |
3.4 PE文件头部解析
3.4.1 DOS MZ头——IMAGE_DOS_HEADER
IMAGE_DOS_HEADER具体定义:
3.4.2 DOS stub
DOS MZ头的下面是DOS Stub。
整个DOS Stub是一个字节块,其内容随着链接时使用的链接器不同而不同,PE中并没有与之对应的相关结构。
3.4.3 PE头标识——Signature
紧跟在DOS Stub后面的是PE头标识Signature。
与大部分文件格式的头部结构一样,PE头部信息中有一个四字节的标识,
该标识位于指针IMAGE DOS_HEADER.e_Ifanew指向的位置。
其内容固定,对应于ASCⅡ码的字符串“PE\O\0”
。
3.4.4 标准PE头——IMAGE_FILE_HEADER
标准PE头IMAGE FILE HEADER紧跟在PE头标识后,即位于IMAGE DOS HEADER的e lfanew值+4的位置。
由此位置开始的20个字节为数据结构标准PE头IMAGE FILE HEADER的内容。
该结构在微软的官方文档中被称为标准通用对象文件格式(Common Object File Format,,COFF)头
。
作用
:
它记录了PE文件的全局属性
如该PE文件运行的平台、PE文件类型(是EXE文件还是DLL文件)、文件中存在的节的总数等
其详细定义如下:
注意:
该结构常用于判断PE文件是EXE类型还是DLL类型
,不但可以通过该结构得到PE文件中节的总量
,还可以当成对节区信息进行遍历操作时的循环次数
。
3.4.5 扩展PE头——IMAGE_OPTIONAL_HEADER32
定义:
作用:
- 文件执行时的
入口地址OEP
、 - 文件被操作系统装入内存后的默认基地址
Image_base
- 节在磁盘和内存中的对齐单位等信息均可以在此结构中找到。
注意:
对该结构中的某些数值的随意改动可能会造成PE文件的加载或运行失败。
3.4.6 PE头——IMAGE_NT_HEADERS
广义的PE头(即由PE头标识、标准PE头、拓展PE头三部分的组成):
其定义如下:
与DOS头一样,PE头开始也是一个标志,用一个双字的“PEO0”来命名,这也是PE头的由来。
Windows头文件winnt.h中IMAGE_NT_HEADERS
结构体