PE结构总导航

PE结构

  • PE文件的数据结构大部分都定义在VC98IncludeWINNT.H这个文件里。

MS-DOS 文件头

  • IMAGE_DOS_HEADER,一共64字节。
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
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   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;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
  • 各个域的说明
e_magic; // 魔术数字	5A 4D
e_cblp; // 文件最后页的字节数	00 90
e_cp; // 文件页数	00 03
e_crlc; // 重定义元素个数	00 00
e_cparhdr; // 头部尺寸,以段落为单位 00 04
e_minalloc; // 所需的最小附加段	00 00
e_maxalloc; // 所需的最大附加段	FF FF
e_ss; // 初始的 SS 值(相对偏移量) 00 00
e_sp; // 初始的 SP 值 00 B8
e_csum; // 校验和 00 00
e_ip; // 初始的 IP 值	00 00
e_cs; // 初始的 CS 值(相对偏移量) 00 00
e_lfarlc; // 重分配表文件地址	00 40
e_ovno; // 覆盖号 00 00
e_res[4]; // 保留字	00 00 00 00 00 00 00 00
e_oemid; // OEM 标识符(相对 e_oeminfo)	00 00
e_oeminfo; // OEM 信息	00 00
e_res2[10]; // 保留字	 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00  00 00 00 00
e_lfanew; // 新 exe 头部的文件地址 00 00 00 D8
  • 重要的有两个域, e_magic 和 e_lfanew。e_lfanew 域保存的是真正的 PE 文件头的偏移,
    e_magic 域需要被设置成 5A4D,也被定义为IMAGE_DOS_SIGNATURE。
4D 5A 90 00  03 00 00 00  04 00 00 00  FF FF 00 00
B8 00 00 00  00 00 00 00  40 00 00 00  00 00 00 00
00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
00 00 00 00  00 00 00 00  00 00 00 00  D8 00 00 00
  • 从上面可以看出来e_lfanew的值为0x00 00 00 D8,所以PE 文件头的偏移为D8。

MS-DOS STUB

  • 从e_lfanew末尾到0x000000D8中间这一段是MS-DOS STUB,修改这部分程序不会报错,所以能提供少许空间存储其他猥琐的东西。长度:dosHeader->elfnew减掉dosHeader 长度。这个程序为152字节。
0E 1F BA 0E  00 B4 09 CD  21 B8 01 4C  CD 21 54 68
69 73 20 70  72 6F 67 72  61 6D 20 63  61 6E 6E 6F
74 20 62 65  20 72 75 6E  20 69 6E 20  44 4F 53 20
6D 6F 64 65  2E 0D 0D 0A  24 00 00 00  00 00 00 00
7E F3 5B 15  3A 92 35 46  3A 92 35 46  3A 92 35 46
B9 8E 3B 46  34 92 35 46  0C B4 3F 46  02 92 35 46
3A 92 34 46  09 92 35 46  58 8D 26 46  39 92 35 46
0C B4 3E 46  38 92 35 46  52 69 63 68  3A 92 35 46
00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
00 00 00 00  00 00 00 00  

IMAGE_NT_HEADERS 文件头

  • IMAGE_NT_HEADERS
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;	//PE文件标志
    IMAGE_FILE_HEADER FileHeader;	//PE文件头
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;//PE文件可选头部
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

IMAGE_FILE_HEADER

  • PE文件头格式,20个字节。
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;
大小 描述
WORD Machine 目标平台 CPU 的类型。常用的值有:
IMAGE_FILE_MACHINE_I386 0x014c // Intel 386
IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
WORD NumberOfSections 指示节表中节的数目。节表紧跟着 IMAGE_NT_HEADERS 结构
DWORD TimeDateStamp 时间戳
DWORD PointerToSymbolTable 指针到符号表
DWORD NumberOfSymbols 符号表中的符号数
WORD SizeOfOptionalHeader IMAGE_FILE_HEADER 结构后面的可选数据的大小
WORD Characteristics 指示文件属性的一组位标志

PE文件头Characteristics

  • Characteristics文件属性标志,在WINNT.H中定义。
#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#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.
#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.
  • Characteristics各个标志的说明
数据位 标志 描述 标志值
0 IMAGE_FILE_RELOCS_STRIPPED 重定位信息已经从文件中移除。 0x0001
1 IMAGE_FILE_EXECUTABLE_IMAGE 文件是可执行映像。 0x0002
2 IMAGE_FILE_LINE_NUMS_STRIPPED 行号被移去 0x0004
3 IMAGE_FILE_LOCAL_SYMS_STRIPPED 符号被移去 0x0008
4 IMAGE_FILE_AGGRESSIVE_WS_TRIM 让操作系统尽量减小工作集(working set) 0x0010
5 IMAGE_FILE_LARGE_ADDRESS_AWARE 此应用程序可以处理大于2GB 的地址 0x0020
6 系统保留
7 IMAGE_FILE_BYTES_REVERSED_LO 处理机的低位字节是相反的 0x0080
8 IMAGE_FILE_32BIT_MACHINE 需要字长为32 位的机器 0x0100
9 IMAGE_FILE_DEBUG_STRIPPED 调试信息已经被移到DBG文件中 0x0200
A IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 如果可执行映像在可移动媒体上,把它复制到交换文件中并从交换文件中运行。 0x0400
B IMAGE_FILE_NET_RUN_FROM_SWAP 如果可执行映像在网络上,把它复制到交换文件中并从交换文件中运行。 0x0800
C IMAGE_FILE_SYSTEM 系统文件 0x1000
D IMAGE_FILE_DLL 文件是DLL 0x2000
E IMAGE_FILE_UP_SYSTEM_ONLY 只能运行于单处理器机器上 0x4000
F IMAGE_FILE_BYTES_REVERSED_HI 处理机的高位字节是相反的 0x8000

