1. PE文件格式由来
微软在推出PE文件格式之前的操作系统都是用的LE文件格式, 推出PE文件格式是为了让一个程序在所有Windows x86平台通用一个文件格式,这样系统的装载器和编程工具无需对新出的CPU进行重写,在WindowsNT之后就拥有了相同的文件格式。
64位Windows只是对PE进行简单的修饰新格式叫PE32+,没有新的结构增加只是简单的把32位字段扩展为64位
PE文件的框架结构
2.PE文件基本概念
PE文件所有代码与数据都合并在了一起, 组成了一个很大的结构,文件的内容会被区分成不同的区块,每个块都会有自己的内存属性,例如这个这个块师傅包含代码,是否可读或者可写
3.DOS头
DOS头的结构体
typedef struct _IMAGE_DOS_HEADER { // DOS-MZ文件头
WORD e_magic; // DOS 可执行文件的标识符
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; // ChecksumWORD e_ip; // Initial IP valueWORD 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; // PE 签名的文件偏移量
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
WORD 占2个字节 LONG占用4 个字节 142+24+2*10+4=60 字节 但是并不止占60字节,实际上占用64字节,为了内存对齐的目的,_IMAGE_DOS_HEADER的大小会被舍入为下一个最接近的按4字节对齐的值。
DOS头只需要看重两个位置: e_magic DOS头标识 e_lfanew 指向PE文件头位置
左下角的大小的64字节 DOS标识头是 4D 5A 第二个红框 指向PE文件头偏移位置 00 00 00
4.PE文件头
PE签名
PE签名占4个字节 PE文件分为三个部分
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //该结构体中的Signature就是PE签名,标识该文件是否是PE文件。该部分占4字节,即“50 45 0000”。
IMAGE_FILE_HEADER FileHeader; //标准头PE
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //扩展头PE
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
PE签名Signature占4个字节, FileHeader 是PE的标准头20个字节,OptionalHeader 是PE的扩展头 大小不定 。
标准PE头
是PE的标准头20个字节。
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; // 标识目标计算机类型的数字。
WORD NumberOfSections; // 区段数量。
DWORD TimeDateStamp; // 自1970年1月1日00:00起的秒数的低 32 位 (C 运行时time_t值) ,该值指示文件创建时间。
DWORD PointerToSymbolTable; // COFF符号表的文件偏移量,如果没有COFF符号表,则为零。映像的此值应为零,因为 COFF 调试信息已弃用。
DWORD NumberOfSymbols; // 符号表中的条目数。此数据可用于查找紧跟在符号表后面的字符串表。映像的此值应为零,因为 COFF 调试信息已弃用。
WORD SizeOfOptionalHeader; // 可选标头的大小,这是可执行文件所必需的。
WORD Characteristics; // 指示文件属性的标志。
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
主要的四个变量
Machine
说明PE文件只能在哪些CPU类型或模拟指定计算机的系统上运行。
NumberOfSections
区段数量 5 个
SizeOfOptionalHeader
PE可选头的大小 00 E0 十进制就是 224
Characteristics
指示文件属性的标志
0102
然后对照表进行解读
这是一个平台为32位机器,文件可执行
分辨一个程序平台架构可以,综合两个参数来看一个是Machine
字段和SizeOfOptionalHeader
字段
Machine
一般情况下,如果Machine字段的值为0x014C,表示程序是32位的,它适用于x86架构。如果Machine字段的值为0x8664,表示程序是64位的,适用于x64架构。
SizeOfOptionalHeader
PE32是32位的可选头格式,用于支持x86架构的应用程序。它的大小固定为224字节。
PE32+是64位的可选头格式,用于支持x64架构的应用程序。它的大小固定为240字节。
扩展PE头
数据结构
typedef struct _IMAGE_ROM_OPTIONAL_HEADER {
WORD Magic; //标识头 PE32 还是PE32+ 或 ROM文件
BYTE MajorLinkerVersion; //连接器主要版本
BYTE MinorLinkerVersion; //连接器次要版本
DWORD SizeOfCode; //所有文本和代码的总和
DWORD SizeOfInitializedData; //初始化数据部分大小
DWORD SizeOfUninitializedData; //未初始化数据部分大小
DWORD AddressOfEntryPoint; //程序载入内存中的映像基地址地址
DWORD BaseOfCode; //PE载入内存中的相对于模块的基地址偏移
DWORD BaseOfData;
DWORD BaseOfBss;
DWORD GprMask;
DWORD CprMask[4];
DWORD GpValue;
} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER;
Magic | PE格式 |
---|---|
0x10b | PE32 |
0x20b | PE32+ |
0x107 | ROM映像 |
...