PE结构

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’

FileHeader

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;

OptionalHeader

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;