PE 文件格式详解

PE 文件结构全貌介绍

PE 文件结构全貌

PE 文件结构大致分为四大部分,每部分又可以细分。从数据管理角度来看,PE 文件大致分为两个部分,一是 DOS 头、PE 头和节表属于构成可执行文件的数据管理结构和数据组织结构部分,二是节表数据才是可执行文件真正的数据部分,包含着程序执行时真正的代码、数据、资源等内容。

DOS 头 MZ 头部
DOS 存根
PE 头 PE 标识符(PE\0\0)
文件头
可选头
节表 节表一
节表二
... ...
节表N
节表数据 节表数据一(可能是代码或者数据)
节表数据二(可能是代码或者数据)
... ...
节表数据N(可能是代码或者数据)

PE 结构各部分简介

一、DOS 头

  DOS 头分为“MZ 头部”和“DOS 存根”。MZ 头部才是真正的DOS头部,由于开始处的两个字节为“MZ”,因此 DOS 头也可以叫做 MZ 头。该头部用于程序在 DOS 系统下加载,他的结构被定义为 IMAGE_DOS_HEADER。

  DOS 存根是一段简单的 DOS 程序,主要用于输出类似“This program cannot be run in DOS mode.”的提示字符串。

  DOS 头主要是为了可执行程序可以兼容 DOS 系统。DOS 存根程序可以通过连接参数进行修改,使可执行文件同时在 Windows 和 DOS 系统同时运行。

二、PE 头

  PE 头部保存着 Windows 系统加载可执行文件的重要信息。PE 头部又 IMAGE_NT_HEADERS 定义。IMAGE_NT_HEADERS 是由 IMAGE_NT_SIGNATRUE(宏定义)、IMAGE_FILE_HEADER 和 IMAGE_OPTIONAL_HEADER 多个结构体组成。

  PE 头部在 PE 文件中的位置是不固定的,由 DOS 头部的某个字段给出。

三、节表

  程序的组织按照各属性的不同而保存在不同的节中,在 PE 头部之后就是一个结构体数组构成的节表。节表中描述了各个节在整个文件中的位置与加载入内存后的位置,同时定义了节的属性(只读、可读写、可执行等)。描述节表的结构体是 IMAGE_SECTION_HEADER,如果 PE 文件中有 N 个节,那么节表就是由 N 个 IMAGE_SECTION_HEADER 组成的数组。

四、节数据

  可执行文件中的真正程序代码部分就保存在 PE 结构的节中,当然,数据、资源等内容也保存在节中。节表只是描述了节数据的起始地址、大小及属性等信息。

详解 PE 文件结构

  PSDK(Platform Software Development Kits,平台软件开发包)的头文件 Winnt.h 中包含了 PE 文件结构的定义格式。PE 头文件分为 32 位和 64 位版本。64 位的 PE 结构是对 32 位 PE 结构进行了扩展。

DOS 头部详解 --- IMAGE_DOS_HEADER

  PE 文件的最开始的位置就是一个 DOS 程序。DOS 程序包含了一个 DOS 头部和一个 DOS 程序体( DOS 存根或 DOS 残留)。DOS 头是用来装载 DOS 存根用的。

IMAGE_DOS_HEADER 定义如下:

#define IMAGE_DOS_SIGNATURE 0x5A4D

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
  WORD e_magic;                    // Magic number 幻数(魔法数字)
  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 初始(相对) SS 值
  WORD e_sp;                       // Initial SP value 初始 SP 值
  WORD e_csum;                     // Checksum 校验和
  WORD e_ip;                       // Initial IP value 初始 IP 值
  WORD e_cs;                       // Initial (relative) CS value 初始(相对) CS 值
  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) OEM 标识符(用于 e_oeminfo)
  WORD e_oeminfo;                  // OEM information; e_oemid specific OEM 信息;e_oemid 特定
  WORD e_res2[10];                 // Reserved words 保留字
  LONG e_lfanew;                   // File address of new exe header PE 文件解析时用它找到 PE 头的位置
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; // 结构体大小 64 字节
IMAGE_DOS_HEADER(汇编)
 IMAGE_DOS_SIGNATURE equ 5A4Dh

IMAGE_DOS_HEADER STRUCT
  e_magic           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             WORD   4 dup(?)
  e_oemid           WORD      ?
  e_oeminfo         WORD      ?
  e_res2            WORD  10 dup(?)
  e_lfanew          DWORD      ?
