PE文件格式(文件头)

  • A+
所属分类:逆向工程

PE文件格式(文件头)

PE文件是Windows操作系统下使用的可执行文件的格式,可执行系列:EXE、SCR,库系列:DLL、OCX、CPL、DRV,驱动程序:SYS、VXD 等都是PE文件


在Windows系统中,PE文件被系统加载器映射到内存中,每一个程序都有自己的虚拟空间,这个虚拟空间的内存地址称为虚拟地址(Virtual AddressVA)


相对虚拟地址(Relative Virtual AddressRVA)是一个简单的,相对于PE文件载入地址的偏移位置,它是一个相对的地址(偏移)

当PE文件在磁盘中时,某个数据位置相对于文件头的偏移量称为文件偏移地址(File Offset)

所有PE文件以64字节DOS头开始,DOS头只是为了兼容早期操作系统

PE文件格式(文件头) 

e_magic:0x5A4D,MZ标志


e_lfanew:0x000000E8,NT头偏移量

PE文件格式(文件头) 

#define IMAGE_DOS_SIGNATURE         0x5A4D      // MZ

这里采用的小端序存储数据,地址高位存储数据的高位,地址低位存储数据的低位,是一种逆序存储方式

000000E8就是NT头的位置,与DOS头之间隔了一段DosStub数据,这个数据是可变的,所以需要e_lfanew来指定NT头的位置

PE文件格式(文件头) 

NT头定义如下

typedef struct _IMAGE_NT_HEADERS {    DWORD Signature;        // PE标识    IMAGE_FILE_HEADER FileHeader;        //文件头    IMAGE_OPTIONAL_HEADER32 OptionalHeader;        //可选头} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
Signature类型为DWORD,占用4个字节#define IMAGE_NT_SIGNATURE           0x00004550   // PE00


PE文件格式(文件头) 

文件头是表示文件大致属性的IMAGE_FILE_HEADER结构体

typedef struct _IMAGE_FILE_HEADER {    WORD    Machine;        // 2个字节,指明支持的CPU类型    WORD    NumberOfSections;        // 2个字节,指明节区数量    DWORD   TimeDateStamp;                // 4字节,编译器生成这个PE文件的时间    DWORD   PointerToSymbolTable;        // 4字节,调试符号相关,不作研究    DWORD   NumberOfSymbols;        // 4字节,调试符号相关,不作研究    WORD    SizeOfOptionalHeader;        // 2个字节,指明可选头 IMAGE_OPTIONAL_HEADER32 大小    WORD    Characteristics;        // 2个字节,表明文件属性,如DLL文件,SYS文件等} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

IMAGE_OPTIONAL_HEADER32是PE头结构体中最大的,定义如下
typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. //
WORD Magic; // 普通可执行文件为0x010B,PE32 (64位)值为0x020B BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; // 代码区块的大小,通常是.text区块大小 DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; // 程序入口点,RVA值 DWORD BaseOfCode; // 代码段的起始地址,RVA值,通常是.text区块的起始RVA DWORD BaseOfData; // 数据段的起始地址,RVA值,通常是.data区块的起始RVA
// // NT additional fields. //
DWORD ImageBase; // PE文件在内存中首选的装载基地址 DWORD SectionAlignment; // PE文件装载到内存时区块的对齐大小,假设.text区块的大小为0x7748,而SectionAlignment的大小为0x1000,那么对齐后的大小为0x8000字节 DWORD FileAlignment; // 磁盘上PE文件中区块的对齐大小,对齐方式类似SectionAlignment WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; // PE文件被装载到内存空间后总的大小,指从ImageBase到最后一个区块的大小 DWORD SizeOfHeaders; // Dos头、DosStub、PE头以及区块头的总大小,并进行FileAlignment对齐后的大小 DWORD CheckSum; // 校验和,一般的EXE文件通常为0,判断文件是否被修改 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;


写一个程序,关掉随机基址

PE文件格式(文件头) 

PE文件格式(文件头) 

AddressOfEntryPoint是一个RVA值,所以当程序实际被加载到内存时,对应的入口点地址的虚拟地址

(VA) = ImageBase+AddressOfEntryPoint = 0x00400000+0x000012DA = 0x004012DA

PE文件格式(文件头) 

子系统查看

PE文件格式(文件头) 

SizeOfImage验证

DWORD   SizeOfImage;     

 // PE文件被装载到内存空间后总的大小,指从ImageBase到最后一个区块的大小

PE文件格式(文件头) 

PE文件格式(文件头) 

OPTIONAL_HEADER末尾是一个数据目录表数组,数组元素个数为16

各元素对应表项:


PE文件格式(文件头) 

IMAGE_DATA_DIRECTORY定义如下:

typedef struct _IMAGE_DATA_DIRECTORY {    DWORD   VirtualAddress;        // 数据块的起始RVA地址    DWORD   Size;                // 数据块的长度} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;


PE文件格式(文件头) 

PE文件格式(文件头) 

PE文件格式(文件头)

PE文件格式(文件头)

PE文件格式(文件头)

PE文件格式(文件头)

本文始发于微信公众号(黑白之道):PE文件格式(文件头)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: