WIN32汇编语言教程:第17章 PE文件 · 17.1 PE文件的结构(2)
从DOS文件头的e_lfanew字段(文件头偏移003ch)得到真正的PE文件头位置后,现在来看看它的定义,PE文件头是由IMAGE_NT_HEADERS结构定义的:
IMAGE_NT_HEADERS STRUCT Signature DWORD ? ;PE文件标识 FileHeader IMAGE_FILE_HEADER <> ;★ OptionalHeader IMAGE_OPTIONAL_HEADER32 <> ;★ IMAGE_NT_HEADERS ENDS
PE文件头的第一个双字是一个标志,它被定义为00004550h,也就是字符“P”,“E”加上两个0,这也是“PE”这个称呼的由来,大部分的文件属性由标志后面的IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER32结构来定义,从名称看,似乎后面的这个PE文件表头结构是可选的(Optional),但实际上这个名称是名不符实的,因为它总是存在于每个PE文件中。
1. IMAGE_FILE_HEADER结构
IMAGE_FILE_HEADER结构的定义如下所示,字段后面的注释中标出了字段相对于PE文件头的偏移量,以供读者快速参考:
IMAGE_FILE_HEADER STRUCT Machine WORD ? ;0004h - 运行平台★ NumberOfSections WORD ? ;0006h - 文件的节数目★ TimeDateStamp DWORD ? ;0008h - 文件创建日期和时间 PointerToSymbolTable DWORD ? ;000ch - 指向符号表(用于调试) NumberOfSymbols DWORD ? ;0010h - 符号表中的符号数量(用于调试) SizeOfOptionalHeader WORD ? ;0014h - IMAGE_OPTIONAL_HEADER32结构的长度★ Characteristics WORD ? ;0016h - 文件属性★ IMAGE_FILE_HEADER ENDS
几个关键字段的含义解释如下。
● Machine字段
用来指定文件的运行平台,常见的定义值见表17.1所示。Windows可以运行在Intel和SUN等几种不同的硬件平台上,不同平台指令的机器码是不同的,为不同平台编译的可执行文件显然无法通用。如果Windows检测到这个字段指定的适用平台与当前的硬件平台不兼容,它将拒绝装入这个文件。
表17.1 运行平台识别码的定义(更多定义参见Windows.inc文件)
Windows.inc中的预定义值 | 16进制值 | 说明 |
IMAGE_FILE_MACHINE_UNKNOWN | 0 | 未知平台 |
IMAGE_FILE_MACHINE_I386 | 014ch | Intel 386 |
暂无 | 014dh | Intel 486 |
暂无 | 014eh | Intel 586 |
暂无 | 0160h | R3000(大尾方式) |
IMAGE_FILE_MACHINE_R3000 | 0162h | R3000(小尾方式) |
IMAGE_FILE_MACHINE_R4000 | 0166h | R4000(小尾方式) |
IMAGE_FILE_MACHINE_R10000 | 0168h | R10000(小尾方式) |
IMAGE_FILE_MACHINE_ALPHA | 0184h | Dec Alpha AXP |
IMAGE_FILE_MACHINE_POWERPC | 01f0h | IBM Power PC(小尾方式) |
IMAGE_FILE_MACHINE_ALPHA64 | 0284h | Dec Alpha AXP64 |
● NumberOfSections字段
指出文件中存在的节的数量(如图17.1中的④所示),同样,节表的数量(如图17.1中的③所示)也等于节的数量。
● TimeDateStamp字段
编译器创建此文件的时间,它的数值是从1969年12月31日下午4:00开始到创建时间为止的总秒数。
● PointerToSymbolTable和NumberOfSymbols字段
这两个字段并不重要,它们与调试用的符号表有关。
● SizeOfOptionalHeader字段
紧接在当前结构下面的IMAGE_OPTIONAL_HEADER32结构的长度,这个值等于00e0h。
● Characteristics字段
属性标志字段,它的不同数据位定义了不同的文件属性,具体内容如表17.2所示,这是一个很重要的字段,不同的定义将影响系统对文件的装入方式,比如,当位13为1时,表示这是一个DLL文件,那么系统将使用调用DLL入口函数的方式调用文件入口,否则的话,表示这是一个普通的可执行文件,系统直接跳到入口处执行。对于普通的可执行PE文件,这个字段的值一般是010fh,而对于DLL文件来说,这个字段的值一般是210eh。
表17.2 属性位字段的含义
数据位 | Windows.inc中的预定义值 | 为1时的含义 |
0 | IMAGE_FILE_RELOCS_STRIPPED | 文件中不存在重定位信息 |
1 | IMAGE_FILE_EXECUTABLE_IMAGE | 文件是可执行的 |
2 | IMAGE_FILE_LINE_NUMS_STRIPPED | 不存在行信息 |
3 | IMAGE_FILE_LOCAL_SYMS_STRIPPED | 不存在符号信息 |
7 | IMAGE_FILE_BYTES_REVERSED_LO | 小尾方式 |
8 | IMAGE_FILE_32BIT_MACHINE | 只在32位平台上运行 |
9 | IMAGE_FILE_DEBUG_STRIPPED | 不包含调试信息 |
10 | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | 不能从可移动盘(如软盘、光盘)运行 |
11 | IMAGE_FILE_NET_RUN_FROM_SWAP | 不能从网络运行 |
12 | IMAGE_FILE_SYSTEM | 系统文件(如驱动程序),不能直接运行 |
13 | IMAGE_FILE_DLL | 这是一个 DLL 文件 |
14 | IMAGE_FILE_UP_SYSTEM_ONLY | 文件不能在多处理器上计算机上运行 |
15 | IMAGE_FILE_BYTES_REVERSED_HI | 大尾方式 |
2. IMAGE_OPTIONAL_HEADER32结构
定义IMAGE_OPTIONAL_HEADER32结构的本意在于让不同的开发者能够在PE文件头中使用自定义的数据,这就是结构名称中“Optional”一词的由来,但实际上IMAGE_FILE_HEADER结构不足以用来定义PE文件的属性,反而在这个“可选”的部分中有着更多的定义数据,对于读者来说,可以完全不必考虑这两个结构的区别在哪里,只要把它们当成是连在一起的“PE文件头结构”就可以了。
IMAGE_OPTIONAL_HEADER32结构的定义如下,同样,字段后面的注释中标出了字段本身相对于PE文件头的偏移量:
IMAGE_OPTIONAL_HEADER32 STRUCT Magic WORD ? ;0018h 107h=ROM Image,10Bh=exe Image MajorLinkerVersion BYTE ? ;001ah 链接器版本号 MinorLinkerVersion BYTE ? ;001bh SizeOfCode DWORD ? ;001ch 所有含代码的节的总大小 SizeOfInitializedData DWORD ? ;0020h所有含已初始化数据的节的总大小 SizeOfUninitializedData DWORD ? ;0024h 所有含未初始化数据的节的大小 AddressOfEntryPoint DWORD ? ;0028h 程序执行入口RVA BaseOfCode DWORD ? ;002ch 代码的节的起始RVA BaseOfData DWORD ? ;0030h 数据的节的起始RVA ImageBase DWORD ? ;0034h 程序的建议装载地址 SectionAlignment DWORD ? ;0038h 内存中的节的对齐粒度 FileAlignment DWORD ? ;003ch 文件中的节的对齐粒度 MajorOperatingSystemVersion WORD ? ;0040h 操作系统主版本号 MinorOperatingSystemVersion WORD ? ;0042h 操作系统副版本号 MajorImageVersion WORD ? ;0044h可运行于操作系统的最小版本号 MinorImageVersion WORD ? ;0046h MajorSubsystemVersion WORD ? ;0048h 可运行于操作系统的最小子版本号 MinorSubsystemVersion WORD ? ;004ah Win32VersionValue DWORD ? ;004ch 未用 SizeOfImage DWORD ? ;0050h 内存中整个PE映像尺寸 SizeOfHeaders DWORD ? ;0054h 所有头+节表的大小 CheckSum DWORD ? ;0058h Subsystem WORD ? ;005ch 文件的子系统 DllCharacteristics WORD ? ;005eh SizeOfStackReserve DWORD ? ;0060h 初始化时的堆栈大小 SizeOfStackCommit DWORD ? ;0064h 初始化时实际提交的堆栈大小 SizeOfHeapReserve DWORD ? ;0068h 初始化时保留的堆大小 SizeOfHeapCommit DWORD ? ;006ch 初始化时实际提交的堆大小 LoaderFlags DWORD ? ;0070h 未用 NumberOfRvaAndSizes DWORD ? ;0074h 下面的数据目录结构的数量 DataDirectory IMAGE_DATA_DIRECTORY 16 dup(<>) ;0078h IMAGE_OPTIONAL_HEADER32 ENDS
上页:第17章 PE文件 · 17.1 PE文件的结构(1) 下页:第17章 PE文件 · 17.1 PE文件的结构(3)