IMAGE_DOS_HEADER ENDS

   该结构体中只需要记住 e_magic 和 e_lfanew 两个字段,e_magic 是 DOS 可执行文件的标识符,e_lfanew 保存着 PE 头的起始位置。

  

 PE 头部详解 --- IMAGE_NT_HEADERS

  PE 头部是真正用来装载 Windows 程序的头部,PE 头的定义为 IMAGE_NT_HEADERS,该结构体包含 PE 标识符、文件头 IMAGE_FILE_HEADER 和可选头 IMAGE_OPTIONAL_HEADER 三部分。IMAGE_NT_HEADERS 是一个宏定义,定义如下:

#ifdef _WIN64
typedef IMAGE_NT_HEADERS64                  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64                 PIMAGE_NT_HEADERS;
#else
typedef IMAGE_NT_HEADERS32                  IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32                 PIMAGE_NT_HEADERS;
#endif

  该头分为 32 位和 64 位,其定义依赖于是否定义了 _WIN64 宏。IMAGE_NT_HEADERS32 的定义如下:

#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
IMAGE_NT_HEADERS(汇编)
IMAGE_NT_SIGNATURE equ 00004550h

IMAGE_NT_HEADERS STRUCT
  Signature         DWORD                   ?
  FileHeader        IMAGE_FILE_HEADER       <>
  OptionalHeader    IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS ENDS

  该结构体的 Signature 就是 PE 标识符,标识该文件是否是 PE 文件。该部分占 4 个字节。该值非常重要,在判断一个文件是否是 PE 文件时,首先要判断文件的起始位置是否为“MZ”,在通过 DOS 头部的相应偏移找到 PE 头部,判断 PE 头部是否为 PE\x00\x00。 

文件头部详解 --- IMAGE_FILE_HEADER

  IMAGE_FILE_HEADER 结构体紧跟在 PE 标识符后面,大小为 20 个字节。IMAGE_FILE_HEADER 定义如下:

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER(汇编)
 IMAGE_FILE_HEADER STRUCT
  Machine               WORD    ?
  NumberOfSections      WORD    ?
  TimeDateStamp         DWORD   ?
  PointerToSymbolTable  DWORD   ?
  NumberOfSymbols       DWORD   ?
  SizeOfOptionalHeader  WORD    ?
  Characteristics       WORD    ?
IMAGE_FILE_HEADER ENDS

  该结构体的各个字段:

  Machine( WORD ):该字段表示可执行文件的目标 CPU 类型。

Machine 的取值
#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_TARGET_HOST       0x0001  // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2  // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE

  NumberOfSections( WORD ):该字段表示  PE 文件的节表数量。

  TimeDataStamp( DWORD ):该字段表示文件是何时被创建的。这个值是自 1970 年 1 月 1 日以来用格林尼威治时间计算的秒数。

  PointerToSymbolTable( DWORD ):该字段表示符号表的偏移量(以字节为单位)或零(如果不存在 COFF 符号表)。

  NumberOfSymbols( DWORD ):该字段表示符号表中的符号数。

  SizeOfOptionalHeader( WORD ):该字段指定 IMAGE_OPTIONAL_HEADER 结构体的大小。PE 文件需要定位节表的位置的时候,计算 IMAGE_OPTIONAL_HEADER 的大小时,应该从 IMAGE_FILE_HEADER 结构体中的 SizeOfOptionalHeader 字段指定的值来获取,而不是 sizeo(IMAGE_OPTIONAL_HEADER)。

  Characteristics( WORD ):该字段指定文件的类型。

Characteristics 的取值
#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file. 从文件中去除了重定位信息。
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved external references). 文件是可执行的(即没有未解析的外部引用)。
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file. COFF行号已从文件中删除。
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file. COFF 符号表条目已从文件中删除。
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Aggressively trim working set 此值已过时。
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses  应用程序可以处理大于 2 GB 的地址。
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed. 此标志已过时。
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine. 计算机支持 32 位字。
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file 调试信息已删除并单独存储在另一个文件中。
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file. 如果映像位于可移动媒体上,请将其复制到交换文件并从交换文件运行它。
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file. 如果映像在网络上,请将其复制到交换文件并从中运行它。
#define IMAGE_FILE_SYSTEM                    0x1000  // System File. 系统文件。
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL. DLL文件.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine 该文件应仅在单处理器计算机上运行。
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed. 此标志已过时。

   

