首页
社区
课程
招聘
[原创]以一个恶意样本为示例来剖析PE结构
发表于: 2021-5-14 22:56 11084

[原创]以一个恶意样本为示例来剖析PE结构

2021-5-14 22:56
11084

前言
先分析解密再进行剖析其PE结构(骚操作,这样分析病毒耗时间),本次编写的原因也是为了大家方便参阅。主要还是为了分析PE结构,让大家掌握PE结构。分析的病毒,主要分析待解密数据的来源,解密key的位置以及通过运算进行解密。

使用Total Commander打开恶意样本,进行初步样本分析
无壳:

查看导入导出表
可以发现没有导出表,那么就可以判定这可能是一个exe程序

切换成汇编的视图,可以看到第一个调用的是GetVersion,那么就可以知道这是一个VC6.0的程序。一些运算的操作。

那么就可以判定这并不是恶意程序真正的本体。
也可以通过lordPE工具查看是否有问题,看到RVA相差这么大,肯定加了混淆。

在这个窗口单击编辑区段,标志代码段还拥有可写入的权限,那么就更确定了。


对比正常区段看看

既然做了运算类似自己加了一层壳的操作,那么必然会进行解密操作,就会使用诸如VirtualAlloc这一类申请内存的操作。那么我们就可以通过对VirtualAlloc下软件的断点来进行内存空间的查看。这里就需要用到OD来进行动态的分析了。
关于内存的一些函数(感觉大多数恶意样本的作者更钟情于VirtutalAlloc?):
https://blog.csdn.net/lqk1985/article/details/4678044?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242
在这之前,使用的是x64dbg来下断点的,但是,F9一运行,程序直接跑偏了(x64dbg默认不带反反调试的功能),那么就可知,程序可能有反调试和反虚拟机的功能,查找字符串时,应重点关注,并且运行完毕后,做了删除自身的操作。
在VirtualAlloc处下断点,根据size参数猜测是否是为PE文件申请的空间,当VirtualAlloc第二次断下的时候,设置硬件写入断点。
第一次断下:

第二次断下:

F8单步步过执行到调用此函数的位置,在申请出来1D30000的位置下word大小硬件写入断点。

F9运行:
第1次写入了E8,第2次写入了C7,那么就可知,每次写入的都是1byte

第3次F9就再次访问到了这块内存空间,会发现第一个字节被修改了,从E8变成了4D。

那么F8单步,可以看到12F9F6处有个向上跳转的红线,那么就可以确定这是个循环操作。

F4让程序运行到12F9F8处可以看到,在内存1F10000处标准的PE文件格式,那么这就是恶意样本真正的本体。那么经过什么样的运算得到最终的值呢,接下来我们就溯源分析一下。

重新运行程序,这里需要删除之前下的硬件写入断点,因为每次申请出来的空间都是不一样的,再次运行到申请的内存处观察。
待解密的数据来源:

可以看到的是1EB0000处的值被修改了,那么从12F99B处往上观察,得出:[eax+edi]=dl=[ecx]=[ebp+ecx4-0x54],eax+edi就代表申请的内存空间,最终找到变址寻址处[ebp+ecx4-0x54],ctrl+g输入ECX转到内存。可以发现在4020B0处的1byte确实是申请的空间放入的值。

那么我们继续F9看看是否还是在此处取值,发现并不是28,由上图可知。

那么再次查看ECX,发现在4D6A10处正是申请空间的第2字节处。

在dl赋值向下的位置F8执行,可以看到红色框内,在ebp-0x8处取出了一个数赋值给ecx,把ebp+ecx4-0x54赋值给edx,并且edx自增1后,再把值还给ebp+ecx4-0x54,ecx的值也在自增,并且ecx自增1后把值还给了ebp-8处,可以从下图看到ecx的是2,刚好也在第二个地址处进行取数据,最后ecx和0x8进行比较,如果不满足条件,ecx置0,并且把值赋给ebp-8处。在这里为什么地址是需要乘4呢,因为指针大小为4,每次ecx自增1时,乘4就可以找到下一个存数据的位置,这叫变址寻址。

查看EBP-0X54处,那么可以确定的是,一共有8处是取数据的地方。

也可以确定的是在4020B0处和4D6A10处数据每次都自增1,并且后面还有6次取数据的操作。从12F9B8的位置处开始,ebx+0x10的值赋值给edx,edi自增1,并且存在循环,进行判断,如果edi大于edx那么就不会执行跳转。由下图可知,edx==DCA00那么就可以知道,整个程序的大小为DCA00。

解密key的来源及运算:
可以看到红色框的部分,cl把解密后的数据给了eax+edx,把一个临时变量ebx-0x10的值赋值给了ecx,edx自增,然后ecx和edx进行比较,然后向上跳转绿色框部分,那么就可得,ecx存储的是程序的大小DCA00,当edx小于DCA00时结束循环。

