电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 534 人浏览分享

逆向之Windows PE结构

[复制链接]
534 0
写在前面

对于Windows PE文件结构,个人认为还是非常有必要掌握和了解的,不管是在做逆向分析、免杀、病毒分析脱壳
加壳都是有着非常重要的技能。但是PE文件的学习又是一个非常枯燥过程,希望本文可以帮你有一个了解。

PE文件结构的基本介绍

先来大概说说什么是PE文件格式,PE(Portable Executable),也就是我们说的可执行文件在Windows中exe,dll,
sys,ocx文件都是PE文件格式。而PE文件结构就是所有的PE文件按照结构的方式组织是有规律的排列组成。
从整个PE件结构大概来分成2部分,PE头和PE体。PE头又存在MS-DOS头和NT头(PE头),PE体主要就是一些表
结构构成,存放代码,数据,资源等。后面我们开始对这些信息进行逐一分析和讲解。

MS-DOS头

首先来看DOS头,DOS头位于整个PE文件的首位部分,是PE文件结构的第一个头,对于现在的系统来说作用就是用
来定位真正的PE头。在peview中可以看到对应IMAGE_DOS_HEADER和MS-DOS Stub Program,IMAGE_DEBU
G_TYPE这里可以忽略,是调试类型,对应debug和relese。

QQ截图20220429111751.png

在二进制中查看,以4D 5A开头,十六进制转ASCII码就是MZ,是MS-DOS设计者名字缩写

1649987539_6258cfd3a4b3664e712f3.jpg

在010 editor或者peview中,可以看到header占位在00000000-0000003C,而整个大小是64字节
额外需要注意的字节顺序,以小尾方式存在。

200.jpg

来看具体的IMAGE_DOS_HEADER是在winnt.h中定义,对于我们来说,我们只关心两个参数,e_magic是
程序的头指纹和e_lfanew是指向真正PE头偏移地址。

199.jpg

这里我们可以尝试修改上面程序,将除了e_magic和e_lfanew对应的地址全部修改成0,可以看到程
序还是可以正常运行。所以有用的数据只占6个字节(e_magic为WORD型占2个字节,e_lfanew
为DWORD型占4个字节)

198.jpg

QQ截图20220429112243.png

MS-DOS stub Program是DOS头的代码块,告诉用户程序不能在DOS下运行。

197.jpg

NT头(PE头)

PE头以50 45 00 00 开头,也就是PE..

196.jpg

来看下PE头结构IMAGE_NT_HEADERS,包括3个部分,Signature,IMAGE_FILE_HEADER,IMAGE_OPT
IONAL_HEADER32(或64),而PE..就是Signature字段,这个字段是PE文件标准特征,是不能进行修改的
强行修改后程序无法正常运行。

QQ截图20220429112457.png

IMAGE_FILE_HEADER共20字节,其中重要有4个部分,从010editor中可以看到Machine,Numb
erOfSections,TimeDateStamp,Characteristics这4个部分是最重要的。

195.jpg

189.jpg

Machine

共4个字节头两个字节表示机器类型,用于标识CPU的类型,后两个字节表示CPU为Intel 386或后
继处理器及其兼容处理器。具体机器类型的值可以在010中自行查看。

188.jpg

NumberOfSections

表示节的数目,这里的节的数目指的就是区段表的数量,这里我们显示5,说明有个区段表数。

187.jpg

也可以利用lordpe查看区段表。

99.png

TimeDateStamp

为时间戳,也就是PE文件创建的时间。

Characteristics

文件属性的标志,共15个常用属性标志,每个bit都有不同含义,如下在010中可以看到:
我们从上往下进行看:
IMAGE_FILE_RELOCS_STRIPPED:为1表示文件中没有重定向信息
IMAGE_FILE_EXECUTABLE_IMAGE:为1表示该文件是可执行文件
IMAGE_FILE_LINE_NUMS_STRIPPED:为1表示文件中不存在行信息
IMAGE_FILE_LOCAL_SYMS_STRIPPED:为1表示没有局部符号信息
IMAGE_FILE_AGGRESIVE_WS_TRIM:表示调整工作集
IMAGE_FILE_LARGE_ADDRESS_AWARE:为1表示程序能处理大于2G的地址
IMAGE_FILE_BYTES_REVERSED_LO:小尾方式
IMAGE_FILE_32BIT_MACHINE:为1只在32位平台上运行
IMAGE_FILE_DEBUG_STRIPPED:为1不包含调试信息
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP:为1不能从可移动盘运行
IMAGE_FILE_NET_RUN_FROM_SWAP:为1不能从网络运行
IMAGE_FILE_SYSTEM:为1表示文件为系统文件而不是程序
IMAGE_FILE_DLL:为1表示是一个dll文件
IMAGE_FILE_UP_SYSTEM_ONLY:为1表示文件只能运行于单处理器机器上
IMAGE_FILE_BYTES_REVERSED_HI:大尾方式

129.jpg

再来看看PE头下的可选头IMAGE_OPTIONAL_HEADER,它是PE头部重要的部分,之所以被称为可
选头是指该结构体的部分数据在不同文件中是不同的。

