PE文件结构

PE文件是Windows系统下可执行文件的总称,英文全称 Portable Executable 可移植的可执行文件,常见的有exe、dll、sys、com、ocx

对于学习反(木马、免杀、病毒、外挂、内核),了解PE文件结构是非常有必要且非常非常重要的!

PE结构包括:

  • MS-DOS头
  • 标准PE头
  • 扩展PE头
  • 数据目录
  • 节表

代码段(.text 或 .code): 可读 可执行 不可写

数据段(.data 或 .rdata 或.bss): 可读 可写 不可执行

未初始化数据段(.bss):可读 可写 不可执行

资源段(.rsrc): 可读 不可执行 不可写

导入表(.idata) : 简称 IAT 表 Import Address Table

导出表(.edata): 简称 EAT 表 Export Address Table

IMAGE_DOS_HEADER (长度不定)

MZ标记: 4D5A EXE程序的标志 在DOS头里 4字节

DOS_STUB (长度不定)

DOS STUB : 在dos系统下,会执行 DOS Stub 中的内容,不会出现不可预料的错误

IMAGE_NT_HEADERS (f8h)

PE Signature: PE标记 MZ偏移3C的位置 是e_lfanew 指向PE标记 PE头相对于文件的偏移地址 4字节

IMAGE_FILE_HEADER PE文件头 (14h)

Machine : PE标记后2个字节是Machine 14C代表32位CPU 8664代表64位CPU 2字节

NumberOfSections: 代表区段数量 代码段 数据段 资源段 2字节

Timestamp: 时间戳,文件创建时间, 表示从1970年1月1日 00:00:00 到文件创建时间的秒数 4字节

PointerOfSymbolTable: 用于调试 4字节

NumberOfSymbols: 用于调试 4字节

SizeOfOptionalHeader: 可选头大小 e0h 2字节

Characteristics: 文件信息标志 如dll/exe 2字节

IMAGE_OPTIONAL_HEADER 可选PE头 (e0h)

Magic :代表文件的格式 010b是32位应用程序 020b是64位应用程序 107是系统的ROM文件 2字节

Major LinkerVersion : 连接器首版本号 1字节

Minor LinkerVersion : 连接器次版本号 1字节

SizeOfCode : 代码块大小 4字节 (512为一个磁盘扇区)

SizeOfInitializedData : 已初始化数据块大小 4字节 也就是.data

SizeOfUninitializedData : 未初始化数据块大小 4字节 也就是.data

AddressOfEntryPoint : 程序执行入口(OEP) 4字节 RVA(相对偏移)(相对虚拟内存地址)

BaseOfCode: 代码块起始RVA 4字节 表示代码段起始RVA

BaseOfData : 数据块起始RVA 4字节 表示数据段的起始RVA

ImageBase: 基址 4字节 入口点

EXE,DLL文件被装载到用户内存的0~7FFFFFFF中,SYS文件被加载到80000000~FFFFFFFF中

执行PE文件的时候。PE装载器先创建进程,再将文件载入内存,然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint

BaseofCode + ImageBase可以得到代码段的起始地址

BaseOfData + ImageBase可以得到数据段段的起始地址

SectionAlignment: 块对齐值 4字节

FileAlignment : 文件对齐值 4字节

Major Operating System Version : 操作系统首版本号 2字节

Minor Operating SystemVersion: 操作系统次版本号 2字节

Major Image Version:用户程序首版本号 2字节

Minor Image Version:用户程序次版本号 2字节

MajorSub System Version :子系统首版本号 2字节

MinorSub System Version :子系统次版本号 2字节

Win32 Version Value : 32位系统版本号值 4字节

SizeOfImage : 整个程序在内存中占用的空间(PE映像尺寸)映像大小 4字节

SizeOfHeaders : 块前头部大小 4字节 所有头(头的结构体大小)+节表的大小

Checksum : 校验和 4字节 对于驱动程序,可能会使用

SubSystem : 程序运行所需子系统 2字节 重要

DICharacteristics:当文件为dll文件时使用 2字节

SizeOf StackReserve :保留栈大小 4字节

SizeOf StackCommit :使用栈大小 4字节

SizeOf HapReserve : 保留堆大小 4字节

SizeOf HeapCommit : 使用堆大小 4字节

LoaderFlags : 设置自动调用断点或调试器 4字节 与调试有关

NumberOfRvaAndSizes: Rva的大小的数量 4字节 下面的成员,数据目录结构的项目数量

DataDirectory : Image_Data Directorys 80字节 数据目录,默认16个,16是宏,这里方便直接写成16

SECTION TABLE (长度不定)

IMAGE_SECTION_HEADER (28h)

Name :块名 8字节

VirtualSize: 内存中快大小 4字节

VirtusalAddress: 内存中块RVA值 4字节

SizeOfRawData:文件中块大小 4字节

PointerToRawData:文件中块偏移 4字节

