(简称逆向工程核心原理第十八章第十九章)
UPack简介,以特种的方式使PE头变形,经常被检测成病毒
使用方法:upack target.exe
(会覆盖原文件)
分析UPack的PE文件头
1. 重叠文件头
根据PE文件规范,NT的起始位置是可变的,于是在upack中就把NT的偏移换了个位置
1 | e_lfanew = MZ文件头大小 + DOS存根大小 = E0 |
UPACK中e_flanew的值为10,并不违反,钻了空子,这样就把MZ文件头和PE文件头重合到了一起
2. IMGET_FILE_HEADER.SizeOfOptionHeader
32位文件的可选头是确定为E0
64位可选头是F0
而在Upack中是148
紧接着可选头的好像是节区头,更准确的说,
1 | IMAGE_OPTIONTAL_HEADER(28) + SizeOfOptionalHeader(148) = 170 //才是节区头的位置 |
所以UPack是想干嘛!?
在增大了可选头的大小,在可选头与节区头之中的区域有了额外空间,UPack就在里放入解码代码
可选头结束的位置是D7(这个稍后解释)
实际上都是解码代码,所以那些PEview类似的工具会解析异常
3. IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes
上面的疑虑为什么结束位置是D7,因为原本长度为10h的数组变成了A,后面的都舍弃了
4. 重叠节区头
发现第一节区和第三节区的文件偏移和大小都是一致的,而在内存偏移中不一样
这边需要第二节区的大小很大,实际上所有压缩后的文件映像都在第二节区
整理一下,压缩在第二节区的映像,在解压缩同时同时会被记录到第一节区,nodepad原文件的内存映像会被整体解压,正常使用
文件映射到内存的情形
5. RVA to RAW
UPack的一个精彩点就在这,利用了Windows PE装载器的Bug
拿程序EP来举例
1 | RAW = 1018 - 1000 + 10 = 28 |
问题就在这,FileAlignment规定了 PointerToRawData 的值应该为此的整数倍,UPack的FileAlignment为200,所以应该为整数倍,但第一个节区为10,这种情况通常被转换为0,所以正确的偏移是18h!
1 | RAW = 1018 - 1000 + 0 = 18 |
于是看下调试器
Bravo!
6. 导入表(IMAGE_IMPORT_DESCRITOR)
导入表属于第三个节区271EE,通过转换可得知是1EE
查看1EE,发现正确的IAT结构体应该是到了201,但是200和201既不属于第一个结构体也不是第二个结构体
当映射的时候,200和201是不会映射过去的,问题就是出在这了!!有些PE实用程序从文件中读导入表就会引用错误内存从而报错
但映射到内存的时候,单节区大小SectionAlignment为1000,剩下的800h会给全部填充给00,于是在内存中引用的时候不会出错!
(这个玄机还真是妙啊)
7. 导入地址表
现在分析下刚刚的结构体,也就是IID(IMAGE_IMPORT_DESCRITOR)
几个关键成员
Name
IAT
INT 虽然烂掉了,但是只要INT或者IAT其中有一个有API名称字符串即可
可以看到两个导入的API函数,分别为LoadLibraryt与GetProcAddress,他们在形成原文件的IAT非常方便,所以普通压缩器也常常导入使用
UPack调试
1. 查找OEP
早版的dbg是会报错的,现在dbg不报错了直接定位到了EP位置了
调整新EP方法(如果刚进去不在这)
2. 解码循环
前两条指令把OEP压入了堆栈
这是decode()函数的地址,会反复调用执行该函数(具体干了什么还没分析)
这两条指令向EDI所指的位置写入了内容,而EDI指向的就是第一个节区的地址
这里配合jb/cmp指令继续循环,于是可以一直观察EDI所指向的地址写入了什么值
3. IAT
在解压缩完代码会根据原文件恢复IAT
UPack也类似
Ret OEP!
最后弹出堆栈!
跳到OEP!
(2022.3.12 14:48记 今天先记录到这 UPack分析还需要看看具体怎么执行)
About this Post
This post is written by P.Z, licensed under CC BY-NC 4.0.