内容引用自:看雪《逆向工程原理》,http://www.blogfshare.com/pe-header-one.html 。 如有错误,欢迎留言。
1、 PE文件是windows操作系统下使用的可执行文件格式。
PE文件指的是32位的可执行文件。 64位的可执行文件成为PE+ 或者 PE32+。
2、 PE文件格式为
DOS头(DOS Header) + DOS存根(DOS Stub) + PE 头(PE Header)
+ 节表(区块表 section table) + 节(区块 sections)
各个部分的定义其实都是一个结构体变量
DOS Header 对应 IMAGE_DOS_HEADER
PE Header 对应 IMAGE_NT_HEADER
3、 DOS Header 是由 IMAGE_DOS_HEADER 定义,DOS Header固定为40h个字节,
其中e_magic 和 e_lfanew 是需要关注的,其他可忽略。
typedef struct _IMAGE_DOS_HEADER {
+00h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记 ,固定为 “MZ”
+02h WORD e_cblp // Bytes on last page of file
+04h WORD e_cp // Pages in file
+06h WORD e_crlc // Relocations
+08h WORD e_cparhdr // Size of header in paragraphs
+0ah WORD e_minalloc // Minimun extra paragraphs needs
+0ch WORD e_maxalloc // Maximun extra paragraphs needs
+0eh WORD e_ss // intial(relative)SS value DOS代码的初始化堆栈SS
+10h WORD e_sp // intial SP value DOS代码的初始化堆栈指针SP
+12h WORD e_csum // Checksum
+14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
+16h WORD e_cs // intial(relative)CS value DOS代码的初始堆栈入口 CS
+18h WORD e_lfarlc // File Address of relocation table
+1ah WORD e_ovno // Overlay number
+1ch WORD e_res[4] // Reserved words
+24h WORD e_oemid // OEM identifier(for e_oeminfo)
+26h WORD e_oeminfo // OEM information;e_oemid specific
+29h WORD e_res2[10] // Reserved words
+3ch LONG e_lfanew // Offset to start of PE header
指向PE文件头(IMAGE_NT_HEADER)的偏移地址,也就是真正PE文件头在文件中的位置。
} IMAGE_DOS_HEADER
4、DOS Stub
在DOS Header 下方,是可选项,大小不固定,即使没有DOS Stub ,文件也可以正常运行。
5、PE Header 由 IMAGE_NT_HEADER32 定义, IMAGE_NT_HEADER32 固定为 F8h个字节
typedef struct _IMAGE_NT_HEADER {
+0h DWORD Signature PE文件标识 , 固定为 50 45 00 00 (“PE00”)
+4h IMAGE_FILE_HEADER FileHeader
+18h IMAGE_OPTIONAL_HEADER32 OptionalHeader
} IMAGE_NT_HEADER32
typedef struct _IMAGE_FILE_HEADER { # 固定大小为14h个字节
+04h WORD Machine; // 运行平台
+06h WORD NumberOfSections; // 文件的区块数目
+08h DWORD TimeDateStamp; // 文件创建日期和时间
+0Ch DWORD PointerToSymbolTable; // 指向符号表(主要用于调试)
COFF符号表的文件偏移位置 常为00 00 00 00
+10h DWORD NumberOfSymbols; // 符号表中符号个数(同上) 常为00 00 00 00
+14h WORD SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 结构大小
+16h WORD Characteristics; // 文件属性
} IMAGE_FILE_HEADER
需要注意的点:
Machine 定义可执行文件的目标CPU类型,常见的值如下:
NumberOfSections 定义区块的数目
TimeDateStamp 定义文件创建时间,自1970年1月1日以来计算的秒数
SizeOfOptionalHeader 定义IMAGE_OPTION_HEADER32的大小,
对于32位PE文件通常为 00 E0,64位 PE+文件 通常为00 F0
Characteristics 定义文件的属性,以bit OR形式组合起来,各个位定义属性如下:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER {
+18h WORD Magic; // 标志字, ROM 映像(0107h),普通可执行文件(010Bh)
+1Ah BYTE MajorLinkerVersion; // 链接程序的主版本号
+1Bh BYTE MinorLinkerVersion; // 链接程序的次版本号
+1Ch DWORD SizeOfCode; // 所有含代码的节的总大小
+20h DWORD SizeOfInitializedData; // 所有含已初始化数据的节的总大小
+24h DWORD SizeOfUninitializedData; // 所有含未初始化数据的节的大小
+28h DWORD AddressOfEntryPoint; // 程序执行入口RVA
+2Ch DWORD BaseOfCode; // 代码的区块的起始RVA
+30h DWORD BaseOfData; // 数据的区块的起始RVA
+34h DWORD ImageBase; // 程序的首选装载地址
+38h DWORD SectionAlignment; // 内存中的区块的对齐大小
+3Ch DWORD FileAlignment; // 文件中的区块的对齐大小
+40h WORD MajorOperatingSystemVersion; // 要求操作系统最低版本号的主版本号
+42h WORD MinorOperatingSystemVersion; // 要求操作系统最低版本号的副版本号
+44h WORD MajorImageVersion; // 可运行于操作系统的主版本号
+46h WORD MinorImageVersion; // 可运行于操作系统的次版本号
+48h WORD MajorSubsystemVersion; // 要求最低子系统版本的主版本号
+4Ah WORD MinorSubsystemVersion; // 要求最低子系统版本的次版本号
+4Ch DWORD Win32VersionValue; // 莫须有字段,不被病毒利用的话一般为0
+50h DWORD SizeOfImage; // 映像装入内存后的总尺寸
+54h DWORD SizeOfHeaders; // 所有头 + 区块表的尺寸大小
+58h DWORD CheckSum; // 映像的校检和
+5Ch WORD Subsystem; // 可执行文件期望的子系统
+5Eh WORD DllCharacteristics; // DllMain()函数何时被调用,默认为 0
+60h DWORD SizeOfStackReserve; // 初始化时的栈大小
+64h DWORD SizeOfStackCommit; // 初始化时实际提交的栈大小
+68h DWORD SizeOfHeapReserve; // 初始化时保留的堆大小
+6Ch DWORD SizeOfHeapCommit; // 初始化时实际提交的堆大小
+70h DWORD LoaderFlags; // 与调试有关,默认为 0
+74h DWORD NumberOfRvaAndSizes; // 下边数据目录的项数,这个字段自Windows NT 发布以来一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 数据目录表
} IMAGE_OPTIONAL_HEADER32
需要注意的点:
Magic 逆向工程核心原理此处有错误, 普通可执行文件的值为 01 0Bh
AddressOfEntryPoint 指向入口地址 RVA地址
ImageBase 指出文件的优先装入地址。 进程虚拟内存空间为0-FFFFFFFF(32位系统),
EXE、DLL文件被装入内存的0-7FFFFFFF中,SYS文件被装入内存的80000000-FFFFFFFF中。
对于EXE文件,由于每个文件都使用独立的虚拟地址空间,优先装入地址不会被占用,所以总是可以依照该地址装入,
EXE文件也不需要重定位信息,一般EXE文件对应的该值为00400000h。
DLL文件的优先装入地址可能被占用,因此DLL文件必须包含重定位信息,一般DLL文件对应的该值为10000000h
SectionAlignment 指定了节被装入内存后的对齐单位
FileAlignment 指定了节存储在磁盘文件中的对齐单位
SizeOfImage 指定了 当PE文件被加载进内存后在虚拟内存占用的空间大小
SizeOfHeader 指定了 所有头 + 区块表 的大小
SubSystem 指定使用界面的子系统, 该字段决定系统如何为程序建立初始的界面,取值如下:
NumberOfRvaAndSizes 指定 DataDirectory 数组长度 目前为止固定为 00 00 00 10h
DataDirectory 最重要的字段之一,由16个IMAGE_DATA_DIRECTORY结构组成。
虽然PE文件中的数据是按照装入内存后的页属性归类而被放在不同的节中的,但是这些
处于各个节中的数据按照用途可以被分为导出表、导入表、资源、重定位表等数据块,
这16个IMAGE_DATA_DIRECTORY结构就是用来定义多种不同用途的数据块的。
数据目录列表(DataDirectory) 包含以下结构: 比较重要的是 导出表 导入表 资源表 重定位表 TLS Directory(thread local storage)