PE结构 PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,它们之间的区别只是语义上的,它们使用完全相同的PE格式,唯一的区别就是用一个字段标识出是EXE还是DLL。
PE格式定义在头文件winnt.h中,64位PE格式只是对32位做了简单的扩展,结构几乎一样。
MS-DOS头部 每个PE文件都是以一个DOS程序开始的。 PE文件的第一个字节起始于一个传统的MS-DOS头部,被称为IMAGE_DOS_HEADER。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
e_magic:一个WORD类型0x4D5A,因此可执行文件必须都是’MZ’开头。
e_lfanew:为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移。
PE文件头 PE相关结构NT映像头,PE文件执行时,装载器在IMAGE_DOS_HEADER中的e_lfanew中找到PE头的起始偏移量,加上基地址就是PE文件头指针。
1 2 3 4 5 typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
Signature 类似于DOS头中的e_magic,0x00004550,用字符表示是’PE’
struct _IMAGE_FILE_HEADER { 1 2 3 4 5 6 7 8 WORD Machine; //运行平台 WORD NumberOfSections; //文件区块数 DWORD TimeDateStamp; //创建的日期时间 DWORD PointerToSymbolTable; //指向符号表 DWORD NumberOfSymbols; //符号表中符号个数 WORD SizeOfOptionalHeader; //紧随其后的可选头的大小 WORD Characteristics; //文件属性 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; //文件被执行时入口RVA地址 DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; //文件优先装入地址 DWORD SectionAlignment; //节在内存中对齐单位 DWORD FileAlignment; //节存储在磁盘文件中对齐单位 WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; //子系统 WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //数据目录表 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
数据目录表: typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 //导出表 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 //导入表 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 //资源 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 //异常 #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 //安全 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 //重定位表 #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 //调试信息 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 //版权信息 #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 //RVA of GP #define IMAGE_DIRECTORY_ENTRY_TLS 9 //TLS Directory #define IMAGE_DIRECTORY_ENTRY_LOAD_IMPORT 10 //Lood Configuration Directory #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 //Bound Import Directory in headers #define IMAGE_DIRECTORY_ENTRY_IAT 12 //导入函数地址表 #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 //Delay Load Import Descriptors #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 //COM Runtime descriptor
节表 PE中所有节的属性都定义在节表中,节表由一系列IMAGE_SECTION_HEADER结构构成,每个结构描述一个节,最后以一个空的结构结束 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //节表名称 union { DWORD PhysicalAddress; //物理地址 DWORD VirtualSize; //区块的大小(没对齐的实际大小) } Misc; DWORD VirtualAddress; //装载到内存中的RVA,是SectionAlignment的整数倍 DWORD SizeOfRawData; //在磁盘中占的大小 DWORD PointerToRawData; //在磁盘中的偏移地址(从文件头开始) DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; //区块的属性 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;