可选头详解 --- IMAGE_OPTIONAL_HEADER

  IMAGE_OPTIONAL_HEADER 虽然叫可选头,但并不表示是可有可无的,是必须存在的头部,该头部的数据目录部分是可选的。可选头是对文件头的一个补充。文件头主要描述文件的相关信息,而可选头主要用来管理 PE 文件被操作系统装载时所需要的信息,该头同样有32 位和 64 位。IMAGE_OPTIONAL_HEADER 是一个宏,定义如下:

#ifdef _WIN64
typedef IMAGE_OPTIONAL_HEADER64             IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64            PIMAGE_OPTIONAL_HEADER;
#define IMAGE_NT_OPTIONAL_HDR_MAGIC         IMAGE_NT_OPTIONAL_HDR64_MAGIC
#else
typedef IMAGE_OPTIONAL_HEADER32             IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32            PIMAGE_OPTIONAL_HEADER;
#define IMAGE_NT_OPTIONAL_HDR_MAGIC         IMAGE_NT_OPTIONAL_HDR32_MAGIC
#endif

  32 位和 64 位的选择是根据是否定义 _WIN64 宏而决定的。在定义中能看到其他几个常量,分别定义如下:

#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b

  IMAGE_OPTIONAL_HEADER32 结构体定义如下:

//
// Optional header format.
//

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    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;
IMAGE_OPTIONAL_HEADER32(汇编)
IMAGE_OPTIONAL_HEADER32 STRUCT
  Magic                         WORD       ?
  MajorLinkerVersion            BYTE       ?
  MinorLinkerVersion            BYTE       ?
  SizeOfCode                    DWORD      ?
  SizeOfInitializedData         DWORD      ?
  SizeOfUninitializedData       DWORD      ?
  AddressOfEntryPoint           DWORD      ?
  BaseOfCode                    DWORD      ?
  BaseOfData                    DWORD      ?
  ImageBase                     DWORD      ?
  SectionAlignment              DWORD      ?
  FileAlignment                 DWORD      ?
  MajorOperatingSystemVersion   WORD       ?
  MinorOperatingSystemVersion   WORD       ?
  MajorImageVersion             WORD       ?
  MinorImageVersion             WORD       ?
  MajorSubsystemVersion         WORD       ?
  MinorSubsystemVersion         WORD       ?
  Win32VersionValue             DWORD      ?
  SizeOfImage                   DWORD      ?
  SizeOfHeaders                 DWORD      ?
  CheckSum                      DWORD      ?
  Subsystem                     WORD       ?
  DllCharacteristics            WORD       ?
  SizeOfStackReserve            DWORD      ?
  SizeOfStackCommit             DWORD      ?
  SizeOfHeapReserve             DWORD      ?
  SizeOfHeapCommit              DWORD      ?
  LoaderFlags                   DWORD      ?
  NumberOfRvaAndSizes           DWORD      ?
  DataDirectory                 IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)
IMAGE_OPTIONAL_HEADER32 ENDS

  该结构体的各个字段:

  Machine:文件的标识。

Machine 的取值
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b    // 32 位可执行文件
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b    // 64 位可执行文件
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107    // ROM 文件

  MajorLinkerVersion:链接器的主要版本号

  MinorLinkerVersion:链接器的次要版本号

  SizeOfCode:代码部分的大小(以字节为单位)或所有此类部分的总和(如果有多个代码) 部分。

  SizeOfInitializedData:初始化的数据部分的大小(以字节为单位)或所有此类部分的总和(如果有多个) 初始化的数据部分。

  SizeOfUninitializedData:未初始化的数据部分的大小(以字节为单位)或所有此类部分的总和(如果有多个) 未初始化的数据部分。

  AddressOfEntryPoint:程序执行的入口地址。该地址是一个相对虚拟地址,简称 EP(EntryPoint),这个值指向了程序第一条要执行的代码。程序如果被加壳后会修改该字段的值,成为壳的入口地址,这样壳就有机会先执行。在脱壳过程中找到了加壳前的入口地址,就说明找到了原始入口点,原始入口点称为 OEP。该字段的地址指向不是 main 函数的地址,也不是 WinMain 函数的地址,而是运行库的启动代码地址。对于 DLL 来说这个值的意义不大,因为 DLL 甚至可以没有 DllMain 函数,没有 DllMain 只是无法捕获装载和卸载 DLL 时的四条消息。如果在  DLL 装载或卸载时没有需要进行处理的事件,可以将 DllMain 函数省略。

  BaseOfCode:代码节的起始相对虚拟地址。

  BaseOfData:数据节的起始相对虚拟地址

  ImageBase:文件被载入内存后第一个字节的首选地址。对于 EXE 文件来说,通常情况下该地址就是装载地址,默认值是 0x00400000;对于 DLL 文件来说,可能就不是装入内存后的地址,默认值是 0x10000000。

  SectionAlignment:节表数据被装入内存后的对齐值,也就是节表数据被映射到内存中需要对齐的单位。在 Win32 下,通常情况下,该值为 0x1000 字节,也就是 4KB 大小。

  FileAlignment:节表数据在文件中的对齐值,通常情况下,该值为 0x1000 字节或 0x200 字节。在文件对齐为 0x1000 字节时,由于与内存对齐值相同,可以加快操作系统对可执行文件装载入内存的速度。而文件对齐值为 0x200 字节时,可以占用相对较少的磁盘空间。0x200 字节是 512 字节,通常磁盘的一个扇区即为 512 字节。

  MajorOperatingSystemVersion:所需操作系统的主版本号

  MinorOperatingSystemVersion:所需操作系统的次要版本号。

  MajorImageVersion:可执行文件的主版本号。

  MinorImageVersion:可执行文件的次要版本号。

  MajorSubsystemVersion:子系统的主要版本号。

  MinorSubsystemVersion:子系统的次要版本号。

  Win32VersionValue:此成员是保留的,必须为 0。

  SizeOfImage:可执行文件装入内存后的总大小。该大小按内存对齐方式对齐。

  SizeOfHeaders:整个 PE 头部的大小。这个 PE 头部指 DOS 头、PE 头、节表的总合大小。该大小按文件对齐方式对齐。

  CheckSum:校验和。对于 EXE 文件通常为 0;对于 SYS 文件(驱动文件、内核文件),则必须有一个校验和。

  Subsystem:可执行文件的子系统类型。

