1、DOS头
// DOS MZ头,大小为64个字节 typedef struct _IMAGE_DOS_HEADER { WORD e_magic; // EXE标志,“MZ”(有用,解析时作为是否是PE文件的第一个标志) 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; // 非常重要,操作系统通过它找到NT头,NT头相对于文件的偏移地址 } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
DOS MZ头下面是DOS Stub,整个Dos Stub是一个字节快,其内容随着链接时使用的链接器不同而不同,而且长度不固定。
2、NT头
// NT 头 typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
(1)紧跟在DOS Stub后面的是PE头标识(DWORD) Signature, 占四个字节,内容固定为“PE “。
(2)标准PE头、文件头、COFF头,占20个字节
3、文件头
typedef struct _IMAGE_FILE_HEADER { WORD Machine; // 运行平台 WORD NumberOfSections; // PE中节的数量 DWORD TimeDateStamp; // 文件创建日期和时间 DWORD PointerToSymbolTable; // 指向符号表(用于调试) DWORD NumberOfSymbols; // 符号表中的符号数量(用于调试) WORD SizeOfOptionalHeader; // 扩展头结构的长度 WORD Characteristics; // PE文件属性 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
4、扩展PE头
// 32位程序当中扩展头的大小为224个字节 typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; // (有用)魔术字 107h = ROM Image, 10Bh = exe Image BYTE MajorLinkerVersion; // 链接器版本号 BYTE MinorLinkerVersion; DWORD SizeOfCode; // (有用)所有含代码的节的总大小 DWORD SizeOfInitializedData; // (有用)所有含已初始化数据的节的总大小 DWORD SizeOfUninitializedData;// (有用)所有含未初始化数据的节的大小 DWORD AddressOfEntryPoint; // (重要)程序执行入口RVA DWORD BaseOfCode; // (有用)代码的节的起始RVA DWORD BaseOfData; // (有用)数据的节的起始RVA DWORD ImageBase; // (重要)程序的建议装载基址(如果没有加载到这个地址,会发生重定位) DWORD SectionAlignment; // (重要)内存中的节的对齐粒度,一般是0x1000 DWORD FileAlignment; // (重要)文件中的节的对齐粒度,一般是0x200 WORD MajorOperatingSystemVersion; // 操作系统版本号 WORD MinorOperatingSystemVersion; WORD MajorImageVersion; // 该PE的版本号 WORD MinorImageVersion; WORD MajorSubsystemVersion; // 所需子系统版本号 WORD MinorSubsystemVersion; DWORD Win32VersionValue; // 未用 DWORD SizeOfImage; // (重要)把文件加载进内存,所需要的内存大小,注意是进行了块对齐之后 DWORD SizeOfHeaders; // (重要)所有头 + 节表的大小 DWORD CheckSum; // 校验和 WORD Subsystem; // (有用)文件的子系统 WORD DllCharacteristics; // (有用)指示DLL特征的标志 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;
5、数据目录表
// 数据目录项 typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; // 数据的起始RVA DWORD Size; // 数据块的长度 } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
struct IMAGE_DATA_DIRECTORY_ARRAY DataDirArray [0]struct IMAGE_DATA_DIRECTORY Export // 导出表 [1]struct IMAGE_DATA_DIRECTORY Import // 导入表 [2]struct IMAGE_DATA_DIRECTORY Resource // 资源表 [3]struct IMAGE_DATA_DIRECTORY Exception // 异常表 [4]struct IMAGE_DATA_DIRECTORY Security // 安全表 [5]struct IMAGE_DATA_DIRECTORY BaseRelocationTable // 重定位表 [6]struct IMAGE_DATA_DIRECTORY DebugDirectory // 调试信息 [7]struct IMAGE_DATA_DIRECTORY CopyrightOrArchitectureSpecificData // 版权信息 [8]struct IMAGE_DATA_DIRECTORY GlobalPtr // 全局PTR [9]struct IMAGE_DATA_DIRECTORY TLSDirectory // 线程本地存储 [10]struct IMAGE_DATA_DIRECTORY LoadConfigurationDirectory // 配置加载表 [11]struct IMAGE_DATA_DIRECTORY BoundImportDirectory // 绑定导入表 [12]struct IMAGE_DATA_DIRECTORY ImportAddressTable // 导入函数地址表 [13]struct IMAGE_DATA_DIRECTORY DelayLoadImportDescriptors // 延迟加载表 [14]struct IMAGE_DATA_DIRECTORY COMRuntimedescriptor // CLR头 [15]struct IMAGE_DATA_DIRECTORY Reserved // 预留
6、区段头表
// 节表项 typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 8个字节的节名 union { DWORD PhysicalAddress; DWORD VirtualSize; // 该节在没有对齐前的真实尺寸,该节可以不准确 } Misc; DWORD VirtualAddress; // 节区的RVA地址 DWORD SizeOfRawData; // 在文件中对齐后的尺寸 DWORD PointerToRawData; // 在文件中的偏移 DWORD PointerToRelocations; // 在OBJ文件中使用 DWORD PointerToLinenumbers; // 行号表的位置(供调试使用) WORD NumberOfRelocations; // 在OBJ文件中使用 WORD NumberOfLinenumbers; // 行号表中行号的数量 DWORD Characteristics; // 节的属性 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
7、RVA 转 FOA
1 // RVA 转 FOA 2 DWORD rva2foa(IMAGE_NT_HEADERS* pNt, DWORD dwRva) 3 { 4 IMAGE_SECTION_HEADER* pScnHdr = (IMAGE_SECTION_HEADER*) 5 IMAGE_FIRST_SECTION(pNt); 6 for (DWORD i = 0; i < pNt->FileHeader.NumberOfSections; i++) 7 { 8 if (dwRva >= pScnHdr[i].VirtualAddress && 9 dwRva <= pScnHdr[i].VirtualAddress + pScnHdr[i].SizeOfRawData) 10 { 11 return dwRva - pScnHdr[i].VirtualAddress + pScnHdr[i].PointerToRawData; 12 } 13 } 14 return -1; 15 }