Windows PE 结构 之 NT头结构解析

Windows PE 结构 之 NT头结构解析 - 侠者安全社区
Windows PE 结构 之 NT头结构解析
此内容为付费阅读,请付费后查看
会员专属资源
您暂无购买权限,请先开通会员
开通会员
付费阅读

0x0 基础知识

PE文件头的结构有两种,分别对应32位的程序和64位的程序,它们的差异在于扩展PE头的结构

PE文件头结构说明
_IMAGE_NT_HEADERS32位程序对应的PE文件头结构
_IMAGE_NT_HEADERS6464位程序对应的PE文件头结构

_IMAGE_NT_HEADERS对应C中的结构体(类型)说明
“PE”,0,0DOWRDPE标识
IMAGE_FILE_HEADERIMAGE_FILE_HEADER标准PE头
IMAGE_OPTIONAL_HEADER32IMAGE_OPTIONAL_HEADER32扩展PE头 32位

_IMAGE_NT_HEADERS64对应C中的结构体(类型)说明
“PE”,0,0DOWRDPE标识,固定值不可变
IMAGE_FILE_HEADERIMAGE_FILE_HEADER标准PE头
IMAGE_OPTIONAL_HEADER64IMAGE_OPTIONAL_HEADER64扩展PE头 64位

顺着 DOS 头中的 e_lfanew,我们很容易可以找到 NT头,这个才是 32/64位PE文件中最有用的头,定义如下:

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_NT_HEADERS64 {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

下图是一张真实的 PE文件头结构 以及其 各个域的取值 :

Windows PE 结构 之 NT头结构解析-侠者安全社区
Windows PE 结构 之 NT头结构解析-侠者安全社区

00 Signature ( 签名 )

类似于 DOS头中的 e_magic,其高16位是0,低16是0x4550,用字符表示是 ‘PE‘ 。

01 PE 头 之 标准PE头

IMAGE_FILE_HEADER 结构体定义

// 20 Bytes
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 成员详情

成员

数据宽度

说明

Machine

WORD(2字节)

程序支持的CPU

任意:0 Intel 386以及后续:14C x64:8664

NumberOfSections

WORD(2字节)

节的数量

不大于96

TimeDateStamp

DWORD(4字节)

编译器填写的时间戳

与文件属性里面(创建时间、修改时间)无关

PointerToSymbolTable

DWORD(4字节)

指向符号表

调试相关

NumberOfSymbols

DWORD(4字节)

符号表中的符号个数

调试相关

SizeOfOptionalHeader

WORD(2字节)

可选PE头结构大小

32位PE文件:0xE0 64位PE文件:0xF0

Characteristics

WORD(2字节)

文件属性

由数据位拼接而成,详见下方

IMAGE_FILE_HEADER 每个域的具体含义

  • Machine:该文件的运行平台,是 x86、x64 还是 I64 等等,可以是下面值里的某一个。
#define IMAGE_FILE_MACHINE_UNKNOWN           0
#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
#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_CEE               0xC0EE
  • NumberOfSections: 该PE文件中有多少个节,也就是节表中的项数。
  • TimeDateStamp: PE文件的创建时间,一般有连接器填写。
  • PointerToSymbolTable: COFF文件符号表在文件中的偏移。
  • NumberOfSymbols: 符号表的数量。
  • SizeOfOptionalHeader: 紧随其后的可选头的大小。
  • 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 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.
Windows PE 结构 之 NT头结构解析-侠者安全社区

02 PE 头 之 拓展PE头

  • 另一个重要的头就是 PE 拓展,它在不同的平台下是不一样的,例如32位下是IMAGE_OPTIONAL_HEADER32,而在64位下是IMAGE_OPTIONAL_HEADER64。为了简单起见,我们只看32位。

typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    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;
    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;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
    WORD        Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD       SizeOfCode;
    DWORD       SizeOfInitializedData;
    DWORD       SizeOfUninitializedData;
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
    ULONGLONG   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;
    ULONGLONG   SizeOfStackReserve;
    ULONGLONG   SizeOfStackCommit;
    ULONGLONG   SizeOfHeapReserve;
    ULONGLONG   SizeOfHeapCommit;
    DWORD       LoaderFlags;
    DWORD       NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

PE 可选头 各个字段分析说明

_IMAGE_OPTIONAL_HEADER 成员详情

成员

数据宽度

说明

Magic

WORD(2字节)

镜像文件的状态,可用于判断程序是32位还是64位

MajorLinkerVersion

BYTE(字节)

链接器的主要版本号

MinorLinkerVersion

BYTE(字节)

链接器的次要版本号

SizeOfCode

DWORD(4字节)

代码段的大小

SizeOfInitializedData

DWORD(4字节)

初始化数据段的大小

SizeOfUninitializedData

DWORD(4字节)

未初始化数据段的大小

AddressOfEntryPoint

DWORD(4字节)

程序入口

BaseOfCode

DWORD(4字节)

代码开始的基址

BaseOfData

DWORD(4字节)

数据开始的基址

ImageBase

DWORD(4字节)

内存镜像基址

SectionAlignment

DWORD(4字节)

内存对齐

FileAlignment

WORD(2字节)

文件对齐

MajorOperatingSystemVersion

WORD(2字节)

标识操作系统版本号 主版本号

MinorOperatingSystemVersion

WORD(2字节)

标识操作系统版本号 次版本号

MajorImageVersion

WORD(2字节)

PE文件自身的版本号

MinorImageVersion

WORD(2字节)

PE文件自身的版本号

MajorSubsystemVersion

WORD(2字节)

运行所需子系统版本号

MinorSubsystemVersion

WORD(2字节)

运行所需子系统版本号

Win32VersionValue

DWORD(4字节)

子系统版本的值,必须为0

SizeOfImage

DWORD(4字节)

Image大小

SizeOfHeaders

DWORD(4字节)

所有头+节表按照文件对齐后的大小

CheckSum

DWORD(4字节)

校验和

Subsystem

WORD(2字节)

子系统

DllCharacteristics

WORD(2字节)

文件特性 不只是针对DLL文件的

SizeOfStackReserve

DWORD(4字节)

初始化时保留的栈大小

SizeOfStackCommit

DWORD(4字节)

初始化时实际提交的大小

SizeOfHeapReserve

DWORD(4字节)

初始化时保留的堆大小

SizeOfHeapCommit

DWORD(4字节)

初始化时实践提交的大小

LoaderFlags

DWORD(4字节)

调试相关

NumberOfRvaAndSizes

DWORD(4字节)

目录项数目

DataDirectory[16]

IMAGE_DATA_DIRECTORY[16]=128字节

指向数据目录中第一个IMAGE_DATA_DIRECTORY结构的指针(数据目录项)

_IMAGE_OPTIONAL_HEADER 每个域的具体含义

  • Magic:表示可选头的类型。
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b  // 32位PE可选头
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b  // 64位PE可选头
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107
    • MajorLinkerVersion 和 MinorLinkerVersion:链接器的版本号。
    • SizeOfCode:代码段的长度,如果有多个代码段,则是代码段长度的总和。
    • SizeOfInitializedData:初始化的数据长度。
    • SizeOfUninitializedData:未初始化的数据长度。
    • AddressOfEntryPoint:程序入口的 RVA,对于exe这个地址可以理解为WinMain的RVA。对于DLL,这个地址可以理解为DllMain的RVA,如果是驱动程序,可以理解为DriverEntry的RVA。当然,实际上入口点并非是WinMain,DllMain和DriverEntry,在这些函数之前还有一系列初始化要完成,当然,这些不是本文的重点。
    • BaseOfCode:代码段起始地址的RVA。
    • BaseOfData:数据段起始地址的RVA。
    • ImageBase:映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。
    • SectionAlignment:内存对齐,节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0。
    • FileAlignment:文件对齐,节在文件中按此值对齐,SectionAlignment必须大于或等于FileAlignment。
    • MajorOperatingSystemVersion、MinorOperatingSystemVersion:所需操作系统的版本号,随着操作系统版本越来越多,这个好像不是那么重要了。
    • MajorImageVersion、MinorImageVersion:映象的版本号,这个是开发者自己指定的,由连接器填写。
    • MajorSubsystemVersion、MinorSubsystemVersion:所需子系统版本号。
    • Win32VersionValue:保留,必须为0。
    • SizeOfImage:映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小。
    • SizeOfHeaders:所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的。
    • CheckSum:映象文件的校验和。
    • Subsystem:运行该PE文件所需的子系统,可以是下面定义中的某一个:
    #define IMAGE_SUBSYSTEM_UNKNOWN              0   // Unknown subsystem.
    #define IMAGE_SUBSYSTEM_NATIVE               1   // Image doesn't require a subsystem.
    #define IMAGE_SUBSYSTEM_WINDOWS_GUI          2   // Image runs in the Windows GUI subsystem.
    #define IMAGE_SUBSYSTEM_WINDOWS_CUI          3   // Image runs in the Windows character subsystem.
    #define IMAGE_SUBSYSTEM_OS2_CUI              5   // image runs in the OS/2 character subsystem.
    #define IMAGE_SUBSYSTEM_POSIX_CUI            7   // image runs in the Posix character subsystem.
    #define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8   // image is a native Win9x driver.
    #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9   // Image runs in the Windows CE subsystem.
    #define IMAGE_SUBSYSTEM_EFI_APPLICATION      10  //
    #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11   //
    #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER   12  //
    #define IMAGE_SUBSYSTEM_EFI_ROM              13
    #define IMAGE_SUBSYSTEM_XBOX                 14
    #define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16
    DllCharacteristics:DLL的文件属性,只对DLL文件有效,可以是下面定义中某些的组合:
    #define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040     // DLL can move.
    #define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY    0x0080     // Code Integrity Image
    #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.
    //                                            0x1000     // Reserved.
    #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER   0x2000     // Driver uses WDM model
    //                                            0x4000     // Reserved.
    #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000
    • SizeOfStackReserve:运行时为每个线程栈保留内存的大小。
    • SizeOfStackCommit:运行时每个线程栈初始占用内存大小。
    • SizeOfHeapReserve:运行时为进程堆保留内存大小。
    • SizeOfHeapCommit:运行时进程堆初始占用内存大小。
    • LoaderFlags:保留,必须为0。
    • NumberOfRvaAndSizes:数据目录的项数,即下面这个数组的项数。
    • DataDirectory:数据目录,这是一个数组,数组的项定义如下:
    typedef struct _IMAGE_DATA_DIRECTORY {
        DWORD   VirtualAddress;   //  VirtualAddress:是一个RVA。
        DWORD   Size;             //  Size:是一个大小。
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    #define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
    #define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
    #define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
    #define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
    #define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
    #define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
    #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 Directory
    #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   // Import Address Table
    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

    0x1 实现代码

    © 版权声明
    THE END
    喜欢就支持一下吧
    点赞5 分享
    评论 抢沙发
    头像
    欢迎您留下宝贵的见解!
    提交
    头像

    昵称

    取消
    昵称表情

      暂无评论内容