感谢互联网的知识分享。
PE文件的全称是Portable Executable ,意为可移植的可执行文件,常见的有EXE,DLL,SYS,COM,OCX,PE文件是微软Windows操作系统上的程序文件。
简单来理解,就是一种数据结构。我们知道知道CPU只认识二进制数,所以可执行文件保存在磁盘中都是以二进制数保存的,不过为了查看,所以市面上的编辑器都是用16进制显示的,比如下面这样,使用010Editer打开一个PE文件:
PE文件结构如下:
有的数据结构是用来执行的代码,有的数据结构是用来保存数据。
首先是DOS头和DOS存根,它们的存在主要是用来兼容DOS系统。当我们的程序运行在DOS系统的时候,就会运行DOS存根中的代码,代码内容就是输出一段字符串告诉用户,这个程序不能在16位系统运行。
而DOS头保存了程序的信息,DOS头的定义如下:
这里面有用的信息就两个:
PE头结构如下:
注意:e_magic是word类型,占两个字节;Signature是dword类型,占四个字节。
Signature表示是否是PE,vs中有一个宏来定义它:
PE头其实由两部分组成,一个是标准PE文件头,一个是可选头。
先说标准PE头:
在VS中继续跟进查看PE文件头结构体:
下面做一些重点介绍:
Machine:
微软也给出了相应平台的宏定义:
NumberOfSections:
用loadPE打开一个PE文件,可以看到其区段:
常用区段:
.text: 代码段,里面的数据都是代码,有的编译器也叫做code段,其实都是宏定义的;
.data:数据段(可读写),存放全局变量和静态变量;
.rdata:数据段(只读);
.idata:导入数据区段,存放导入表数据信息;
.edata:导出数据区段,存放导出表数据信息;
.rsrc:资源段;
.bss:存放未初始化数据;
.crt:c++ 运行时库 runtime;
.reloc:重定位;
.tls:线程局部存储。
Characteristics:
PE文件的属性,相应宏定义如下:
其结构体成员如下:
Magic
宏定义PE是32位还是64位
AddressOfEntryPoint:
Subsystem:
可执行文件期望的子系统的值,宏定义如下:
通过C++打印相关成员,在监视中,我们也能看到相关成员的属性值:
区段也是一个结构:
前面我们在loadPE中打开,已经能看到区段表相关信息:
现在通过已经了解到的,模仿loadPE,用控制台程序写一个PE 区段表解析器。
Microsoft Visual Studio提供了一个宏(IMAGE_FIRST_SECTION )来定义定位区段表:
以此来定义一个区段头:
然后去PE文件标准头的地址:
IMAGE_FILE_HEADER 有个值表示了区段数量,可以根据这个数量来进行遍历:
代码如下:
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;
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;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
/
/
运行平台,在不同平台上,其值也不一样
WORD NumberOfSections;
/
/
区段数据数量
DWORD TimeDateStamp;
/
/
文件什么时候被创建的
DWORD PointerToSymbolTable;
/
/
指向符号表的偏移指针
DWORD NumberOfSymbols;
/
/
符号表中的符号数量
WORD SizeOfOptionalHeader;
/
/
文件头扩展头的大小
WORD Characteristics;
/
/
PE文件的属性
} IMAGE_FILE_HEADER,
*
PIMAGE_FILE_HEADER;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
/
/
运行平台,在不同平台上,其值也不一样
WORD NumberOfSections;
/
/
区段数据数量
DWORD TimeDateStamp;
/
/
文件什么时候被创建的
DWORD PointerToSymbolTable;
/
/
指向符号表的偏移指针
DWORD NumberOfSymbols;
/
/
符号表中的符号数量
WORD SizeOfOptionalHeader;
/
/
文件头扩展头的大小
WORD Characteristics;
/
/
PE文件的属性
} IMAGE_FILE_HEADER,
*
PIMAGE_FILE_HEADER;
typedef struct _IMAGE_ROM_OPTIONAL_HEADER {
WORD Magic;
/
/
文件类型的标识
32
位的PE还是
64
位PE
BYTE MajorLinkerVersion;
/
/
链接器主版本号
BYTE MinorLinkerVersion;
/
/
链接器子版本号
DWORD SizeOfCode;
/
/
区段的总大小
DWORD SizeOfInitializedData;
/
/
已初始化数据段的大小
DWORD SizeOfUninitializedData;
/
/
未初始化数据段的大小
DWORD AddressOfEntryPoint;
/
/
程序入口RVA
DWORD BaseOfCode;
/
/
代码段机址RVA
DWORD BaseOfData;
/
/
数据段基址RVA
DWORD BaseOfBss;
/
/
入口点,文件在内存中的首选装入地址
DWORD GprMask;
DWORD CprMask[
4
];
DWORD GpValue;
} IMAGE_ROM_OPTIONAL_HEADER,
*
PIMAGE_ROM_OPTIONAL_HEADER;
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;
/
/
映像文件在装入内存中区段的对齐大小 ,通常是
0x1000
DWORD FileAlignment;
/
/
磁盘中节区对齐大小
WORD MajorOperatingSystemVersion;
/
/
操作系统最低版本的主版本号
WORD MinorOperatingSystemVersion;
/
/
操作系统最低版本的子版本号
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
/
/
保留值 最低为
00000000
DWORD SizeOfImage;
DWORD SizeOfHeaders;
/
/
ms—dos头,pe头,区段表总和
DWORD CheckSum;
/
/
映像文件静态和
WORD Subsystem;
/
/
可执行文件期望的子系统的值
WORD DllCharacteristics;
/
/
dllMain函数何时被调用
ULONGLONG SizeOfStackReserve;
/
/
exe中线程被保存的堆栈大小
ULONGLONG SizeOfStackCommit;
/
/
栈初始化的内存大小 默认大小
4kb
ULONGLONG SizeOfHeapReserve;
/
/
堆初始化的内存大小默认大小
1mb
ULONGLONG SizeOfHeapCommit;
/
/
每次指派给堆的大小,默认
4kb
DWORD LoaderFlags;
/
/
和调试有关 模式
0
DWORD NumberOfRvaAndSizes;
/
/
数据目录成员的数量 一般
16
个
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64,
*
PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_ROM_OPTIONAL_HEADER {
WORD Magic;
/
/
文件类型的标识
32
位的PE还是
64
位PE
BYTE MajorLinkerVersion;
/
/
链接器主版本号
BYTE MinorLinkerVersion;
/
/
链接器子版本号
DWORD SizeOfCode;
/
/
区段的总大小
DWORD SizeOfInitializedData;
/
/
已初始化数据段的大小
DWORD SizeOfUninitializedData;
/
/
未初始化数据段的大小
DWORD AddressOfEntryPoint;
/
/
程序入口RVA
DWORD BaseOfCode;
/
/
代码段机址RVA
DWORD BaseOfData;
/
/
数据段基址RVA
DWORD BaseOfBss;
/
/
入口点,文件在内存中的首选装入地址
DWORD GprMask;
DWORD CprMask[
4
];
DWORD GpValue;
} IMAGE_ROM_OPTIONAL_HEADER,
*
PIMAGE_ROM_OPTIONAL_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-11-30 14:02
被soloz编辑
,原因: