PE文件结构与程序装载是掌握Windows逆向、加壳、免杀等技术的基础,本文详细记录了PE文件的基本结构,用编辑器对文件结构进行分析,并介绍程序装载的相关概念和基本过程。
参考书籍:《逆向工程核心原理》《程序员的自我修养》
文章目录
一、PE文件结构
Windows PE (Protable Executable) 文件基本结构由PE头和多个节区组成,如下图所示:
下面逐一说明各个部分的基本特征和作用:
(一) PE头
1.DOS头
微软在创建PE文件格式时,DOS文件正在广泛使用,为兼容DOS文件,在PE头部添加了DOS头部分,DOS头实际上是 IMAGE_DOS_HEADER
结构体,大小为64字节,定义如下所示:
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;
该结构体中有2个重要成员:
WORD e_magic
:DOS签名,固定为4D5A (“MZ”),位于DOS头的第一个部分LONG e_lfanew
:标识NT头的偏移,位于DOS头的最后一个部分
2.DOS存根
可选项,大小不固定,由代码和数据组成。在32/64位Windows系统中会被识别为PE格式,此时会跨过DOS存根部分;在DOS环境中系统不能识别PE文件格式,因此按照DOS文件进行解析,此时DOS存根部分的代码会被执行。
3.NT头
实际为 IMAGE_NT_HEADERS
结构体,大小为248个字节,定义如下所示:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; // PE Signature (“PE”00)
IMAGE_FILE_HEADER FileHeader; // PE File Header
IMAGE_OPTIONAL_HEADER32 OptionalHeader; // PE Optional Header
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
该结构体中成员有3个,介绍如下:
(1) DWORD Signature
:PE签名,为0x50450000 (“PE”00)
(2) IMAGE_FILE_HEADER FileHeader
:该结构体大小为20个字节,定义如下所示:
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER
结构体中又包括4种重要成员,如下所示:
① WORD Machine
:CPU标识,每种CPU对应唯一的Machine码,常见的如:Intel386 —> 0x014c,AMD64 —> 0x8664
② WORD NumberOfSections
:节区数量,PE文件按照节区的属性划分节区
③ WORD SizeOfOptionalHeader
:标识IMAGE_OPTIONAL_HEADER32
或IMAGE_OPTIONAL_HEADER64
结构体的长度
④ WORD Characteristics
:文件类型,不同类型按位向或进行组合,常见如:EXE文件 —> 0x0002,DLL文件 —> 0x2000,具体如下:
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010