IMAGE_OPTIONAL_HEADER

  • PE文件可选头部
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_HEADER各个域描述
大小 英文名 中文名 描述
WORD Magic 魔数 一个特征字,用于表明文件头的类型。两个常用的值为:
IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
BYTE MajorLinkerVersion 链接器的主版本号 用于创建这个可执行文件的链接器的主版本号。
BYTE MinorLinkerVersion 链接器的次版本号 用于创建这个可执行文件的链接器的次版本号
DWORD SizeOfCode 代码节大小 带有 IMAGE_SCN_CNT_CODE 属性的所有节的总大小,一般放在“.text”节里。如果有多个代码节的话,它是所有代码节的和。必须是FileAlignment的整数倍,是在文件里的大小。
DWORD SizeOfInitializedData 已初始化数大小 所有由已初始化的数据组成的节的总大小,一般放在“.data”节里。如果有多个这样的节话,它是所有这些节的和。必须是FileAlignment的整数倍,是在文件里的大小。
DWORD SizeOfUninitializedData 未初始化数大小 所有由未初始化的数据组成的节的总大小,它通常是 0,因为链接器经常把未初始化的数据添加到正常的数据节的末尾。一般在“.bss”节里。如果有多个这样的节话,它是所有这些节的和。必须是FileAlignment的整数倍,是在文件里的大小。
DWORD AddressOfEntryPoint 入口点 文件中首先被执行的代码的第一个字节的 RVA。对于 DLL来说,入口点在进程初始化和退出期间,以及线程创建和退出期间都会被调用。在大多数可执行文件中,这个地址并不是直接指向 main、WinMain 或者 DllMain,而是指向调用上述函数的运行时库代码。对于 DLL 来说,这个域可以设为 0,这样它就接收不到前面说的四个通知。/NOENTRY链接器选项可以将这个域设置为 0
DWORD BaseOfCode 代码基址 当镜像被加载进内存时代码节的开头RVA。必须是SectionAlignment的整数倍。
DWORD BaseOfData 数据基址 当镜像被加载进内存时数据节的开头RVA。(在64位文件中此处被并入紧随其后的ImageBase中。)必须是SectionAlignment的整数倍。
DWORD ImageBase 镜像基址 当加载进内存时镜像的第1个字节的首选地址。它必须是64K的倍数。DLL默认是10000000H。Windows CE 的EXE默认是00010000H。Windows 系列的EXE默认是00400000H。
DWORD SectionAlignment 内存对齐 当加载进内存时节的对齐值(以字节计)。它必须≥FileAlignment。默认是相应系统的页面大小。
DWORD FileAlignment 文件对齐 用来对齐镜像文件的节中的原始数据的对齐因子(以字节计)。它应该是界于512和64K之间的2的幂(包括这两个边界值)。默认是512。如果SectionAlignment小于相应系统的页面大小,那么FileAlignment必须与SectionAlignment相等。
WORD MajorOperatingSystemVersion 主系统的主版本号 所需的操作系统的主版本号。随着众多版本 Windows 的到来,这个域已失去了它最初的意义。
WORD MinorOperatingSystemVersion 主系统的次版本号 所需的操作系统的次版本号。
WORD MajorImageVersion 镜像的主版本号 此文件的主版本号。系统并未使用这个域,可以设置为 0。
使用/VERSION 链接器选项可以设定这个域的值。
WORD MinorImageVersion 镜像的次版本号 此文件的次版本号。
WORD MajorSubsystemVersion 子系统的主版本号 可执行文件所需的子系统的主版本号。以前相对于旧版本的 Windows NT 界面来说,用它来指明需要新的 Windows 95或 Windows NT 4.0 用户界面。现在由于 Windows 版本繁多,这个域已经不使用了,通常被设为 4。使用链接器选项/SUBSYSTEM 可以设置这个域的值。
WORD MinorSubsystemVersion 子系统的次版本号 可执行文件所需的子系统的次版本号。
DWORD Win32VersionValue 保留,必须为0 一个从来不用的域,通常设为 0。
DWORD SizeOfImage 镜像大小 SizeOfImage 包含了假设存在于最后一个节之后的那个节的 RVA。这等效于把此文件加载进内存时系统需要保留的内存数量。当镜像被加载进内存时的大小,包括所有的文件头。向上舍入为SectionAlignment的倍数。
DWORD SizeOfHeaders 头大小 MS-DOS 文件头、PE 文件头和节表的总大小。在 PE 文件中,这些内容出现于任何代码或数据节之前。这个域的值被向上舍入到文件对齐值的倍数,可以以此值作为PE文件第一节的文件偏移量。
DWORD CheckSum 校验和 镜像文件的校验和。计算校验和的算法被合并到了Imagehlp.DLL 中。以下程序在加载时被校验以确定其是否合法:所有的驱动程序、任何在引导时被加载的DLL以及加载进关键Windows进程中的DLL。
WORD Subsystem 子系统类型 运行此镜像所需的子系统。MAGE_SUBSYSTEM_NATIVE
// 不需要子系统
IMAGE_SUBSYSTEM_WINDOWS_GUI
// 使用 Windows GUI
IMAGE_SUBSYSTEM_WINDOWS_CUI
// 控制台应用程序。当它运行时,操作系统为其创一
// 个控制台并提供 stdin、stdout 和 stderr 文件句柄。
WORD DllCharacteristics DLL标识 指示 DLL 特征的标志。这些值对应于 WINNT.H 文件中的IMAGE_DLLCHARACTERISTICS_xxx 定义。当前值如下:
IMAGE_DLLCHARACTERISTICS_NO_BIND
// 不绑定映像
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
// 使用 WDM 模型的驱动程序
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
// 当终端服务器加载一个并没有准备运行于终端服务
// 器上的应用程序时,它同时加载包含兼容代码的 DLL
DWORD SizeOfStackReserve 堆栈保留大小 最大大小。CPU的堆栈。默认是1MB。
DWORD SizeOfStackCommit 堆栈提交大小 初始提交的堆栈大小。默认是4KB。
DWORD SizeOfHeapReserve 堆保留大小 最大大小。编译器分配的。默认是1MB。
DWORD SizeOfHeapCommit 堆栈交大小 初始提交的局部堆空间大小。默认是4KB。
DWORD LoaderFlags 保留,必须为0 此域已经废弃不用。
DWORD NumberOfRvaAndSizes 目录项数目 在 IMAGE_NT_HEADERS 结构末尾处是一个IMAGE_DATA_DIRECTORY 结构数组。这个域包含了这个数组的元素数目。由于以前发行的 Windows NT 的原因,它被设置为 16。
IMAGE_DATA_DIRECTORY
32位系统中扩展头大小一般是224(0x00E0),在64位系统中一般是240(0x00F0)。
DataDirectory[16] IMAGE_DATA_DIRECTORY 结构数组。每个结构包含可执行文件中一些重要部分(例如导入表、导出表以及资源等)的RVA 和大小。

DataDirectory

  • 数据目录表示文件中其它可执行信息重要组成部分的位置。当前的 PE 文件格式定义了 16 种可能的数据目录,如导出表、导入表、资源、重定位表等。
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
数组编号 Description 描述
0 Export table address and size 导入表地址和大小
1 Import table address and size 导出表地址和大小
2 Resource table address and size 资源表地址和大小
3 Exception table address and size 异常表地址和大小
4 Certificate table address and size 证书表数据地址和大小
5 Base relocation table address and size 基地址重定位表地址和大小
6 Debugging information starting address and size 调试信息起始地址和大小
7 Architecture-specific data address and size 体系结构
8 Global pointer register relative virtual address 指向全局指针寄存器的值
9 Thread local storage (TLS) table address and size 线程局部存储表地址和大小
A Load configuration table address and size 加载配置表地址和大小
B Bound import table address and size 绑定导入表地址和大小
C Import address table address and size 导入函数地址表
D Delay import descriptor address and size 延时导入表地址和大小
E CLR Runtime Header CLR运行时头部的地址和大小。(已废除)
F Reserved 系统保留

IMAGE_DIRECTORY_ENTRY_EXPORT

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
  • 导出表域描述
大小 描述
DWORD Characteristics 导出标志。当前未定义任何值。
DWORD Time/Date Stamp 导出函数被创建的日期和时间。这个值与NT头的第一部分TimeDateStamp相同。
WORD Major Version 导出数据的主版本号。未用,设置为 0。
WORD Minor Version 导出数据的次版本号。未用,设置为 0。
DWORD Name 与导出符号相关的 DLL 的名称 ASCII 字符串的 RVA。以一个NULL字节结尾。
DWORD Base 这个域包含了这个可执行文件的导出符号所使用的序数值的起始值。它通常被设置为1。
DWORD NumberOfFunctions 导出函数中所有元素的数目。
DWORD NumberOfNames 导出名称指针表中元素的数目。它同时也是导出序数表中元素的数目。
DWORD AddressOfFunctions 导出地址表RVA。
DWORD AddressOfNames 导出名称指针表RVA。
DWORD AddressOfNameOrdinals 导出序数表RVA。