PointerToRelocations: OBJ文件使用 4字节

PointerToLineNumbers: OBJ文件使用 4字节

NumberOfRelocations : OBJ文件使用 2字节

NumberOfLineNumbers : OBJ文件使用 2字节

Characteristics : 块属性

  • RVA 相对虚拟地址,映像文件在虚拟内存中相对于加载基址的偏移。
  • VA 虚拟地址,映像文件在虚拟内存中的地址。
  • FOA 文件偏移地址,映像文件在磁盘文件中相对于文件开头的偏移。

三个地址概念:

  • VA:( Virtual Address )虚拟内存地址,范围00000000h - 0FFFFFFFh,就是进程的基地址 + RVA相对虚拟内存地址
  • RVA:相对虚拟内存地址,RVA是相对某个模块而存在的
  • FOA:文件偏移地址,文件头的偏移地址

VA = ImageBase + RVA

RVA = VA - ImageBase

PE头部分用于宏观上记录文件的一些信息,运行平台,大小,创建日期,属性等

节表部分用于对各中类型的数据进行定义分段

节数据就是文件的数据部分,实际上我们编写程序的过程中就是对该部分的数据进行编写。

而其他的部分则是由编译器依照我们编写的部分进行相应的填写而得到

DOS头结构

在winnt.h里已经定义了,在使用的时候包含windows.h头文件即可

#include<Windows.h>

DOS头的结构体

