DOS头

struct __IMAGE_DOS_HEADER {
    WORD e_magic; //MZ标记 4D 5A
    WORD e_cblp;
    WORD e_cp;
    WORD e_crlc;
    WORD e_cparhdr;
    WORD e_minalloc;
    WORD e_maxalloc;
    WORD e_ss;
    WORD e_sp;
    WORD e_csum;
    WORD e_ip;
    WORD e_cs;
    WORD e_lfarlc;
    WORD e_ovno;
    WORD e_res[4];
    WORD e_oemid;
    WORD e_oeminfo;
    WORD e_res2[10];
    DWORD e_lfanew; //PE文件真正开始的偏移地址(基于首地址偏移) NT头
};

NT头

struct __IMAGE_NT_HEADERS {
    DWORD Signature; //PE标记 50 45
    __IMAGE_FILE_HEADER FileHeader; //标准PE头
    __IMAGE_OPTIONAL_HEADER OptionalHeader; //可选PE头
};

标准PE头

struct __IMAGE_FILE_HEADER {
    WORD Machine; //程序运行的CPU型号:0x0 任何处理器/0x14C 386及后续处理器
    WORD NumberOfSections; //文件中存在的节的总数 如果要新增节或者合并节 就要修改这个值.
    DWORD TimeDateStamp; //文件创建时的时间戳(和操作系统的创建时间无关),编译器填写的.
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD SizeOfOptionalHeader; //可选PE头的大小,32位PE文件默认E0h 64位PE文件默认为F0h 大小可以自定义.
    WORD Characteristics; //每个位有不同的含义,可执行文件值为10F 即0 1 2 3 8位置1
};

可选PE头

struct __IMAGE_OPTIONAL_HEADER {
    WORD Magic; //10B 32位下的PE文件 20B 64位下的PE文件
    BYTE MajorLinkerVersion;
    BYTE MinorLinkerVersion;
    DWORD SizeOfCode; //所有代码节的和,必须是FileAlignment的整数倍 编译器填的 没用
    DWORD SizeOfInitializedData; //已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用
    DWORD SizeOfUninitializedData; //未初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用
    DWORD AddressOfEntryPoint; //程序入口(在内存中基于基地址偏移)
    DWORD BaseOfCode; //代码开始的基址,编译器填的 没用
    DWORD BaseOfData; //数据开始的基址,编译器填的 没用
    DWORD ImageBase; //内存镜像基址 内存中所有数据开始的地址
    DWORD SectionAlignment; //内存对齐大小
    DWORD FileAlignment; //文件对齐大小
    WORD MajorOperatingSystemVersion;
    WORD MinorOperatingSystemVersion;
    WORD MajorImageVersion;
    WORD MinorImageVersion;
    WORD MajorSubsystemVersion;
    WORD MinorSubsystemVersion;
    DWORD Win32VersionValue;
    DWORD SizeOfImage; //内存中整个PE文件的映射的尺寸(拉伸后的大小),可以比实际的值大,但必须是SectionAlignment的整数倍
    DWORD SizeOfHeaders; //所有头+节表按照文件对齐后的大小 必须是FileAlignment整数倍否则加载会出错
    DWORD CheckSum; //和校验,一些系统文件有要求.用来判断文件是否被修改.
    WORD Subsystem;
    WORD DllCharacteristics;
    DWORD SizeOfStackReserve; //初始化时保留的堆栈大小
    DWORD SizeOfStackCommit; //初始化时实际提交的大小
    DWORD SizeOfHeapReserve; //初始化时保留的堆大小
    DWORD SizeOfHeapCommit; //初始化时实践提交的大小
    DWORD LoaderFlags;
    DWORD NumberOfRvaAndSizes; //目录项数目
    _IMAGE_DATA_DIRECTORY DataDirectory[16];
};

struct __IMAGE_SECTION_HEADER {
    BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //节名称
    union {
        DWORD PhysicalAddress;
        DWORD VirtualSize; //该节数据在内存中运行时的真实大小(未对齐)
    } Misc;
    DWORD VirtualAddress; //该节在内存中的偏移地址
    DWORD SizeOfRawData; //该节数据在硬盘上文件对齐后大小
    DWORD PointerToRawData; //该节在硬盘上文件对齐后偏移首地址
    DWORD PointerToRelocations;
    DWORD PointerToLinenumbers;
    WORD NumberOfRelocations;
    WORD NumberOfLinenumbers;
    DWORD Characteristics; //该节特征属性
};

导出表

struct __IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;    // 未使用,通常为 0
    DWORD   TimeDateStamp;      // 时间戳
    WORD    MajorVersion;       // 主版本号(通常为 0)
    WORD    MinorVersion;       // 次版本号(通常为 0)
    DWORD   Name;               // 模块名称的 RVA地址
    DWORD   Base;               // 导出函数的起始序号
    DWORD   NumberOfFunctions;  // 导出函数的数量
    DWORD   NumberOfNames;      // 按名称导出的函数数量
    DWORD   AddressOfFunctions; // 导出函数地址表的 RVA
    DWORD   AddressOfNames;     // 导出函数名称表的 RVA
    DWORD   AddressOfNameOrdinals; // 导出函数序号表的 RVA
};

重定位表

struct __IMAGE_BASE_RELOCATION {
    DWORD VirtualAddress;    // 重定位块的虚拟地址,基址,块中的偏移加上此基址则定位到需要修改的地方
    DWORD SizeOfBlock;       // 重定位块的大小,单位是字节,通常是 8 的倍数。
};