IMAGE_DIRECTORY_ENTRY_IMPORT

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    };
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                           									 // -1 if bound, and real date	ime stamp
                                            								//     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                           									 // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
  • 导入表域描述
大小 描述
DWORD OriginalFirstThunk 这个域的命名太不恰当。它包含导入名称表的 RVA。导入名称表是一个IMAGE_THUNK_DATA 结构数组。这个域被设置为 0 表示IMAGE_IMPORT_DESCRIPTOR 结构数组的结尾。
DWORD TimeDateStamp 当镜像与相应的DLL绑定之后,这个域被设置为这个DLL的日期/时间戳。
DWORD ForwarderChain 这是首个转发的函数的索引。如果没有转发的函数,这个域被设置为-1。它仅用于老的绑定类型,因为那种绑定类型不能很有效地处理转发的函数。
DWORD Name 导入的 DLL 名称字符串(ASCII 码格式)的 RVA。
DWORD FirstThunk 导入地址表的 RVA。IAT 是一个 IMAGE_THUNK_DATA 结构数组。

IMAGE_DIRECTORY_ENTRY_RESOURCE

typedef struct _IMAGE_RESOURCE_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    WORD    NumberOfNamedEntries;
    WORD    NumberOfIdEntries;
//  IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
  • 资源表
描述
Characteristics 理论上这个域可能是资源的标志,但它好像总是 0。
TimeDateStamp 指示资源创建日期的日期/时间戳。
MajorVersion 理论上这些域应该保存资源的主版本号,但它们好像总是 0。
MinorVersion 理论上这些域应该保存资源的次版本号,但它们好像总是 0。
NumberOfNamedEntries 本结构后面使用名称的数组元素的个数。
NumberOfIdEntries 本结构后面使用整数 ID 的数组元素的个数。
DirectoryEntries[] 这个域实际上并不是 IMAGE_RESOURCE_DIRECTORY 结构的一部分。它是紧跟在IMAGE_RESOURCE_DIRECTORY 结构后面的类型为 IMAGE_RESOURCE_DIRECTORY_ENTRY 结构的数组。这个数组中的元素数目是 NumberOfNamedEntries 和 NumberOfIdEntries 这两个域的和。用名称作为标识的元素(而不是用整数 ID)在这个数组的前面一部分。
IMAGE_RESOURCE_DIRECTORY_ENTRY
描述
Name 这个域或者是一个整数 ID,或者是指向一个包含字符串名称的结构的指针。如果最高位(0x80000000)是 0,那么这个域就被解释为一个整数 ID。如果最高位非 0,那么它的低 31 位是一个 IMAGE_RESOURCE_DIR_STRING_U 结构的偏移地址(相对于资源的开头)。IMAGE_RESOURCE_DIR_STRING_U 结构由一个保存字符个数的 WORD 类型的值和它后面的一个表示资源名称的 UNICODE 字符串组成。是的,即使 PE 文件打算用在非UNICODE 的 Win32 系统上,这里也使用 UNICODE。要把一个 UNICODE 字符串转换成 ANSI字符串,可以使用 WideCharToMultiByte 函数。
OffsetToData 这个域或者是另一个资源目录的偏移,或者是一个指向有关特定资源实例的信息的指针。如果最高位(0x80000000)置位,那么这个目录项引用的是一个子目录。它的低31 位是另一个 IMAGE_RESOURCE_DIRECTORY 结构的偏移地址(相对于资源的开头)。如果最高位没有置位,那么低 31 位指向一个 IMAGE_RESOURCE_DATA_ENTRY 结构。IMAGE_RESOURCE_DATA_ENTRY 结构包含了资源的原始数据的位置、它的大小和它的代码页的信息。

IMAGE_DIRECTORY_ENTRY_EXCEPTION

//
// Function table entry format for IA64 images.  Function table is
// pointed to by the IMAGE_DIRECTORY_ENTRY_EXCEPTION directory entry.
// This definition duplicates the one in ntia64.h for use by portable
// image file mungers.
//

typedef struct _IMAGE_IA64_RUNTIME_FUNCTION_ENTRY {
    DWORD BeginAddress;
    DWORD EndAddress;
    DWORD UnwindInfoAddress;
} IMAGE_IA64_RUNTIME_FUNCTION_ENTRY, *PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY;
  • 异常表是一个由IMAGE_RUNTIME_FUNCTION_ENTRY 结构组成的数组。

IMAGE_DIRECTORY_ENTRY_SECURITY