89.jpg

88.jpg

同样,对照010中对不同的PE文件可进行分析查看修改。

87.jpg

节表

PE文件所有的节属性都定义节表中节表是由IMAGE_SECTION_HEADER结构排列而组成的
且节表的位置在MS-DOS+PE头下面。

86.jpg

IMAGE_SECTION_HEADER结构

59.png

对于上面的字段来说,我们来说一说重要的的字段。在说字段前,再把三个地址概念复习下,后面会具体说地址转换计算。
1.VA:VirtualAddress虚拟内存地址,范围00000000h - 0fffffffh,就是进程的基地址 + RVA相对虚拟内存地址。 2.RVA:
相对虚拟内存地址。 是PE文件中的数据、模块等运行在内存中的实际地址相对PE文件装载到内存的基址之间的距离如果PE
文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h
3.FOA:文件偏移地址,文件头的偏移地址。

NAME

8个字节ASCII的名称,必须要8个字节,不够可以用null值来填充,这里的名称可以自己起也可以编译器来定义。

58.jpg

VirtualSize

对应表的区块的大小,这是区块的数据在没有进行对齐处理前的实际大小,通俗的来说就是节的数据真实大小。

VirtualAddress

该区块装载到内存中的RVA 地址。

SizeOfRawData

文件偏移量(文件大小)

PointerToRawData

指出节在磁盘文件中所处的位置。这个数值是从文件头开始算起的偏移量。

Characteristics

节的属性,可读写等。

地址转换

前面说到三个地址,学习地址转化可以对程序的一些功能修改或添加,地址转化非常重要
后面的加密,对壳的操作,对感染性病毒修复都非常关键。
还是以前面的程序节表来看。

58.jpg

我们来计算hello world!字符串偏移地址。

39.jpg

首先可以看到字符串起始位置是983006,结束在983011。

38.jpg

计算过程:

1.通过VA转RVA
用起始位置-程序入口地址,程序入口地址980000,也就是
983006-980000 = 3006 RVA地址
这里说明一点,计算是十六进制计算,后面都一样。

2.找RVA所在的节
可以看到3006是在.data0983000到0098400之间,所以所属的节是.data

57.png

3.计算.data节起始的RVA和起始的FOA的差值
3000-A00=2600

4.通过RVA减去差值
3006-2600 = A06
用010打开exe程序,可以看到字段起始和我们计算出来的一致

36.jpg

在lordpe中直接算偏移量,可以看到和我们算出的一致。

21.png

添加节,给程序做入口弹框

对于加壳保护,病毒来说,一般情况下都会添加节,会将可执行程序保护的代码或者将病毒代码写在新添加的节中。
步骤:1.增加节表项;2.修正文件的映像程度;3.修正一个节的数量;4.增加文件的节数据。

以PEview程序为例,添加一个弹框。

用lordpe打开程序,首先看到区段表数量是5

20.png

选择一个表名称,右键-添加区段

19.png

将所有的地址记下来
00015000 00000000 00010A00 00000000 E00000E0
对于不清楚含义的可以再回头看看

18.png

先将映射入内存后的长度(虚拟大小)改为1000,将磁盘文件中的长度(物理大小)改为200

17.png

在区段标志(节属性)中,将可写和初始化去掉,节属性变成60000020。

16.png

字节大小转换:
前面我们插入200长度大小,为16进制,转换成10进制为512个字节
将程序使用010打开,在文件末尾添加512个字节,可以看到最末一个是109FF,109FF+1刚好是10A00

15.jpg

所以添加数据从最后一位插入512个字节数据

14.jpg

修正大小,前面将虚拟内存的大小修改为1000,镜像大小还是15000,发现程序是无法运行的

13.png

将镜像大小修正为16000

12.png

再次打开可以运行

11.png

接下来添加我们需要的程序。
反编译进行调试,发现程序入口的位置是00401000,再往下走程序就运行了。

10.jpg

前面我们说过程序的入口是imagebase(基地址)+entrypoint(入口点)组成我们回
头再验证一下,加起来为00401000一致。

9.png

所以需要程序从我们给添加的节开始执行,我们添加的节是00015000 所以需要让入
口点修改为我们的节地址。新的入口点00415000。

8.jpg

选定00415020,右键转储跟随选定的地址。

7.jpg

编辑内容,同样在00415030出编辑内容。

6.jpg

在程序入口处00415000写入弹框

5.jpg

然后再入口处F8单步调试,发现成功弹框。

4.jpg

然后还没有成功,这里只是弹框,没有打开我们PEview主程序,还需要进行跳转 跳转的位置就是最开始的
00401000这个位置,jmp 00401000,然后步入,可以发现主程序打开。

3.jpg

接着保存数据,修改的数据全部选中,右键复制到可执行文件

2.jpg

右键保存文件

1.jpg

就完成了通过添加节,添加一个弹框案例。

后记

WindosPE文件结构还有几个节表本次没有涉及到,后面可以自行了解。对于逆向来说PE文件结构是基础中的基础
不仅要对汇编熟悉,还要懂得调试程序,后面我会讲讲脱壳加壳的内容。大家一起努力吧!

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.