SubSystem 的取值
#define IMAGE_SUBSYSTEM_UNKNOWN              0        // 未知子系统。
#define IMAGE_SUBSYSTEM_NATIVE               1        // 无需子系统(设备驱动程序和本机系统进程)。
#define IMAGE_SUBSYSTEM_WINDOWS_GUI          2        // 窗口图形用户界面 (GUI) 子系统。
#define IMAGE_SUBSYSTEM_WINDOWS_CUI          3        // Windows 控制台 (CUI) 子系统。
#define IMAGE_SUBSYSTEM_OS2_CUI              5        // OS/2 CUI 子系统。
#define IMAGE_SUBSYSTEM_POSIX_CUI            7        // POSIX CUI 子系统。
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8 
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9        // Windows CE系统。
#define IMAGE_SUBSYSTEM_EFI_APPLICATION      10       // 可扩展固件接口 (EFI) 应用程序。
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11   // 具有启动服务的 EFI 驱动程序。
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER   12       // 具有运行时服务的 EFI 驱动程序。
#define IMAGE_SUBSYSTEM_EFI_ROM              13
#define IMAGE_SUBSYSTEM_XBOX                 14       // Xbox 系统。
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16   // 启动应用程序。
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG    17

  DllCharacteristics:指定 DLL 文件的属性。

DllCharacteristics 取值
//      IMAGE_LIBRARY_PROCESS_INIT            0x0001     // Reserved.
//      IMAGE_LIBRARY_PROCESS_TERM            0x0002     // Reserved.
//      IMAGE_LIBRARY_THREAD_INIT             0x0004     // Reserved.
//      IMAGE_LIBRARY_THREAD_TERM             0x0008     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA    0x0020  // 具有 64 位地址空间的 ASLR。
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040     // DLL可以在加载时重定位。
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY    0x0080     // 强制进行代码完整性校验
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT    0x0100     // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200     // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH       0x0400     // Image does not use SEH.  No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND      0x0800     // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000     // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER   0x2000     // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF     0x4000     // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000

  SizeOfStackReserve:为线程保留的栈大小,以字节为单位。

  SizeOfStackCommit: 为线程已提交的栈大小,以字节为单位。

  SizeOfHeapReserve:为线程保留的堆大小。

   SizeOfHeapCommit:为线程提交的堆大小。

  LoaderFlags:保留字段,必须为 0。

  NumberOfRvaAndSizes:数据目录项的个数。#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

  DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:数据目录表,由 NumberOfRvaAndSizes 个 IMAGE_DATA_DIRECTORY 结构体组成的数组。该数组包含输入表、输出表、资源、重定位等数据目录项的 RVA(相对虚拟地址)和大小。IMAGE_DATA_DIRECTORY 结构体定义如下:

//
// Directory format.
//

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;        // 实际上数据目录的 RVA
    DWORD   Size;                  // 数据目录项的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