typedef struct _WIN_CERTIFICATE {
    DWORD       dwLength;
    WORD        wRevision;
    WORD        wCertificateType;   // WIN_CERT_TYPE_xxx
    BYTE        bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
  • Security Directory
  • 与数字签名有关
描述
dwLength 此结构体的长度
wRevision 在bCertificate里面保护的证书的版本号
wCertificateType 证书类型
bCertificate 包含一个或多个证书,一般来说这个证书的内容一直到安全表的末尾。
wCertificateType
信息 Win32 SDK中的宏定义名
0x0001 X.509证书 WIN_CERT_TYPE_X509
0x0002 包含PKCS#7的SignedData的结构 WIN_CERT_TYPE_PKCS_SIGNED_DATA
0x0003 保留 WIN_CERT_TYPE_RESERVED_1
0x0004 终端服务器协议堆栈证书签名 WIN_CERT_TYPE_TS_STACK_SIGNED

IMAGE_DIRECTORY_ENTRY_BASERELOC

//
// Based relocation format.
//

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
  • 基址重定位域描述
描述
VirtualAddress 重定位块RVA。
SizeOfBlock 重定位块中重定位表项数量。

IMAGE_DIRECTORY_ENTRY_DEBUG

//
// Debug Format
//

typedef struct _IMAGE_DEBUG_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Type;
    DWORD   SizeOfData;
    DWORD   AddressOfRawData;
    DWORD   PointerToRawData;
} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;
  • 调试域描述
描述
Characteristics 未用,设置为 0。
TimeDateStamp 调试信息的日期/时间戳。
MajorVersion 调试信息的主版本号,未用。
MinorVersion 调试信息的次版本号,未用。
Type 调试信息的类型。以下是经常遇到的类型:
IMAGE_DEBUG_TYPE_COFF
IMAGE_DEBUG_TYPE_CODEVIEW // 包含 PDB 文件
IMAGE_DEBUG_TYPE_FPO // 帧指针省略
IMAGE_DEBUG_TYPE_MISC // IMAGE_DEBUG_MISC
IMAGE_DEBUG_TYPE_OMAP_TO_SRC
IMAGE_DEBUG_TYPE_OMAP_FROM_SRC
IMAGE_DEBUG_TYPE_BORLAND
// Borland 格式
SizeOfData 文件中调试数据的大小。不包括外部调试文件(例如.PDB 文件)的大小。
AddressOfRawData 当映射进内存时调试数据的 RVA。如果调试信息不被映射,它被设置为 0。
PointerToRawData 调试数据的文件偏移(不是 RVA)。

IMAGE_DIRECTORY_ENTRY_COPYRIGHT

struct _IMAGE_DATA_DIRECTORY {
0x00 DWORD VirtualAddress;
0x04 DWORD Size;
};
  • 版权信息是保留表,必须为0。

IMAGE_DIRECTORY_ENTRY_ARCHITECTURE

struct _IMAGE_DATA_DIRECTORY {
0x00 DWORD VirtualAddress;
0x04 DWORD Size;
};
  • 体系结构信息

IMAGE_DIRECTORY_ENTRY_GLOBALPTR

struct _IMAGE_DATA_DIRECTORY {
0x00 DWORD VirtualAddress;
0x04 DWORD Size;
};
  • Global Ptr数据描述的是被存储在全局指针寄存器中的一个值。

IMAGE_DIRECTORY_ENTRY_TLS

//
// Thread Local Storage
//

typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
    PVOID DllHandle,
    DWORD Reason,
    PVOID Reserved
    );

typedef struct _IMAGE_TLS_DIRECTORY32 {
    DWORD   StartAddressOfRawData;
    DWORD   EndAddressOfRawData;
    PDWORD  AddressOfIndex;
    PIMAGE_TLS_CALLBACK *AddressOfCallBacks;
    DWORD   SizeOfZeroFill;
    DWORD   Characteristics;
} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;
  • 线程局部存储
描述
StartAddressOfRawData 用于在内存中初始化新线程的 TLS 数据的一段内存的起始地址。
EndAddressOfRawData 用于在内存中初始化新线程的 TLS 数据的一段内存的结束地址。
AddressOfIndex 当可执行文件被加载进内存时,如果它包含.tls 节,加载器调用TlsAlloc 给它分配一个 TLS 句柄,并将分配的句柄保存在这个域指定的位置处。运行时库使用这个句柄定位线程局部数据。
AddressOfCallBacks 由 PIMAGE_TLS_CALLBACK 类型的函数指针组成的数组的地址。当创建或撤销线程时,这个列表中的每个函数都会被调用。最后一个元素的值为 0,它标志着表的结尾。一般由 Visual C++生成的可执行文件中这个表是空的。
SizeOfZeroFill 已初始化数据中除了由 StartAddressOfRawData 和EndAddressOfRawData 域组成的已初始化数据界限之外的大小(以字节计)。所有超出这个范围的用于单个线程的数据都被初始化为 0。
Characteristics 保留,当前被设置为 0。

IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG

//
// Load Configuration Directory Entry
//

typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   GlobalFlagsClear;
    DWORD   GlobalFlagsSet;
    DWORD   CriticalSectionDefaultTimeout;
    DWORD   DeCommitFreeBlockThreshold;
    DWORD   DeCommitTotalFreeThreshold;
    PVOID   LockPrefixTable;
    DWORD   MaximumAllocationSize;
    DWORD   VirtualMemoryThreshold;
    DWORD   ProcessHeapFlags;
    DWORD   ProcessAffinityMask;
    WORD    CSDVersion;
    WORD    Reserved1;
    PVOID   EditList;
    DWORD   Reserved[ 1 ];
} IMAGE_LOAD_CONFIG_DIRECTORY, *PIMAGE_LOAD_CONFIG_DIRECTORY;
  • 加载配置信息域描述
