首页
社区
课程
招聘
[原创]Win PE系列之PE头解析
发表于: 2021-10-10 20:48 11588

[原创]Win PE系列之PE头解析

2021-10-10 20:48
11588

WinPE系列目录:

Win PE系列之PE头解析

Win PE系列之导入表解析与IAT Hook技术

Win PE系列之重定位表解析与模块注入技术

Win PE系列之导出表解析与ShellCode的编写及应用

Win PE系列之一个简单的加密壳的实现

写了一个简单PE的解析器供大家学习,可以解析PE头,导入表,导出表以及重定位表的信息。

github的链接:https://github.com/LegendSaber/PE-Parse

为了解析PE,首先就需要把文件中的内容读到内存中,在这份代码中使用ReadFileBuffer来读取,代码内容如下

关于PE的定义,官网会说是可执行文件啥的,挺不好理解。简单理解的话,其实它就是一种数据结构罢了。大家应该知道CPU只认识二进制数,所以可执行文件保存在磁盘中都是以二进制数保存的,不过为了方便程序员查看,所以市面上的编辑器都是用16进制显示的,比如下面这样。

那我们知道,一个程序中是有不同的组成部分的。有的是用来执行的代码,有的是用来使用的数据等等。而且,不同的程序代码和数据也都是不一样的。那计算机如何知道这个程序哪些二进制数是代码哪些二进制数是数据。这其实就是PE的作用,作为一种数据结构来说明保存的二进制数的意义,告诉计算机哪些是数据哪些是代码。

它的整体结构非常复杂,详细见附件PE结构.pdf,大体的的结构如下图

这是可执行文件在磁盘中的大致样子。节区里面包含的就是代码数据等等内容,而节区上面的那些内容都是用来描述这个可执行文件的信息。

首先是DOS头和DOS存根,它们的存在主要是用来兼容DOS系统。当我们的程序运行在DOS系统的时候,就会运行DOS存根中的代码,代码内容就是输出一段字符串告诉用户,这个程序不能在16位系统运行。

而DOS头保存了程序的信息,DOS头的定义如下

这里面有用的信息就两个

第一个成员e_magic,作为判断是否为PE文件的一个表示,如果不是"MZ"(16进制0x5A4D),那就不是PE文件,如果是还要看PE头标识。

最后一个成员e_lfanew,指定PE头的开始位置距离文件的偏移,它的数值就是NT头的开始地址。如下图,这里是E8,那么NT头开始地址就是E8的地方。

接下来是NT头,定义如下

Signature是PE表示,如果不是"PE"(16进制0x00004550)就不是PE文件,它和DOS头的e_magic两个成员共同说明这是否是一个PE文件。

据此就可以写出如下代码来判断加载的文件是否是一个PE文件

其中的IMAGE_DOS_SIGNATURE和IMAGE_NT_SIGNATURE在文档中的定义如下

FileHeader是一个IMAGE_FILE_HEADER的结构体,定义如下

FileHeader的大小是20,在文档中用如下定义来表示它的大小

Machine指定了程序可以运行的CPU的型号,常见的是下面这几种

NumberOfSections指定了节区的数量,也就是最上面的那张图中的.txt,.idata这些用来保存数据和代码等等的区域的数量。

SizeOfOptionalHeader指定了可选头,也就是FileHeader的下一个数据的OptionHeader的大小。

Characteristics说明了文件的一些属性,常见的如下

接下来就是OptionalHeader,它是一个IMAGE_OPTIONAL_HEADER的结构体,定义如下

Magic的值指定这是32位的PE还是64位PE,文档中定义如下

AddressOfEntryPoint指定了程序启动以后开始运行的第一行代码相对于基地址的偏移。

ImageBase指定了程序加载到内存中的基地址,对于exe的主程序文件通常是0x40000。

SectionAlignment指定了在内存中的节区对齐大小(通常是0x1000)。

FileAlignment指定了在磁盘中节区对齐大小(通常是0x400或者0x1000)。

为了寻址方便,操作系统将文件装载进内存的时候,会根据SectionAlignment来进行节区对齐,也就是说如果这个节区中的数据不足SectionAlignment个,操作系统就会在后面补0,为了让下一个节区装置进内存的地址刚好是SectionAlignment的整数倍。

而为了节约磁盘空间,文件保存在磁盘中的时候,会以FileAlignment指定的值进行对齐,这个值正常情况下都小于等于SectionAlignment,如下图

可以看到,由于FileAlignment和SectionAlignment的大小不同,在文件中,每个节区都是0x400的整数倍保存,而在内存中则需要填入NULL来扩展到0x1000的整数倍。

SizeOfImage指定了将整个PE程序张载到内存中以后所占内存的总大小,它是SectionAlignment的整数倍。

SizeOfHeader指定了整个PE头的大小,该值是FileAlignment的整数倍。

Subsystem用于区分驱动文件与可执行文件,定义如下

DllCharacteristics通常用来说明文件是否可以重定位,当它与下面这个宏定义&以后如果为1则可重定位

DataDirectory是由IMAGE_DATA_DIRECTORY结构体组成的数组,数组一共16项,在文档中有如下定义

数组每一项都描述特定的一张表的数据,如下


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-2-10 21:50 被1900编辑 ,原因:
上传的附件:
收藏
免费 8
支持
分享
最新回复 (1)
雪    币: 566
活跃值: (3583)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
写的精干简练,比起直接看大部头书好很多
2022-12-25 00:17
1
游客
登录 | 注册 方可回帖
返回
//