PE文件格式
PE的一些基本概念
名称 | 描述 |
---|---|
地址 | 是“虚拟地址”而不是“物理地址”。为什么不是“物理地址”呢?因为数据在内存的位置经常在变,这样可以节省内存开支、避开错误的内存位置等的优势。同时用户并不需要知道具体的“真实地址”,因为系统自己会为程序准备好内存空间的(只要内存足够大) |
镜像文件 | 包含以EXE文件为代表的“可执行文件”、以DLL文件为代表的“动态链接库”。为什么用“镜像”?这是因为他们常常被直接“复制”到内存,有“镜像”的某种意思。看来西方人挺有想象力的哦0 |
RVA | 英文全称Relatively Virtual Address。偏移(又称“相对虚拟地址”)。相对镜像基址的偏移。 |
节 | 节是PE文件中代码或数据的基本单元。原则上讲,节只分为“代码节”和“数据节”。 |
VA | 英文全称Virtual Address。基址 |
PE地址概念
虚拟地址VA = 基地址(ImageBase)+ 相对虚拟地址(RVA)
IMAGE_DOS_HEADER
一共有64个字节,一个WORD两个字节,一个LONG四个字节。
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; // [0x00] Magic number(重要,是否为PE文件的第一个标志)
WORD e_cblp; // [0x02]Bytes on last page of file
WORD e_cp; // [0x04]Pages in file
WORD e_crlc; // [0x06]Relocations
WORD e_cparhdr; // [0x08]Size of header in paragraphs
WORD e_minalloc; //[0x0A] Minimum extra paragraphs needed
WORD e_maxalloc; //[0x0C] Maximum extra paragraphs needed
WORD e_ss; // [0x0E]Initial (relative) SS value
WORD e_sp; // [0x10]Initial SP value
WORD e_csum; // [0x12]Checksum
WORD e_ip; //[0x14] Initial IP value
WORD e_cs; //[0x16] Initial (relative) CS value
WORD e_lfarlc; // [0x18]File address of relocation table
WORD e_ovno; // [0x1A]Overlay number
WORD e_res[4]; // [0x1C]Reserved words
WORD e_oemid; // [0x24]OEM identifier (for e_oeminfo)
WORD e_oeminfo; //[0x26] OEM information; e_oemid specific
WORD e_res2[10]; // [0x28]Reserved words
LONG e_lfanew; // [0x3C]File address of new exe header(有用,PE解析时用它找到PE头的位置)
} IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER;
重要数据的是第一个和最后一个,也就是e_magic与e_lfanew这两个数据成员,e_magic翻译为魔数,其实它就是一个标记,DOS头标志位,其值恒为4D5A,在系统中用宏定义为:IMAGE_DOS_SIGNATURE,e_lfanew,它表示NT头部在文件中的偏移。
IMAGE_NT_HEADERS32
typedef struct _IMAGE_NT_HEADERS
{
DWORD Signature; //标记(重要,判断是否为PE文件的第二个标志)
IMAGE_FILE_HEADER FileHeader; //文件头(重要,存储着PE文件的基本信息)
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //扩展头(重要,存储着关于PE文件时加载的信息)
} IMAGE_NT_HEADERS32, * PIMAGE_NT_HEADERS32;
IMAGE_FILE_HEADER
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; 1 (文件的运行平台)
WORD NumberOfSections; 2 (区段的数量)
DWORD TimeDateStamp; 3 (文件创建时间)
DWORD PointerToSymbolTable; 4 (符号表偏移,用于调试)
DWORD NumberOfSymbols; 5 (符号个数,用于调试)
WORD SizeOfOptionalHeader; 6 (扩展头的大小)
WORD Characteristics; 7 (PE文件的一些属性)
} IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER;
Machine :01 4C(注意是小端)
值 描述
0x0 适用于任何类型处理器
0x1d3 Matsushita AM33处理器
0x8664 x64处理器
0x1c0 ARM小尾处理器
0xebc EFI字节码处理器
0x14c Intel 386或后继处理器及其兼容处理器
0x200 Intel Itanium处理器
0x9041 Mitsubishi M32R小尾处理器
0x266 MIPS16处理器
0x366 带FPU的MIPS处理器
0x466 带FPU的MIPS16处理器
0x1f0 PowerPC小尾处理器
0x1f1 带符点运算支持的PowerPC处理器
0x166 MIPS小尾处理器
0x1a2 Hitachi SH3处理器
0x1a3 Hitachi SH3 DSP处理器
0x1a6 Hitachi SH4处理器
0x1a6 Hitachi SH5处理器
0x1c2 Thumb处理器
0x169 MIPS小尾WCE v2处理器
IMAGE_OPTIONAL_HEADER32
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic; 1 文件类型标识,32位一般是0x010B,64位的PE文件一般是0x020B,还有0x0170,代表ROM镜像。
BYTE MajorLinkerVersion; 2 连接器主版本
BYTE MinorLinkerVersion; 3 连接器次版本
DWORD SizeOfCode; 4 (重要)指所有代码区段(节)的总大小
DWORD SizeOfInitializedData; 5 已初始化数据的总大小
DWORD SizeOfUninitializedData; 6 未初始化数据的总大小,在磁盘中不占用空间,在加载进内存之后,会预留这么大的空间。一般存储在.bss区段中。
DWORD AddressOfEntryPoint; 7 (重要)程序开始执行的相对虚拟地址(RVA),也叫OEP,Orginal Entry Point ,源入口点。
DWORD BaseOfCode; 8 (重要)起始代码的相对虚拟地址(RVA),一般这个值为0x00001000.
DWORD BaseOfData; 9 起始数据的相对虚拟地址(RVA)
//
// NT additional fields.
//
DWORD ImageBase; 10 (重要)默认加载基址(如果没有加载到这个地址,会发生重定位.)
DWORD SectionAlignment; 11 (重要)块对齐数,就是在映射到内存中的区段(节)对齐,这个数必须大于文件对齐数,一般是0x1000
DWORD FileAlignment; 12 (重要)文件对齐数,就是在硬盘中的文件的区段(节)对齐,一般是0x200
WORD MajorOperatingSystemVersion; 13 主操作系统版本号
WORD MinorOperatingSystemVersion; 14 次操作系统版本号
WORD MajorImageVersion; 15 主映像版本
WORD MinorImageVersion; 16 次映像版本
WORD MajorSubsystemVersion; 17 主子系统版本
WORD MinorSubsystemVersion; 18 次子系统版本
DWORD Win32VersionValue; 19 保留值,一般是0
DWORD SizeOfImage; 20 (重要)要把文件加载进内存,所需要的内存大小,注意是进行了块对齐之后
DWORD SizeOfHeaders; 21 所有头部大小,Dos头、PE头、区段表的尺寸之和
DWORD CheckSum; 22 校验和(一般无用)对于驱动和一些系统dll来说需要校验(使用IMAGEHLP.DLL中的CheckSumMappedFile API)
WORD Subsystem; 23 (重要)子系统值
WORD DllCharacteristics ; 24 (重要)指示Dll特征的标志,DllMain()函数何时被调用,默认为0.
DWORD SizeOfStackReserve; 25 初始化时栈的大小
DWORD SizeOfStackCommit; 26 初始化时实际提交的栈的大小
DWORD SizeOfHeapReserve; 27 初始化时保留的堆的大小
DWORD SizeOfHeapCommit; 28 初始化时实际提交的堆的大小
DWORD LoaderFlags; 29 与调试相关
DWORD NumberOfRvaAndSizes; 30 数据目录的个数,也就是下面那个数组中元素的个数。
IMAGE_DATA_DIRECTORY DataDirectory[ IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 31 (非常重要)数据目录表
} IMAGE_OPTIONAL_HEADER32, * PIMAGE_OPTIONAL_HEADER32;
IMAGE_DATA_DIRECTORY
typedef struct _IMAGE_DATA_DIRECTORY
{
DWORD VirtualAddress; // 数据的相对虚拟地址(RVA)
DWORD Size; // 数据的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
IMAGE_SECTION_HEADER
typedef struct _IMAGE_SECTION_HEADER
{
+0 BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称,如“.text”
//IMAGE_SIZEOF_SHORT_NAME=8
+8 union
{
DWORD PhysicalAddress; // 物理地址
DWORD VirtualSize; // 真实长度,这两个值是一个联合结构,可以使用其中的任何一个,一
// 般是取后一个
} Misc;
+ch DWORD VirtualAddress; // 节区的 RVA 地址
+10h DWORD SizeOfRawData; // 在文件中对齐后的尺寸
+14h DWORD PointerToRawData; // 在文件中的偏移量
+18h DWORD PointerToRelocations; // 在OBJ文件中使用,重定位的偏移
+1ch DWORD PointerToLinenumbers; // 行号表的偏移(供调试使用地)
+1eh WORD NumberOfRelocations; // 在OBJ文件中使用,重定位项数目
+20h WORD NumberOfLinenumbers; // 行号表中行号的数目
+24h DWORD Characteristics; // 节属性如可读,可写,可执行等
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
评论区