描述
Characteristics 标志字节,用来显示文件的属性,通常为0。如果存在加载配置信息,则大部分情况下被设置为48h。
TimeDateStamp 时间戳。
MajorVersion 主版本。
MinorVersion 次版本。
GlobalFlagsClear 当PE加载器加载该映像时需要清除的全局标志。
GlobalFlagsSet PE加载器加载该映像时需要设置的全局标志。
CriticalSectionDefaultTimeout 用于这个进程处于无约束状态的临界区的默认超时值。
DeCommitFreeBlockThreshold 返回到系统之前必须释放的内存数量(以字节计)。
DeCommitTotalFreeThreshold 空闲内存总量(以字节计)。
LockPrefixTable 该值是一个VA。该字段仅适用于x86平台。它指向一个地址列表,这个地址列表中保存的是使用lock前缀的指令的地址,这样便于在单处理器机器上将这些lock前缀替换为nop指令。
MaximumAllocationSize 最大的分配粒度(以字节计)。
VirtualMemoryThreshold 最大的虚拟内存大小(以字节计)。
ProcessAffinityMask 如果将该字段设置为非零值,则等效于在进程启动时将这个设定的值作为参数去调用函数SetProcessAffinityMask。
ProcessHeapFlags 进程堆的标志,相当于函数HeapCreate的第一个参数。这些标志用于在进程启动过程中创建的堆。
CSDVersion Service Pack版本标识。
Reserved1 保留值。
EditList 保留,供系统使用。
SecurityCookie 指向cookie的指针。该cookie由Visual C++编译器的"GS implementation"所使用。
SEHandlerTable 该值为一个VA。与平台相关,指向一个地址列表。这个地址列表中保存的是映像中每个合法的、独一无二的、基于SEH框架的异常处理程序的RVA,并且它们已经按RVA从小到大的顺序排过序,最后以一个双字的0结尾。
SEHandlerCount IMAGE_LOAD_CONFIG_DIRECTORY.SEHandlerTable指向列表中双字的个数,最后一个0除外。

IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT

//
// New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ]
//

typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    NumberOfModuleForwarderRefs;
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
  • 绑定表域描述
描述
TimeDateStamp 这是包含导入的 DLL 的日期/时间戳的一个 DWORD 类型的值。
OffsetModuleName 这是包含导入的 DLL 的名称字符串偏移地址的一个 WORD 类型的值。这个域是相对于首个 IMAGE_BOUND_IMPORT_DESCRIPTOR 结构的偏移(而不是 RVA)。
NumberOfModuleForwarderRefs 这是一个 WORD 类型的值,它包含紧跟在这个结构后面的 IMAGE_BOUND_FORWARDER_REF 结构的数目。除了最后一个 WORD 类型的成员(NumberOfModuleForwarderRefs)是保留的外,IMAGE_BOUND_FORWARDER_REF 结构与IMAGE_BOUND_IMPORT_DESCRIPTOR 结构一样。

IMAGE_DIRECTORY_ENTRY_IAT

struct _IMAGE_DATA_DIRECTORY {
0x00 DWORD VirtualAddress;
0x04 DWORD Size;
};
  • IAT是导入地址表的英文缩写。准确地讲,它是导入表的一部分,这个双字数组里定义了所有导入函数的VA,程序可以直接通过跳转指令跳转到该VA处执行。

IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

struct _IMAGE_DELAY_IMPORT_DESCRIPTOR {
0x00 DWORD grAttrs;
0x04 DWORD szName;
0x08 DWORD phmod;
0x0c DWORD pIAT;
0x10 DWORD pINT;
0x14 DWORD pBoundIAT;
0x18 DWORD pUnloadIAT;
0x1c DWORD dwTimeStamp;
};
  • 延迟加载数据域描述
描述
grAttrs 此结构的属性。当前惟一定义的标志是 dlattrRva(值为 1)。这个标志表明此结构中的地址域是 RVA,而不是虚拟地址。设置这个标志表明延迟加载描述符是 VC7.0 或其后续版本。
rvaDLLName 导入的 DLL 的名称字符串的 RVA。这个字符串被传递给 LoadLibrary 函数
rvaHmod 一块 HMODULE 大小的内存的 RVA。当延迟加载的 DLL 被加载进内存时,它的 HMODULE 被存储在这个位置。
rvaIAT 此 DLL 的导入地址表的 RVA。它的格式与正常的 IAT 相同。
rvaINT 此 DLL 的导入名称表的 RVA。它的格式与正常的 INT 相同。
rvaBoundIAT 可选的绑定 IAT 的 RVA。它是此 DLL 的导入地址表的一个绑定副本的 RVA。它的格式与正常的 IAT 相同。当前这个 IAT 副本并未绑定,但这个功能可能被添加到将来的 BIND 程序中。
rvaUnloadIAT 原始的 IAT 的可选副本的 RVA。它是此 DLL 的导入地址表的一个未绑定的副本的 RVA。它的格式与正常的 IAT 相同。当前总是设置为 0。
dwTimeStamp 延迟加载导入的 DLL 的日期/时间戳。通常设置为 0。

IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR

typedef struct _IMAGE_COR20_HEADER {
    DWORD cb;
    WORD MajorRuntimeVersion;
    WORD MinorRuntimeVersion;
    IMAGE_DATA_DIRECTORY MetaData;
    DWORD Flags;
    DWORD EntryPointToken;
    IMAGE_DATA_DIRECTORY Resources;
    IMAGE_DATA_DIRECTORY StrongNameSignature;
    IMAGE_DATA_DIRECTORY CodeManagerTable;
    IMAGE_DATA_DIRECTORY VTableFixups;
    IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
    IMAGE_DATA_DIRECTORY ManagedNativeHeader;
};
  • .NET 头部域描述
描述
cb 头部的大小(以字节计)。
MajorRuntimeVersion 运行这个程序所需的运行时组件的最小版本号。对于第一个发行的.NETFramework 而言,此值为 2。
MinorRuntimeVersion 次版本号,当前为 0。
MetaData 元数据表的 RVA。
Flags 包含这个映像属性的标志。当前定义了以下值:
COMIMAGE_FLAGS_ILONLY
// 映像仅包含 IL 代码,并不需要运
// 行于特定 CPU 上
COMIMAGE_FLAGS_32BITREQUIRED
// 仅运行于 32 位处理器上
COMIMAGE_FLAGS_IL_LIBRARY
STRONGNAMESIGNED
// 映像已经用散列数据签名
COMIMAGE_FLAGS_TRACKDEBUGDATA
// 让 JIT 或运行时组件为方法保持
// 调试信息
EntryPointToken 映像入口点的 MethodDef的记号。.NET运行时调用这个方法开始托管执行。
Resources .NET 资源的 RVA 和大小。
StrongNameSignature 强名称散列数据的 RVA。
CodeManagerTable 代码管理器表的 RVA。代码管理器包含获取正在运行的程序的状态(例如堆栈跟踪和跟踪 GC 引用)所需的代码。
VTableFixups 需要被修正的函数指针组成的数组。用于支持非托管的 C++虚表。
ExportAddressTableJumps 由对应于导出符号的 JMP 形实转换块被写入的位置(RVA)组成的数组的 RVA。这些形实转换块允许托管方法被导出,这样非托管代码可以调用它们。
ManagedNativeHeader 在内存中供.NET 运行时组件内部使用。在可执行文件中被设置为 0。

节表

  • IMAGE_SECTION_HEADER结构数组,节表中此结构的数目由IMAGE_NT_HEADERS.FileHeader.NumberOfSections 给出。
  • SecOffset = dos_head->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof(IMAGE_FILE_HEADER)+
    peHeader->FileHeader.SizeOfOptionalHeader;
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;
  • 各个域的描述
大小 英文名 描述
1*8 Name[8] 这是一个8字节ASCII编码的字符串,不足8字节时用NULL填充,必须使其达到8字节。如果它正好是8字节,那就没有最后的NULL字符。可执行镜像不支持长度超过8字节的节名。
4 VirtualSize 指示节实际占用的内存大小。这个域的值可能比 SizeOfRawData域的值大或小。如果大,SizeOfRawData 域表示可执行文件中已初始化的数据的大小,VirtualSize 域比它大的部分用 0 填充。在 OBJ 文件中,此域的值为 0。
4 VirtualAddress 表示在内存中节的起始 RVA。内存中节相对于镜像基址的偏移。必须是SectionAlignment的整数倍。
4 SizeOfRawData 磁盘文件中初始化数据的大小。它必须是NT头中FileAlignment域的倍数。当节中仅包含未初始化的数据时,这个域应该为0。
4 PointerToRawData 节中数据起始的文件偏移。它必须是NT头中FileAlignment域的倍数。当节中仅包含未初始化的数据时,这个域应该为0。
4 PointerToRelocations 节的重定位信息的文件偏移。对于可执行文件或没有重定位项的文件来说,此值应该为0。
4 PointerToLinenumbers 节中 COFF 行号信息的文件偏移。如果它不为 0,那么它指向一个 IMAGE_LINENUMBER 结构。
2 NumberOfRelocations 节中重定位项的个数。对于可执行文件或没有重定位项的文件来说,此值应该为0。
2 NumberOfLinenumbers PointerToLinenumbers 域指向的行号信息的数目。只有当生成COFF 行号信息时才使用。
4 Characteristics 描述节特征的标志。

节表Characteristics