从绿色框开始位置12F9D0,ebp-0x8把值给edi,然后从edi+ebx处取解密key赋值给cl,从申请的存放数据的地方和cl进行异或运算,cl再和dl进行异或运算,edi自增,并与0xF进行比较,再把edi还给ebp-0x8,如果条件不成立edi置0,那么就可以确定从edi+ebx处53FA20-53FA2F的数据和申请的存放数据的地方和cl进行异或运算后,再依次和0x0-0xF进行异或运算。最后得到最终的PE文件。
解密key:

通过去除混淆,Dump出一个.mem文件,进行PE结构的分析

手工解析DOS结构体、NT结构体,以及区段表结构体里面重要的成员,重要成员的分析是以lordPE工具为参照进行划分的,当然,分析也包括结构体里面的嵌套结构体。
DOS结构体:


DOS头结构体大小:0x40
检测是否是PE文件,判断开始两个字节是否为IMAGE_DOS_SIGNATURE(0x5A4D)
最后4个字节为NT头的文件偏移:0x108
接下来看看NT头也叫PE头:


在文件中NT头是从0x108开始的。可以看到NT头包含了两个结构体,分别是文件头和选项头由颜色可知,接下来重点分析这两个结构体的成员。
NT头结构体大小:0xF8
文件头:


文件头结构体大小:0x14
判定是什么程序:Machine: x86(0x014C) x64(0x8664)、SizeOfOptionalHeader扩展头(也叫选项头)大小: x86(0xE0) x64(0xF0)、Characteristics: 标志位 x86(0x0100) x64(0x0020)
NumberOfSections值是0x5,那么就表示区段有5个,可以看到之前dump出来的区段数量就是5个。
Characteristics其它值可通过微软的官方查看,我这里把它也拷贝下来了

啰嗦一句文件头里面的值除了第一个成员和最后一个成员不可更改,其余的值其实是可以更改的,程序作者有时为了不让别人使用工具分析程序,如lordPE等工具查看其结构,会进行值的改变,破坏其值。让工具无法正确的解析。
扩展头:


判定是什么程序:Magic: x86(0x010B) x64(0x20B)
代码区段的总大小:0x8FA00
OEP的入口点RVA(相对虚拟地址):0x66C4B
代码区段的起始RVA(相对虚拟地址):0x1000
只读数据段的RVA(相对虚拟地址):0x91000
程序的模块基址:0x400000
内存中的区段对齐:0x1000
文件中的区段对齐:0x200
在内存中的程序总大小:0xE7A10
DllCharacteristics特性:高位:0x81防止在已标记为数据存储区的内存区域中执行代码。 此功能也称为非执行和执行保护。低位0x40:DLL可移动的,表示是存在随机基址的,如果把值置为0则以默认基址0x400000为准。
因为涉及了RVA这样的术语,那么在这里做一些术语的补充:
FOA(offset):文件偏移地址,相对于文件起始的偏移
RVA:相对虚拟地址,通常是相对于模块加载基址的偏移,少数情况下,相对的是其它
VA:虚拟地址,在4GB虚拟空间中的绝对地址
镜像(没跑):保存在磁盘中的可执行文件,如果对PE文件使用了类似CreateFile的函数那么就变成了映像(运行在内存中)了
IMAGE_DATA_DIRECTORY DataDirectory[16]数据目录项:

像这样的结构体只有15个,但是会有一个全0为结尾的8字节字符作为预留位置
相应的表结构:


在这里,我们要明白,使用010Editor打开PE文件时,我们所看到的值,是和运行在内存中的数据相同的,都是以补码的形式存在的,程序运行时,称之为映像文件。我们通过静态查看时,称之为镜像文件,想要定位对应的数据,是只能通过文件的方式进行定位,而不能通过内存的方式进行查看,文件对齐和内存对齐的值是不一样的,所以是需要进行值的转换的。

我们现在还不能通过已知的信息在文件中进行位置的定位,也就是找到文件偏移,需要知道了区段的数据才能够进行计算,下面我们继续看区段表结构。
区段结构体:

可以看到的是之前在文件头里面已知的数据FileHeader.NumberOfSections的值是5,那么就可得5*0x28+0x200=0x2C8,存在5个节大小一共是0xC8,区段到文件位置0x2C8结束。

Misc.VirtualSize:区段在内存中对齐之前的大小
VirtualAddress:区段的起始RVA,因为是第一次出现的所以说是起始RVA就相当于在内存中的相对偏移地址,之前有介绍那么就可以得到一个公式:RVA+Optional.ImageBase=VA(绝对偏移地址)这是在内存中可以找到的,当然,前提是没有随机基址。
SizeOfRawData:在磁盘中文件对齐后的大小,加上FOA文件偏移后那么就可以定位下一个区段的位置。
PointerToRawData:在磁盘中FOA(文件偏移),没有基址,所以是0x400那么在文件中就在这个位置是代码段的开始。
Characteristics:区段的属性,分析病毒时可以根据标志观察是否加壳,如果加了壳,代码段就变成可读可写可执行了,正常的代码段只能是可读可执行,在这里是60000020,如果是加了可执行那么就是E0000020了。可以查看一下未脱壳的样本的标志。
最后可以整理出来一个表:

在这之前数据目录表还有文件偏移没有确定,现在已经可以通过已知信息找到5个表文件偏移位置了。
这里会用到一个公式:数据目录表中的RVA-某个区段的RVA+文件偏移
就可以得到一个FOA的值去定位在文件中的位置了。
当然了需要确定是在哪个区段里面,就要确定数据目录表的值是在哪个区段的范围里面。
例如求导入表的文件偏移:
查看表可知,RVA=0xB9494,它是在.rdata只读数据段
那么可得:0xB9494-0x91000+0x8FE00=0xB8294
剩下的几个表都一样的计算方法,这里就不在演示了。那么就完成了下面表结构缺省的文件偏移。

接下来会手工分析数据目录表中的导入表。
导入表:

INT和IAT在还是文件的时候,里面存储的东西是一样的,都是指向PIMAGE_IMPORT_BY_NAME的RVA中Hint导入序号或者Name函数名称。
但是从字面理解IAT应该是存储地址的,为什么会存储名称。因为在程序没有运行的时候,无法得到此模块会加载到什么位置,也就无法得到函数地址是多少。当程序运行起来之后,系统会去将IAT填充上函数的地址。
根据数据目录表可知,导入表大小是0x140,根据上述结构体大小可知是0x14,那么就知道了导入了多少个DLL程序,0x140/0x14=0x10,并且导入表会有一个以全0为结束的结构体标志,那么就可得0x10-0x1=0xF,那么就有15个导入的DLL文件。
通过计算0xB8294+0x140=0xB83D4找到如下16进制段:

Oh!红配绿,醒目, 要知道这里的值也只是RVA并不是真正的文件位置,还得进行转换,计算方式和之前一样,数据目录表中的RVA-某个区段的RVA+文件偏移。
在这里可以通过计算找到Name成员值:0xB9DC6-0x91000+0x8FE00=0xB8BC6,可以看到的是一个关于网络的DLL

我们还得确认是序号导入还是函数名称导入。我们接下来看看两个结构体。

在这个磁盘中起作用的只有只有后两个成员
当 IMAGE_THUNK_DATA 值最高位是1表示是一个序号,序号导入起作用。内存地址最大表示2GB 7FFF FFFF进入了内核层地址超过了8
最高位是0最后一个成员起作用
最高位是否为1可以使用系统提供的
如果是最后一个成员起作用,那么就指向如下结构体:

Hint 字段表示函数的序号
Name字段定义了导入函数的名称字符串,这是一个以 0 为结尾的字符串。
那么现在就通过计算找到的值查看是否高位是INT计算后高位是否是以8开头的:
INT:0xB9C60-0x91000+0x8FE00=0xB8A60
定位到此文件偏移处:

确定高位不是8,那么再次计算:
Hint=0xB9D0C-0x91000+0x8FE00=0xB8B0C=0x009A
紧跟着的则是导入函数名称:

IAT:0x9168C-0x91000+0x8FE00=0x9048C值和INT是一样的:

从查看INT和IAT的RVA,以全0结尾就代表了一个dll库的函数API的数量,那么就可以确定WININET.dll库函数的API会是0x9个并且第一个API函数是InternetOpenW。
最后总结一下,名称表元素的个数和序号表元素个数是相同的,地址表中的元素可能会比序号表和名称表元素个数要多。地址表中多出来的,就是没有名称的函数,或者是无效的函数。


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

最后于 2021-5-27 18:44 被APT_华生编辑 ,原因:
上传的附件:
收藏
免费 4
支持
分享
最新回复 (7)
雪    币: 3906
活跃值: (3579)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
欢迎提问。
2021-5-18 14:47
0
雪    币: 1475
活跃值: (14652)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
3
为什么这套工具好像是火绒的far呢
2021-5-18 14:59
0
雪    币: 3906
活跃值: (3579)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
SSH山水画 为什么这套工具好像是火绒的far呢
Total Commander吗,这是我学习姜烨老师的课程学到的,OD的话是外星人
2021-5-18 15:06
0
雪    币: 1475
活跃值: (14652)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
5
APT_华生 Total Commander吗,这是我学习姜烨老师的课程学到的,OD的话是外星人
可以,有时间我也去看看
2021-5-18 15:11
0
雪    币: 8201
活跃值: (2701)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
什么工具?显示不是Hiew吗?
2021-5-18 16:40
0
雪    币: 3906
活跃值: (3579)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
option 什么工具?显示不是Hiew吗?
Total Commander文件管理器对着样本F3会显示Hiew,Hiew配合Total Commander很方便
2021-5-18 16:49
0
雪    币: 3906
活跃值: (3579)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
刘某人逮着你了
2021-7-14 21:13
1
游客
登录 | 注册 方可回帖
返回
//