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文件格式(文件头)

本文原创,作者:张,其版权均为华盟网所有。如需转载,请注明出处:https://www.77169.net/html/271468.html

发表回复