标志 描述
IMAGE_SCN_CNT_CODE 节中包含代码。
IMAGE_SCN_MEM_EXECUTE 节是可执行的。
IMAGE_SCN_CNT_INITIALIZED_DATA 节中包含已初始化的数据。
IMAGE_SCN_CNT_UNINITIALIZED_DATA 节中包含未初始化的数据。
IMAGE_SCN_MEM_DISCARDABLE 这个节在最终的可执行文件中可以被丢弃。用于保存链接器使用的信息,包括.debug$节。
IMAGE_SCN_MEM_NOT_PAGED 这个节不能被交换到页面文件中,因此它应该总是存在于物理内存中。经常用于内核模式驱动程序。
IMAGE_SCN_MEM_SHARED 包含这个节的物理页面将在加载这个可执行文件的所有进程之间共享。因此每个进程看到的这个节中的数据的值完全一样。对于在进程的所有实例之间共享全局变量比较有用。要共享某个节,使用/SECTION:节名,S链接器选项。
IMAGE_SCN_MEM_READ 节是可读的。几乎总是设置这个值。
IMAGE_SCN_MEM_WRITE 节是可写的。
IMAGE_SCN_LNK_INFO 节中包含链接器使用的信息。仅存在于 OBJ 文件中。
IMAGE_SCN_LNK_REMOVE 这个节中的内容将不成为最终的映像的一部分。仅用于OBJ文件。
IMAGE_SCN_LNK_COMDAT 节中的内容是公共数据(comdat)。公共数据(Communal data)是可以被定义在多个 OBJ 文件中的数据(或代码)。链接器只将其中的一份副本包含进最终的可执行文件中。Comdats 对于支持 C++的模板函数和函数级的链接至关重要。它仅存在于 OBJ 文件中。
IMAGE_SCN_ALIGN_xBYTES 这个节中的数据在最终的可执行文件中的对齐值。有各种各样的值(_4BYTES,_8BYTES,_16BYTES等)。如果不指定,默认为16,仅在 OBJ 文件中才设置这些标志。

节名

节名 内容
.text 默认代码节
.data 默认的可读/可写数据节。全局变量通常在这个节中
.rdata 默认的只读数据节。字符串常量和 C++/COM 虚表就放在这个节中
.idata 导入表。实际上,链接器经常把.idata 节合并到其它节中(或者是明确指定的,或者是通过链接器的默认行为)。默认情况下,链接器仅在创建发行版的程序时才把.idata 节合并到其它节中
.edata 导出表。当创建要导出函数或数据的可执行文件时,链接器会创建一个.EXP 文件。这个.EXP文件包含一个.edata 节,这个节被添加到最后的可执行文件中。与.idata 节一样,.edata节也经常被合并到.text 节或.rdata 节中
.rsrc 资源节。这个节是只读的。它不应该被命名为其它名称,也不应该被合并到其它节中
.bss 未初始化的数据节。在最新的链接器创建的可执行文件中很少见到。链接器扩展可执行文件的.data 节的 VirtualSize 域以便容纳未初始化的数据。
.crt 添加到可执行文件中的数据,用来支持C++运行时库(CRT)。一个比较好的例子就是用于调用静态C++对象的构造函数和析构函数的指针。
.tls 这个节中的数据用来支持使用__declspec(thread)语法创建的线程局部存储变量。它包括数据的初始值,以及运行时需要的附加变量。
.reloc 可执行文件中的基址重定位节。通常 DLL 需要基址重定位信息而 EXE 并不需要。在创建发行版的程序时,链接器并不为 EXE 文件生成基址重定位信息。可以使用/FIXED 链接器选项移除基址重定位信息
.sdata 通过全局指针(Global Pointer)相对寻址的“短(Short)”可读/可写数据。用于 IA-64和其它使用全局指针寄存器的平台上。IA-64 平台上正常大小的全局变量在这个节中。
.srdata 通过全局指针相对寻址的“短(Short)”只读数据。用于 IA-64 和其它使用全局指针寄存器的平台上。
.pdata 异常表。它包含一个 IMAGE_RUNTIME_FUNCTION_ENTRY 结构数组,这个结构与平台体系结构相关。数据目录中索引为 IMAGE_DIRECTORY_ENTRY_EXCEPTION 的项指向它。用于使用基于表的异常处理的平台,例如 IA-64。惟一不使用基于表的异常处理的平台是 x86(它使用的是基于堆栈的异常处理)
.debug$S OBJ 文件中的 Codeview 格式的调试符号(Symbol)信息。这是一列可变长度的 CodeView 格式的调试符号记录。
.debug$T OBJ 文件中的 Codeview 格式的调试类型(Type)记录。这是一列可变长度的 CodeView 格式的调试类型记录。
.debug$P 可以在使用预编译头(Precompiled Headers)生成的 OBJ 文件中找到这个节。
.drectve 这个节包含链接器指令,并且只存在于 OBJ 文件中。这些指令是传递到链接器命令行的 ASCII码字符串,例如:-defaultlib:LIBC。指令之间用空格分开。
.didat 延迟加载导入数据。可以在非发行版本的可执行文件中找到。在发行版本中,延迟加载数据被合并到其它节中。
原文地址:https://www.cnblogs.com/Kali-Team/p/12200084.html