typedef struct _IMAGE_DOS_HEADER {  // DOS-MZ文件头   
WORD   e_magic;                     // DOS 可执行文件的标识符      +0h
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;                    // 指向PE文件头   +3ch
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

其中e_magic 和 e_lfanew 比较重要, e_magic 为 "MZ" ,e_lfanew 字段是真正PE文件的相对偏移(RVA)

typedef struct _IMAGE_NT_HEADERS {DWORD Signature; //该结构体中的Signature就是PE签名,标识该文件是否是PE文件。该部分占4字节,即“50 45 0000”。IMAGE_FILE_HEADER FileHeader;       //20字节IMAGE_OPTIONAL_HEADER32 OptionalHeader;  //32位0xE0字节 64位0xF0字节
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;    //64位是PIMAGE_NT_HEADERS64
typedef struct _IMAGE_FILE_HEADER {WORD Machine;  // 程序允许的cpu型号,为0代表所有     重要成员WORD NumberOfSections;  // 节区数量           重要成员DWORD TimeDateStamp;  // 自1970年1月1日00:00起的秒数的低 32 位 (C 运行时time_t值) ,该值指示文件创建时间。DWORD PointerToSymbolTable; // COFF符号表的文件偏移量,如果没有COFF符号表,则为零。映像的此值应为零,因为 COFF 调试信息已弃用。DWORD NumberOfSymbols;  // 符号表中的条目数。此数据可用于查找紧跟在符号表后面的字符串表。映像的此值应为零,因为 COFF 调试信息已弃用。WORD SizeOfOptionalHeader;  // 可选标头的大小,这是可执行文件所必需的 32位默认E0 64位默认F0   重要成员WORD Characteristics;  // 指示文件属性的标志。 文件属性,每个位有不同含义  可判断是否存在重定位信息,很重要	   重要成员
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_OPTIONAL_HEADER {WORD    Magic;                                 // +0018h   -   用于标识32/64位文件 PE32: 10B PE64: 20BBYTE    MajorLinkerVersion;                    // +001ah   -   链接器版本号BYTE    MinorLinkerVersion;                    // +001bh   -   DWORD   SizeOfCode;                            // +001ch   -   所有代码段的总大小 按照FileAlignment对齐后的大小 编译器填入 无用DWORD   SizeOfInitializedData;                 // +0020h   -   所有已初始化数据区块的大小 按文件对齐 编译器填入 没用(可改)DWORD   SizeOfUninitializedData;               // +0024h   -   所有未初始化数据区块的大小 按文件对齐 编译器填入 没用(可改)DWORD   AddressOfEntryPoint;      重要成员      // +0028h   -   程序执行入口OEP RVADWORD   BaseOfCode;                            // +002ch   -   代码节的起始RVADWORD   BaseOfData;                            // +0030h   -   数据节的起始RVADWORD   ImageBase;            重要成员          // +0034h   -   程序的建议装载地址 内存镜像基址(程序默认载入基地址)DWORD   SectionAlignment;     重要成员          // +0038h   -   内存中的节的对齐粒度DWORD   FileAlignment;        重要成员          // +003ch   -   文件中的节的对齐粒度WORD    MajorOperatingSystemVersion;           // +0040h   -   操作系统版本号WORD    MinorOperatingSystemVersion;           // +0042h   -   WORD    MajorImageVersion;                     // +0044h   -   该PE的版本号WORD    MinorImageVersion;                     // +0046h   -   WORD    MajorSubsystemVersion;                 // +0048h   -   所需子系统的版本号WORD    MinorSubsystemVersion;                 // +004ah   -   DWORD   Win32VersionValue;                     // +004ch   -   未用DWORD   SizeOfImage;         重要成员           // +0050h   -   内存中的整个PE映像尺寸,可比实际值大,必须是SectionAlignment的整数倍DWORD   SizeOfHeaders;       重要成员           // +0054h   -   所有头+节表的大小 对齐之后的值DWORD   CheckSum;                              // +0058h   -   校验和  映像校验和,一些系统.dll文件有要求,判断是否被修改WORD    Subsystem;                             // +005ch   -   文件的子系统WORD    DllCharacteristics;                    // +005eh   -   DLL文件特性,,不是针对DLL文件的,16进制转换2进制可以根据属性对应的表格得到相应的属性DWORD   SizeOfStackReserve;                    // +0060h   -   初始化时的栈大小DWORD   SizeOfStackCommit;                     // +0064h   -   初始化时实际提交的栈大小DWORD   SizeOfHeapReserve;                     // +0068h   -   初始化时保留的堆大小DWORD   SizeOfHeapCommit;                      // +006ch   -   初始化时实际提交的堆大小DWORD   LoaderFlags;                           // +0070h   -   与调试有关DWORD   NumberOfRvaAndSizes;  重要成员          // +0074h   -   下面的数据目录结构的项目数量IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];     // 0078h   -   数据目录
}
IMAGE_DATA_DIRECTORY {DWORD   VirtualAddress;                 // +0000h   -   数据的起始RVADWORD   Size;                           // +0004h   -   数据块的长度
}
 IMAGE_SECTION_HEADER {              BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];   // +0000h   -   8个字节节名   重要成员union {DWORD   PhysicalAddress;DWORD   VirtualSize;        重要成员  // 区段大小,没做对齐之前的大小} Misc;                                  // +0008h   -   节区的尺寸DWORD   VirtualAddress;    重要成员       // +000ch   -   节区的RVA地址DWORD   SizeOfRawData;                   // +0010h   -   在文件中对齐后的尺寸DWORD   PointerToRawData;     重要成员    // +0014h   -   在文件中的偏移DWORD   PointerToRelocations;            // +0018h   -   在OBJ文件中使用DWORD   PointerToLinenumbers;            // +001ch   -   行号表的位置(供调试用)WORD    NumberOfRelocations;             // +0020h   -   在OBJ文件中使用WORD    NumberOfLinenumbers;             // +0022h   -   行号表中行号的数量DWORD   Characteristics;    重要成员      // +0024h   -   节的属性
}
typedef struct _IMAGE_IMPORT_DESCRIPTOR {union {DWORD   Characteristics;            // 0 for terminating null import descriptorDWORD   OriginalFirstThunk;         // RVA 指向 INT (PIMAGE_THUNK_DATA结构数组)} DUMMYUNIONNAME;DWORD   TimeDateStamp;                  // 0 if not bound,// -1 if bound, and real date\time 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 forwardersDWORD   Name;							//RVA指向dll名字,以0结尾DWORD   FirstThunk;                     // RVA 指向 IAT (PIMAGE_THUNK_DATA结构数组)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {WORD    Hint; //可能为空,编译器决定,如果不为空,是函数在导出表的索引BYTE    Name[1]; //函数名称,以0结尾
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;#include "pshpack8.h"                       // Use align 8 for the 64-bit IAT.typedef struct _IMAGE_THUNK_DATA64 {union {ULONGLONG ForwarderString;  // 指向一个转向者字符串的RVAULONGLONG Function;         // 被输入的函数的内存地址ULONGLONG Ordinal;			// 被输入API的序数值ULONGLONG AddressOfData;    // 指针指向 IMAGE_IMPORT_BY_NAME} u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;#include "poppack.h"                        // Back to 4 byte packingtypedef struct _IMAGE_THUNK_DATA32 {union {DWORD ForwarderString;      // PBYTE DWORD Function;             // PDWORDDWORD Ordinal;DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
typedef struct _IMAGE_EXPORT_DIRECTORY {DWORD   Characteristics;        //保留段,值为00,特征值DWORD   TimeDateStamp;          //导出表创建时间WORD    MajorVersion;           //导出表主版本号WORD    MinorVersion;           //导出表子版本号DWORD   Name;					// 指针指向该导出表文件名字符串DWORD   Base;					// 导出函数起始序号DWORD   NumberOfFunctions;		// 所有导出函数的个数DWORD   NumberOfNames;			// 以函数名字导出的函数个数DWORD   AddressOfFunctions;     // 指针指向导出函数地址表RVADWORD   AddressOfNames;         // 指针指向导出函数名称表RVADWORD   AddressOfNameOrdinals;  // 指针指向导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

正常情况下,dll才有导出表

typedef struct _IMAGE_BASE_RELOCATION {DWORD   VirtualAddress; // 重定位数据的开始 RVA 地址DWORD   SizeOfBlock;	// 重定位块的长度
//  WORD    TypeOffset[1];	// 重定位项数组
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
typedef struct _IMAGE_TLS_DIRECTORY32 {DWORD   StartAddressOfRawData;		// 内存起始地址DWORD   EndAddressOfRawData;		//内存结束地址DWORD   AddressOfIndex;             // PDWORDDWORD   AddressOfCallBacks;         // PIMAGE_TLS_CALLBACK *DWORD   SizeOfZeroFill;				// 0填充区域长度union {DWORD Characteristics;			//保留字段struct {DWORD Reserved0 : 20;DWORD Alignment : 4;DWORD Reserved1 : 8;} DUMMYSTRUCTNAME;} DUMMYUNIONNAME;} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;

TLS表 存在TSL区段里:线程局部存储,会在程序运行之前执行完毕,用于反调试

typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR {union {DWORD AllAttributes;struct {DWORD RvaBased : 1;             // Delay load version 2DWORD ReservedAttributes : 31;} DUMMYSTRUCTNAME;} Attributes;DWORD DllNameRVA;                       // RVA to the name of the target library (NULL-terminate ASCII string)DWORD ModuleHandleRVA;                  // RVA to the HMODULE caching location (PHMODULE)DWORD ImportAddressTableRVA;            // RVA to the start of the IAT (PIMAGE_THUNK_DATA)DWORD ImportNameTableRVA;               // RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData)DWORD BoundImportAddressTableRVA;       // RVA to an optional bound IATDWORD UnloadInformationTableRVA;        // RVA to an optional unload info tableDWORD TimeDateStamp;                    // 0 if not bound,// Otherwise, date/time of the target DLL} IMAGE_DELAYLOAD_DESCRIPTOR, *PIMAGE_DELAYLOAD_DESCRIPTOR;

导入表(Import Table)

  • 导入表包含了程序对外部DLL函数的引用,包括函数的名字和所在的DLL名称。
  • 在编译阶段,链接器会生成导入表,其中的条目用于告诉加载器程序需要哪些外部函数。
  • 导入表中通常包含IMAGE_IMPORT_DESCRIPTOR结构,它描述了导入的DLL和函数列表。

IAT(Import Address Table)

  • IAT是在程序加载到内存时由操作系统动态填充的,它存储了从导入表中列出的DLL函数的实际内存地址。
  • 当程序加载时,加载器会解析导入表,加载所需的DLL,并将DLL中函数的实际地址填入IAT。
  • 程序执行时,它通过IAT中的地址来调用外部DLL的函数。

----------------------------------------------------------------------------------------------------------------------------

IMAGE_DOS_HEADER DOS头 0x40(64)字节

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE headerWORD   e_magic;                     // MZ标记                  勿改WORD   e_cblp;                      // Bytes on last page of fileWORD   e_cp;                        // Pages in fileWORD   e_crlc;                      // RelocationsWORD   e_cparhdr;                   // Size of header in paragraphsWORD   e_minalloc;                  // Minimum extra paragraphs neededWORD   e_maxalloc;                  // Maximum extra paragraphs neededWORD   e_ss;                        // Initial (relative) SS valueWORD   e_sp;                        // Initial SP valueWORD   e_csum;                      // ChecksumWORD   e_ip;                        // Initial IP valueWORD   e_cs;                        // Initial (relative) CS valueWORD   e_lfarlc;                    // File address of relocation tableWORD   e_ovno;                      // Overlay numberWORD   e_res[4];                    // Reserved wordsWORD   e_oemid;                     // OEM identifier (for e_oeminfo)WORD   e_oeminfo;                   // OEM information; e_oemid specificWORD   e_res2[10];                  // Reserved wordsLONG   e_lfanew;                    // PE头偏移                  勿改} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

仅使用了两个成员 , 其他成员都可以修改

e_magic 0x5A4D

0 + e_lfanew = PE标记

e_lfanew 到 PE标记 之间的数据为 DOS_STUB , 可随意修改

IMAGE_NT_HEADER NT头 32位: 0xF8(248)字节 64位: 0x108(264)字节

typedef struct _IMAGE_NT_HEADERS {DWORD Signature;                         //PE标记   0x00004550 IMAGE_FILE_HEADER FileHeader;            //标准PE头  0x14(20)字节IMAGE_OPTIONAL_HEADER32 OptionalHeader;  //可选PE头  32位默认大小为0xE0
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;typedef struct _IMAGE_NT_HEADERS64 {DWORD Signature;                         //PE标记   0x00004550 IMAGE_FILE_HEADER FileHeader;            //标准PE头  0x14(20)字节IMAGE_OPTIONAL_HEADER64 OptionalHeader;  //可选PE头  64位默认大小为0xF0
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

PE标记必须为0x00004550 , 否则程序无法启动

IMAGE_FILE_HEADER 标准PE头 0x14(20)字节

typedef struct _IMAGE_FILE_HEADER {WORD    Machine;                         //运行平台  0x014c 或 0x8664    WORD    NumberOfSections;                //节区数量                     DWORD   TimeDateStamp;                   //文件创建时间戳   可抹零DWORD   PointerToSymbolTable;            //指向符号表(用于调试)DWORD   NumberOfSymbols;                 //符号表中符号个数(用于调试)WORD    SizeOfOptionalHeader;            //可选头大小  32位:0xE0  64位:0xF0  WORD    Characteristics;                 //文件属性  由位组成                 
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
#define IMAGE_SIZEOF_FILE_HEADER             20

IMAGE_OPTIONAL_HEADER 可选PE头 32位默认大小为0xE0(224)字节 64位大小为0xF0(240)字节

typedef struct _IMAGE_OPTIONAL_HEADER {WORD    Magic;                        //镜像文件的状态,用于判断程序是32位还是64位BYTE    MajorLinkerVersion;           //链接器版本号BYTE    MinorLinkerVersion;           //链接器次要版本号DWORD   SizeOfCode;                   //代码段的大小(以字节为单位),如果有多个代码段,则为所有这些代码段的总和。是文件对齐后的大小 编译器填的 没用(不一定准确)DWORD   SizeOfInitializedData;        //已初始化数据段的大小(以字节为单位),如果有多个初始化数据段,则为所有这些数据段的总和。是文件对齐后的大小 编译器填的 没用(不一定准确)DWORD   SizeOfUninitializedData;      //未初始化数据段的大小(以字节为单位),如果有多个未初始化数据段,则为所有这些数据段的总和。是文件对齐后的大小 编译器填的 没用(不一定准确)DWORD   AddressOfEntryPoint;     //RVA 一个指向入口点函数的指针,相对于ImageBase, 1.对于可执行文件,这是起始地址 2.对于设备驱动程序,这是初始化函数的地址3.入口点函数对于dll是可选的。当没有入口点存在时,该成员为零 DWORD   BaseOfCode;              //代码段RVA 指向代码段开头的指针,相对于ImageBase。编译器填的  没用(不一定准确)DWORD   BaseOfData;              //数据段RVA 指向数据段开头的指针,相对于ImageBase。编译器填的  没用(不一定准确)DWORD   ImageBase;               //内存镜像基址 exe默认0x400000,dll默认0x10000000DWORD   SectionAlignment;        //加载到内存中的节的对齐方式,以字节为单位。该值必须大于或等于FileAlignment(文件对齐)成员。默认值是系统的页面大小DWORD   FileAlignment;           //Image(PE文件)中各节的原始数据(以字节为单位)的对齐方式。该值应该是512到64K(包括)之间2的幂。缺省值是512。如果SectionAlignment成员小于系统页面大小,则该成员必须与SectionAlignment相同WORD    MajorOperatingSystemVersion;       //所需操作系统的主要版本号WORD    MinorOperatingSystemVersion;       //所需操作系统的次要版本号WORD    MajorImageVersion;                 //镜像(PE文件)的主版本号WORD    MinorImageVersion;                 //镜像(PE文件)的次要版本号WORD    MajorSubsystemVersion;             //子系统的主要版本号WORD    MinorSubsystemVersion;             //子系统的次要版本号DWORD   Win32VersionValue;                 //保留,并且必须为0DWORD   SizeOfImage;                       //映像装入内存后的总大小DWORD   SizeOfHeaders;                     //DOS头、PE头、区块表总大小 文件对齐后大小DWORD   CheckSum;                          //Image(PE文件)校验和WORD    Subsystem;                         //运行此映像所需的子系统WORD    DllCharacteristics;                //Image的DLL特性DWORD   SizeOfStackReserve;                //为堆栈保留的字节数DWORD   SizeOfStackCommit;                 //要提交给堆栈的字节数DWORD   SizeOfHeapReserve;                 //为本地堆保留的字节数DWORD   SizeOfHeapCommit;                  //要为本地堆提交的字节数DWORD   LoaderFlags;                       //该成员已过时,与调试有关,默认为 0 DWORD   NumberOfRvaAndSizes;               //数据目录表的项数 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

ImageBase + AddressOfEntryPoint (RVA) = 程序真正执行地址 (OEP)

ImageBase + 相对虚拟地址(RVA) = 虚拟内存地址(VA)

VA - ImageBase = 相对虚拟地址(RVA)

文件偏移地址(FOA)

IMAGE_DATA_DIRECTORY 数据目录表

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16typedef struct _IMAGE_DATA_DIRECTORY {DWORD   VirtualAddress;                    //数据块的起始RVADWORD   Size;                              //目录项大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

导出表 / 导入表 / 重定位表 / IAT表

IMAGE_SECTION_HEADER 节表 每个40字节

#define IMAGE_SIZEOF_SECTION_HEADER          40
#define IMAGE_SIZEOF_SHORT_NAME              8typedef struct _IMAGE_SECTION_HEADER {BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];     //节名称 8字节 \0结尾的ASCII码字符串 可自定义union                                      //8字节{DWORD   PhysicalAddress;           //节的文件地址DWORD   VirtualSize;               //节内存中大小} Misc;DWORD   VirtualAddress;                    //(RVA)节在内存中的偏移地址DWORD   SizeOfRawData;                     //节在文件中的大小  对齐后DWORD   PointerToRawData;                  //(FOA)节在文件中的偏移地址DWORD   PointerToRelocations;              //.obj文件有效,重定位的偏移  DWORD   PointerToLinenumbers;              //调试相关WORD    NumberOfRelocations;               //.obj文件有效,重定位项数目  WORD    NumberOfLinenumbers;               //行号表中行号的数量DWORD   Characteristics;                   //节属性 可读 可写 可执行 60000020 
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

.data 初始化的数据

.idata 导入表

.rsrc 资源数据

.reloc 基地址重定位表

.edata 导出表

.tls thread local storage 线程局部存储器

.rdata 存放调试目录和说明字符串

最后一个节区之后的40个字节 必须为0

IMAGE_EXPORT_DIRECTORY 导出表

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directorytypedef struct _IMAGE_EXPORT_DIRECTORY {DWORD   Characteristics;        // 未使用 0DWORD   TimeDateStamp;          // 创建导出表的时间戳WORD    MajorVersion;           // 未使用 0WORD    MinorVersion;           // 未使用 0DWORD   Name;                   // 指向该导出表的文件名字符串RVADWORD   Base;                   // 导出函数的起始序号DWORD   NumberOfFunctions;      // 所有导出函数的个数  不准确DWORD   NumberOfNames;          // 以函数名字导出的函数个数DWORD   AddressOfFunctions;     // 导出函数地址表RVADWORD   AddressOfNames;         // 导出函数名称表RVADWORD   AddressOfNameOrdinals;  // 导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

IMAGE_IMPORT_DESCRIPTOR 导入表

typedef struct _IMAGE_IMPORT_DESCRIPTOR {union {DWORD   Characteristics;           //导入表结束标志DWORD   OriginalFirstThunk;        //导入名称表(INT)的地址RVA  } DUMMYUNIONNAME;DWORD   TimeDateStamp;                 //时间戳  如果是0xFFFFFFFF为绑定导入DWORD   ForwarderChain;                //链表的前一个结构DWORD   Name;                          //导入DLL文件名的地址RVADWORD   FirstThunk;                    //导入地址表(IAT)的地址RVA
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;//成员OriginalFirstThunk 和 FirstThunk 都指向此结构
typedef struct _IMAGE_THUNK_DATA32 {union {DWORD ForwarderString;      // PBYTE  指向一个转向者字符串的RVADWORD Function;             // PDWORD 被输入的函数的内存地址DWORD Ordinal;              // 序号DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME 指向IMAGE_IMPORT_BY_NAME} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;//如果结构_IMAGE_THUNK_DATA32成员最高有效位为1时 低31位为导出序号,否则指向此结构
typedef struct _IMAGE_IMPORT_BY_NAME {WORD    Hint;       //导出序号(有些编译器不会填充此值)CHAR    Name[1];    //该值长度不准确,以0结尾的字符串,导出函数名
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

_IMAGE_BASE_RELOCATION 重定位表

typedef struct _IMAGE_BASE_RELOCATION {DWORD   VirtualAddress;             //重定位数据所在页的RVADWORD   SizeOfBlock;                //当前页中重定位数据块的大小
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

PE笔记

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
#include <stdio.h>using namespace std;int main()
{FILE* pFile = fopen("C:\\Users\\Administrator\\Desktop\\PETool.exe", "rb");fseek(pFile, NULL, SEEK_END);int nSize = ftell(pFile);fseek(pFile, NULL, SEEK_SET);char* pFileBuffer = (char*)malloc(nSize);memset(pFileBuffer, 0, nSize);fread(pFileBuffer, nSize, 1, pFile);char* a =  pFileBuffer + 0x3c;int b = *((int*)a);cout << pFileBuffer << endl;cout << pFileBuffer + b << endl;FILE* pFile1 = fopen("D:\\PETool.exe", "wb");fwrite(pFileBuffer, nSize, 1, pFile1);free(pFileBuffer);fclose(pFile);return 0;
}

cout<<hex<<i<<endl; //输出十六进制数 cout<<dec<<i<<endl; //输出十进制数

cout << hex << uppercase << showbase << pDos->e_magic << endl;

抹除PE标记作业

#include "tools.h"
int main()
{int FileSize = 0;char* pFileBuffer = FileToMemory(FILE_PATH_IN, &FileSize);PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;//输出 PIMAGE_DOS_HEADER 所有信息cerr << hex << uppercase << showbase << pDos->e_magic << endl;cerr  << hex << uppercase << showbase << pDos->e_cblp << endl;cerr  << hex << uppercase << showbase << pDos->e_cp << endl;cerr  << hex << uppercase << showbase << pDos->e_cparhdr << endl;cerr  << hex << uppercase << showbase << pDos->e_crlc << endl;cerr  << hex << uppercase << showbase << pDos->e_cs << endl;cerr  << hex << uppercase << showbase << pDos->e_csum << endl;cerr  << hex << uppercase << showbase << pDos->e_ip << endl;cerr  << hex << uppercase << showbase << pDos->e_lfarlc << endl;cerr  << hex << uppercase << showbase << pDos->e_maxalloc << endl;cerr  << hex << uppercase << showbase << pDos->e_oemid << endl;cerr  << hex << uppercase << showbase << pDos->e_oeminfo << endl;cerr  << hex << uppercase << showbase << pDos->e_ovno << endl;for (size_t i = 0; i < 4; i++){cerr << hex << uppercase << showbase << pDos->e_res[i] << endl;}for (size_t i = 0; i < 10; i++){cerr << hex << uppercase << showbase << pDos->e_res2[i] << endl;}cerr  << hex << uppercase << showbase << pDos->e_sp << endl;cerr  << hex << uppercase << showbase << pDos->e_ss << endl;cerr  << hex << uppercase << showbase << pDos->e_lfanew << endl;memset(pFileBuffer, 0x00, 0x2);               //抹除MZ标记memset(pFileBuffer + 2, 0x00, 0x3A);          //抹除e_magic - e_lfanew 之间数据memset((&(pDos->e_lfanew))+ 1 , 0x00, 0xC0);  //抹除DOS_STUBmemset((pFileBuffer + *(&(pDos->e_lfanew))), 0x00, 0x2); //抹除PE标记MemoryToFile(FILE_PATH_OUT, pFileBuffer, FileSize);return 0;
}

时间戳转时间

string StampToTime(time_t timeStamp) 
{struct tm* timeinfo = nullptr;char buffer[80];timeinfo = localtime(&timeStamp);strftime(buffer, 80, "%Y年%m月%d日 %H:%M:%S", timeinfo);printf("文件创建时间: %s\n", buffer);return string(buffer);
}

PE结构体

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

Characteristics

0102

0000 0001 0000 0010

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   //该文件是ROM镜像

Subsystem

DllCharacteristics

DataDirectory

#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  
#define 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  

Characteristics 节属性常用位含义

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言-08复合类型-结构体

一、结构体 1.结构体struct struct关键字&#xff0c;允许自定义复合数据类型&#xff0c;将不同类型的值组合在一起&#xff0c;这种类型称为结构体类型。 2.使用步骤 第一步&#xff1a;创建或声明结构体 第二步&#xff1a;定义结构体变量 第三步&#xff1a;调用并操作结…

Web前端基础知识(一)

前端是构建网页的一部分&#xff0c;负责用户在浏览器中看到和与之交互的内容。 网页是在浏览器中呈现内容的文档或页面。 通常&#xff0c;网页使用HTML、CSS、JavaScript(JS)组成。 HTML:定义了页面的结构和内容。包括文本、图像、链接等。 CSS&#xff1a;定义页面的样式…

网络安全词云图与技术浅谈

网络安全词云图与技术浅谈 一、网络安全词云图生成 为了直观地展示网络安全领域的关键术语&#xff0c;我们可以通过词云图&#xff08;Word Cloud&#xff09;的形式来呈现。词云图是一种数据可视化工具&#xff0c;它通过字体大小和颜色的差异来突出显示文本中出现频率较高…

fpgafor循环语句使用

genvar i;//循环变量名称 generate for(i0;i<4;ii1)begin:tx//自己定义名称 //循环内容 end endgenerate12位的16进制乘以4就是48位位宽的2进制 因为 222*2(2^4)16

【python高级】342-TCP服务器开发流程

CS模式&#xff1a;客户端-服务端模式 TCP客户端开发流程介绍&#xff08;五步&#xff09;&#xff08;C端&#xff09; 1.创建客户端套接字对象 2.和服务端套接字建立连接 3.发送数据 4.接收数据 5.关闭客户端套接字 TCP服务端开发流程&#xff08;七步&#xff09;&#xf…

es 中 terms set 使用

在 Elasticsearch 中&#xff0c;terms_set 查询通常用于在一个字段上进行多值匹配&#xff0c;并支持设置一个条件&#xff08;例如最小匹配数量&#xff09;&#xff0c;让查询结果更具灵活性。为了展示如何使用 terms_set 查询&#xff0c;我们首先会创建一个索引&#xff0…

修改采购订单BAPI学习研究-BAPI_PO_CHANGE

这里是修改采购订单BAPI&#xff0c;修改订单数量和交货日期的简单应用 文章目录 修改数量代码运行结果 修改交货日期代码运行结果 修改数量 代码 *&---------------------------------------------------------------------* *& Report Z_BAPI_PO_CHANGE *&----…

WSL2高级配置之mirrored镜像网络

WSL2高级配置之mirrored镜像网络 引言版本要求更改配置 引言 WSL2默认的网络模式为NAT。尽管WSL2原生提供了localhost转发这种能够方便地在Windows中访问子系统服务的特性&#xff0c;但如果想反过来&#xff0c;则只能通过局域网或者想办法桥接&#xff0c;这两种方法都有些许…

《ROS2 机器人开发 从入门道实践》 鱼香ROS2——第4章内容

第4章 服务和参数——深入ROS2通信 4.2 用Python服务通信实现人脸检测 4.2.1 自定义服务接口 1. 创建接口功能包 终端中输入 ros2 pkg create chapt4_interfaces --dependencies sensor_msgs rosidl_default_generators --license Apache-2.0 ros2 pkg create 功能包名称…

Linux系统编程深度解析:C语言实战指南

文章一览 前言一、gcc编译系统1.1 文件名后缀1.2 C语言编译过程1.3 gcc命令行选项 二、gdb程序调试工具2.1 启动gdb和查看内部命令2.2 显示源程序和数据2.2.1 显示和搜索源程序2.2.2 查看运行时数据 2.3 改变和显示目录或路径2.4 控制程序的执行2.4.1 设置断点2.4.2 显示断点2.…

SQL优化原理与具体实例分析

一、引言 SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是关系型数据库的核心语言。在实际应用中&#xff0c;数据库查询性能往往成为系统性能瓶颈。因此&#xff0c;掌握SQL优化技巧对于提高数据库查询效率具有重要意义。本文将围绕SQL优…

安卓蓝牙扫描流程

目录 系统广播 流程图 源码跟踪 系统广播 扫描开启广播&#xff1a;BluetoothAdapter.ACTION_DISCOVERY_STARTED "android.bluetooth.adapter.action.DISCOVERY_STARTED";扫描关闭广播&#xff1a;BluetoothAdapter.ACTION_DISCOVERY_FINISHED "android.b…

shell 编程(三)

条件测试命令 条件测试&#xff1a;判断某需求是否满足&#xff0c;需要有测试机制来实现 专用的测试表达式需要由测试命令辅助完成测试过程&#xff0c;评估布尔生命&#xff0c;以便用在条件性执行中 若真,则状态码变量$? 返回0 // echo $? 打印0 反之返回1 t…

八股(One Day one)

最近老是看到一些面试的视频&#xff0c;对于视频内部面试所提到的八股文&#xff0c;感觉是知道是什么&#xff0c;但是要说的话&#xff0c;却又不知道该怎么说&#xff08;要不咋称之为八股文呢&#xff09;&#xff0c;所以就想到写一篇八股文总结的博客&#xff0c;以便进…

Rust 在前端基建中的使用

摘要 随着前端技术的不断发展&#xff0c;前端基础设施&#xff08;前端基建&#xff09;的建设已成为提升开发效率、保障产品质量的关键环节。然而&#xff0c;在应对复杂业务场景与高性能需求时&#xff0c;传统的前端技术栈逐渐暴露出诸多不足。近年来&#xff0c;Rust语言…

豆包MarsCode:a替换函数

问题描述 思路分析 在这个问题中&#xff0c;我们的目标是将字符串中的所有小写字母 a 替换为 "%100"。为了实现这一点&#xff0c;我们需要分析问题的核心需求和合理的解决方案。以下是分析和思路的详细步骤&#xff1a; 1. 理解问题 给定一个字符串 s&#xff0…

人脸生成3d模型 Era3D

从单视图图像进行3D重建是计算机视觉和图形学中的一项基本任务&#xff0c;因为它在游戏设计、虚拟现实和机器人技术中具有潜在的应用价值。早期的研究主要依赖于直接在体素上进行3D回归&#xff0c;这往往会导致过于平滑的结果&#xff0c;并且由于3D训练数据的限制&#xff0…

【点估计】之Python实现

点估计是一种统计推断方法,它利用样本数据来估计总体的未知参数。在概率论和数理统计的框架下,点估计将总体的未知参数视为一个确定的值或一个具体的点,并试图通过样本数据来找到这个值的最佳估计。以下是对点估计的详细解释: 一、定义与原理 定义:点估计是根据样本数据估…

rust与python互通

互通三件套 rust侧与python互通的三个库&#xff1a; pyo3 pythonize serde pyo3 pyo3跟用Python C API写python扩展有点类似&#xff0c;核心是&#xff1a; #[pymodule] #[pyfunction]两个注解。前者对应Py_InitModule&#xff0c;后者对应PyMethodDef。 下面是其它博…

Ubuntu系统下 npm install -g tauri 报错问题处理

处理在安装 Tauri 时遇到的问题&#xff0c;可以按照以下步骤进行操作 npm install -g taurinpm warn deprecated inflight1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async …