IMAGE_DATA_DIRECTORY(汇编)
 IMAGE_DATA_DIRECTORY STRUCT
  VirtualAddress    DWORD      ?
  isize             DWORD      ?
IMAGE_DATA_DIRECTORY ENDS
数据目录中的成员在数组中的索引
// Directory Entries

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // 导出表
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // 导入表
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // 资源
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // 重定位
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // 导入地址表
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

节表详解 --- IMAGE_SECTION_HEADER

  节表的位置在 IMAGE_OPTIONAL_HEADER 结构体后面,节表中的每个 IMAGE_SECTION_HEADER 中都存放着可执行文件被映射到内存中所在位置的信息,节的个数由 IMAGE_FILE_HEADER 中的 NumberOfSections 给出。IMAGE_SECTION_HEADER 的大小为 40 字节,IMAGE_SECTION_HEADER 定义如下:

//
// Section header format.
//

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef 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;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

#define IMAGE_SIZEOF_SECTION_HEADER          40
IMAGE_SECTION_HEADER(汇编)
 IMAGE_SECTION_HEADER STRUCT
    Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)
    union Misc
        PhysicalAddress dd  ?
        VirtualSize dd      ?
    ends
    VirtualAddress dd       ?
    SizeOfRawData dd        ?
    PointerToRawData dd     ?
    PointerToRelocations dd ?
    PointerToLinenumbers dd ?
    NumberOfRelocations dw  ?
    NumberOfLinenumbers dw  ?
    Characteristics dd      ?
IMAGE_SECTION_HEADER ENDS

  该结构体的各个字段:

  Name[IMAGE_SIZEOF_SHORT_NAME]:一个 8 字节、NULL 填充的 UTF-8 字符串。多余字节会被自动截断。

  Misc.PhysicalAddress:文件地址。

  Misc.VirtualSize:加载到内存中的节的总大小(以字节为单位)。如果此值大于 SizeOfRawData 成员,则该节将用零填充。此字段仅对可执行映像有效,对于目标文件应设置为 0。

  VirtualAddress:节区数据装入内存后的相对虚拟地址,这个地址是按内存对齐的,该地址加上 IMAGE_OPTIONAL_HEADER 结构体中的 ImageBase 才是内存中的虚拟地址。

  SizeOfRawData:节区数据在磁盘上的大小,该值是按照文件对齐进行对齐后的值,但是也有例外。

  PointerToRawData:节区在磁盘文件上的偏移地址。

  PointerToRelocations:A file pointer to the beginning of the relocation entries for the section. If there are no relocations, this value is zero.

  PointerToLinenumbers:A file pointer to the beginning of the line-number entries for the section. If there are no COFF line numbers, this value is zero.

  NumberOfRelocations:The number of relocation entries for the section. This value is zero for executable images.

  NumberOfLinenumbers:The number of line-number entries for the section.

  Characteristics:节区的属性。

Characteristics 取值
//
// Section characteristics.
//
//      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
//      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.
//      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.
//      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.
//      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.

#define IMAGE_SCN_CNT_CODE                   0x00000020  // 部分包含代码。
#define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // 部分包含初始化的数据。
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // 部分包含未初始化的数据。

#define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.
#define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.
//      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.
#define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.
//                                           0x00002000  // Reserved.
//      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA                0x00008000
//      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000
#define IMAGE_SCN_MEM_PURGEABLE              0x00020000
#define IMAGE_SCN_MEM_16BIT                  0x00020000
#define IMAGE_SCN_MEM_LOCKED                 0x00040000
#define IMAGE_SCN_MEM_PRELOAD                0x00080000

#define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //
#define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //
#define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //
#define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //
#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //
#define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //
#define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //
#define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //
#define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //
#define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //
#define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //
#define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //
#define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //
// Unused                                    0x00F00000
#define IMAGE_SCN_ALIGN_MASK                 0x00F00000

#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // 部分包含扩展的重定位。
#define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // 节可以被丢弃。
#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // 节不可缓存。
#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // 节是不可分页的。
#define IMAGE_SCN_MEM_SHARED                 0x10000000  // 节是可共享的。
#define IMAGE_SCN_MEM_EXECUTE                0x20000000  // 节是可执行的。
#define IMAGE_SCN_MEM_READ                   0x40000000  // 节是可读的。
#define IMAGE_SCN_MEM_WRITE                  0x80000000  // 节是可写的。

  

 

posted @ 2023-02-03 16:42  liert  阅读(606)  评论(0编辑  收藏  举报