March 10, 2022

关于逆向工程核心原理-UPack壳

(简称逆向工程核心原理第十八章第十九章)

UPack简介,以特种的方式使PE头变形,经常被检测成病毒

使用方法:upack target.exe

(会覆盖原文件)

分析UPack的PE文件头

1. 重叠文件头

根据PE文件规范,NT的起始位置是可变的,于是在upack中就把NT的偏移换了个位置

image-20220310145613670

1
e_lfanew = MZ文件头大小 + DOS存根大小 = E0

UPACK中e_flanew的值为10,并不违反,钻了空子,这样就把MZ文件头和PE文件头重合到了一起

2. IMGET_FILE_HEADER.SizeOfOptionHeader

32位文件的可选头是确定为E0

64位可选头是F0

而在Upack中是148

image-20220312125309668

紧接着可选头的好像是节区头,更准确的说,

1
IMAGE_OPTIONTAL_HEADER(28) + SizeOfOptionalHeader(148) = 170	//才是节区头的位置 

所以UPack是想干嘛!?

在增大了可选头的大小,在可选头与节区头之中的区域有了额外空间,UPack就在里放入解码代码

可选头结束的位置是D7(这个稍后解释)

image-20220312130005253

实际上都是解码代码,所以那些PEview类似的工具会解析异常

image-20220312130141723

3. IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes

上面的疑虑为什么结束位置是D7,因为原本长度为10h的数组变成了A,后面的都舍弃了

image-20220312130917276

4. 重叠节区头

发现第一节区和第三节区的文件偏移和大小都是一致的,而在内存偏移中不一样

这边需要第二节区的大小很大,实际上所有压缩后的文件映像都在第二节区

整理一下,压缩在第二节区的映像,在解压缩同时同时会被记录到第一节区,nodepad原文件的内存映像会被整体解压,正常使用

image-20220312131703000

文件映射到内存的情形

image-20220312132337706

5. RVA to RAW

UPack的一个精彩点就在这,利用了Windows PE装载器的Bug

拿程序EP来举例

image-20220312132717536

1
2
RAW = 1018 - 1000 + 10 = 28
//内存基地址是1000 文件基地址是10

问题就在这,FileAlignment规定了 PointerToRawData 的值应该为此的整数倍,UPack的FileAlignment为200,所以应该为整数倍,但第一个节区为10,这种情况通常被转换为0,所以正确的偏移是18h!

1
2
RAW = 1018 - 1000 + 0 = 18
//内存基地址是1000 文件基地址是10

于是看下调试器
Bravo!

image-20220312133536613

6. 导入表(IMAGE_IMPORT_DESCRITOR)

导入表属于第三个节区271EE,通过转换可得知是1EE

image-20220312135306602

查看1EE,发现正确的IAT结构体应该是到了201,但是200和201既不属于第一个结构体也不是第二个结构体

image-20220312135631964

当映射的时候,200和201是不会映射过去的,问题就是出在这了!!有些PE实用程序从文件中读导入表就会引用错误内存从而报错

image-20220312135853583

但映射到内存的时候,单节区大小SectionAlignment为1000,剩下的800h会给全部填充给00,于是在内存中引用的时候不会出错!

(这个玄机还真是妙啊)

image-20220312140322468

7. 导入地址表

现在分析下刚刚的结构体,也就是IID(IMAGE_IMPORT_DESCRITOR)

几个关键成员

image-20220312140837193

Name

image-20220312140904390

IAT

INT 虽然烂掉了,但是只要INT或者IAT其中有一个有API名称字符串即可

image-20220312141040078

可以看到两个导入的API函数,分别为LoadLibraryt与GetProcAddress,他们在形成原文件的IAT非常方便,所以普通压缩器也常常导入使用

image-20220312141150963

UPack调试

1. 查找OEP

早版的dbg是会报错的,现在dbg不报错了直接定位到了EP位置了

image-20220312142144807

调整新EP方法(如果刚进去不在这)

image-20220312142438406

2. 解码循环

前两条指令把OEP压入了堆栈

image-20220312142926129

这是decode()函数的地址,会反复调用执行该函数(具体干了什么还没分析)

image-20220312143854461

这两条指令向EDI所指的位置写入了内容,而EDI指向的就是第一个节区的地址

image-20220312144236321

这里配合jb/cmp指令继续循环,于是可以一直观察EDI所指向的地址写入了什么值

image-20220312144112653

3. IAT

在解压缩完代码会根据原文件恢复IAT

UPack也类似

image-20220312144622600

Ret OEP!

最后弹出堆栈!

跳到OEP!

image-20220312144715388

(2022.3.12 14:48记 今天先记录到这 UPack分析还需要看看具体怎么执行)

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.