吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 50245|回复: 94
收起左侧

[Scripts] UPX完美脱壳脚本

  [复制链接]
MistHill 发表于 2013-11-15 16:20

UPX Unpacker for Dummies
Version: 1.3.0.459

简单地说,脚本做UPX的"-d"选项相同的事。不过在UPX的"-d"选项不可用时,脚本仍然能完美脱壳

只需要"OllyDbg v1.10"及插件"ODbgScript plugin v1.82.6.110"。
使用方法很简单:
1. OD打开或拖放目标EXE/DLL。在DLL的情况下,OllyDbg会用自身的loaddll.exe加载DLL文件,并停在DllEntryPoint处。
2. 在目标的入口点(EntryPoint)运行脚本。当前eip为EntryPoint是运行脚本的唯一要求。
3. 待ODbgScript显示"Script finished"后,退出OllyDbg。
   不要继续运行或调试目标,脚本使用了目标的内存空间,内容已经变化,继续可能不正常。
4. 运气好的话,在目标的相同文件夹内会生成已脱壳的文件。请检查"Script Log Window"里的内容,有助于排错。

显然,仅支持win32/pe类型的文件,以下讨论也限制在此文件类型。

写脚本时参考了UPX的源码"upx-3.91-src.tar.bz2",在一些细节的处理上还是不太清楚,所以还跟了一下其最近版本"UPX 3.91w(Sep 30th 2013)"的decompress过程,及几个样本自解压的过程。
因为有源码,从技术上讲已经没有难点或秘密之处,但一些不易理解的东西需要揭开面纱,并注意细节。

一.UPX文件结构
经过UPX压缩的win32/pe文件,包含三个区段:UPX0, UPX1, .rsrc或UPX0, UPX1, UPX2(原文件本身无资源时)。
UPX0:在文件中没有内容,它的"Virtual size"加上UPX1的构成了原文件全部区段需要的内存空间,相当于区段合并。
UPX1:起始位置为需解压缩的源数据,目标地址为UPX0基址。紧接着源数据块是"UPX stub",即壳代码。一个典型的pushad/popad结构,所以人们常用"ESP定律"来脱UPX。
.rsrc/UPX2:在原文件有资源时,含有原资源段的完整头部和极少部分资源数据(类型为ICON、GROUP_ICON、VERSION和MANIFEST),以保证explorer.exe能正常显示图标、版本信息。还有就是UPX自己的Imports内容,导出表的库名和函数名(如果有的话)。

这里需要注意的是,压缩的数据是按内存而不是按文件!

二.UPX"-d"选项的烦恼
UPX的"-d"选项在解压缩文件时,需要一个UPX1HEAD结构,它被清除或被修改都会造成UPX拒绝解压。需要借助其他工具来修复或恢复,但并不总能成功。
以"UPX 3.91w"为例来解释这个结构。
[Plain Text] 纯文本查看 复制代码
UPX 3.91w (Sep 30th 2013)
-------------------------
2013-09-30  17:51           305,152 upx391.exe


文件偏移000001F0处:
[Plain Text] 纯文本查看 复制代码
000001F0:  33 2E 39 31.00 55 50 58.21 0D 09 0E.0A 94 06 BB  3.91 UPX!
00000200:  FF 0E 97 35.8F 93 86 19.00 AC 93 04.00 00 E6 18
00000210:  00 26 13 00.BA


整理一下:
[Plain Text] 纯文本查看 复制代码
000001F0:  33 2E 39 31.00       "3.91",压缩时使用的UPX版本ASCII串,无实际意义。
UPX1HEAD(header.S)
000001F5:  55 50 58 21          UPX_MAGIC_LE32: "UPX!",UPX Tag
000001F9:  0D 09 0E 0A          version: 0D; format: 09(UPX_F_WIN32_PE); method: 0E(M_LZMA); level: 0A(--best)
000001FD:  FFBB0694             uncompressed adler32
00000201:  8F35970E             compressed adler32
00000205:  00198693             uncompressed length
00000209:  000493AC             compressed length
0000020D:  0018E600             original file size
00000211:  26 13 00 BA          filter id: 26; filter cto: 13; unused: 00; header checksum: BA

其中:
[Plain Text] 纯文本查看 复制代码
version:             PE file=0C/0D;djgpp2/coff=0E;其它=0D。
format:              可执行文件格式;win32/pe文件为09。
method:              压缩算法;多种:NRV,LZMA和DEFLATE(zlib)等。
level:               压缩级别;1~10.,对应选项:-l1~-l9,--best。
uncompressed adler32:数据解压后/原数据的adler32 Hash。
compressed adler32:  数据压缩后的adler32 Hash。
uncompressed length: 数据解压后/原数据的大小。
compressed length:   数据压缩后的大小。
original file size:  原文件大小。注意:不包含附加数据(Overlay)!
filter id/filter cto:涉及数据压缩理论的重要概念,请参阅"upx-3.91-src\doc\filter.txt"。


概念性地,"filtering"是指在数据压缩前进行预处理,增加字节串的匹配长度,以提高压缩率。
最常见的就是代码部分的E8xxxxxxxx/E9xxxxxxxx(Call/Jmp Near)处理,预处理扫描代码所有的E8/E9指令以找出一个字节作为标识(filter cto),标识字节不应是紧接着E8/E9后的那些字节之一;解压后的"unfiltering"代码会根据这个标识来还原。
当然具体实现时远比这个复杂。印象中ASProtect也有相似的E8/E9处理过程。

解压时,先按源数据的大小计算adler32,比较之,若不相符,终止不再继续;然后按format/method执行相应的解压模块,比较解压后的大小,再计算解压后的adler32,比较之,不符合同样挂掉。
所以在用UPX的"-d"选项来解压缩文件时,没有UPX1HEAD或其中的字段有问题就一定失败。

“提高压缩率”是UPX的宗旨!但也造成了它的某些缺陷,比如对win32/pe类型的文件,--exact选项不可用,永远无法还原出与原文件完全相同的内容。
UPX自己也提到文件映像的“证书”问题,即一个经数字签名的可执行文件在压缩、解压缩后,由于内容已经改变使得签名毫无意义。这点需要注意!

三.脚本的工作原理
脚本不依赖UPX1HEAD,靠"UPX stub"自身来实现数据解压。只要目标能正常运行,解压一定正确,脚本完美脱壳就成为可能。
"UPX stub"的全称为"UPX assembly stub",它是用汇编写的一个模板(Template)或框架(Framework)。写得非常精巧,且具前瞻性。十年前的结构和现在相比也没有太大的变化,这是UPX的强大之处,也是脚本能通用的前提条件。
结构非常灵活,根据压缩时的选项,采用“宏”的方式来填充具体代码。看得出来,其中每一个字节都经过仔细推敲,且得到时间的检验和不断完善,再次赞叹其强大!
喜爱汇编的人一定不要错过这部分内容,很值得学习研究!

脚本完全遵循这个框架的处理流程:解压,unfiltering,导入表(IMPORT)、重定位表(RELOCATION)、导出表(EXPORT)、资源表(RESOURCE)的处理。
资源表的恢复是脚本必须的,"UPX stub"无需再作处理,没有相应的代码。

1. 解压(DECOMPRESSION)
脚本直接利用stub的代码,在解压完成处设一个断点,停下来,从解压出的数据里获得文件还原的关键信息。这里包含原文件的PE Header+Sections Table,及重建导入表和重定位表所用到的重要指针。
在源码"upx-3.91-src\src\p_w32pe.cpp"的末尾有这样一段注释:
[Plain Text] 纯文本查看 复制代码
/*
 extra info added to help uncompression:

 <ih sizeof(pe_head)>
 <pe_section_t objs*sizeof(pe_section_t)>
 <start of compressed imports 4> - optional           \
 <start of the names from uncompressed imports> - opt /
 <start of compressed relocs 4> - optional   \
 <relocation type indicator 1> - optional    /
 <icondir_count 2> - optional
 <offset of extra info 4>
*/

初一看,难以理解。这些指针指向的UPX自定义结构又不清楚,在跟过几个样本后就明白了,这里不详细说它,篇幅会很长。感兴趣的请阅脚本的相应部分,自认为有较好的注释。

这里脚本并不关心它的解压算法。在每一个目标中,对应算法的解压代码就摆在那里的,直接用就好。

2. unfiltering
脚本在它完成处再设一个断点,停下来后,stub的代码已经替我们完成了unfiltering。
到这里stub对我们已经没有多大用处了,只移植了后面一小段处理重定位表的代码用于重建。
因为从这以后,stub处理那些表的方式和我们恢复文件不一样:它会继续完成导入、重定位等过程,而我们需要重建导入表、重定位表等等。

3. 重建导入表
从这以后,脚本并未严格按源码的方式,它有太多的类,比较繁琐。基于我对PE文件的理解,所以存在错误或bug!
这里脚本进行的工作非常类似于大家所熟悉的工具ImportREC(Import REConstructor)。
视压缩时的选项,导入表有两种压缩方式,要分别处理。
a) 方式1
压缩时"Import Directory"和"Import Address Table"的内容被完全清空,以提高压缩率;需要全部重建。
b) 方式2
压缩时保留了完整的IAT和INT,"Import Directory"指向的那些IMAGE_IMPORT_DESCRIPTOR里仅有导入库名称指针(Name)。需要填写FirstThunk、导入库名的ASCII字符串及按IAT恢复导入函数名。

这里,所有IMAGE_IMPORT_BY_NAME里的Hint压缩时没有保存,无法恢复。这也是win32/pe类型的文件,--exact选项不可用的原因之一。方式1的INT全为空白,理论上与IAT相同,可复制一份,但没有必要,如果不需要对恢复的文件进行Binding的话。
另外注意到,UPX的"-d"选项在复制导入函数名时,使用“Compact”方式:因为IMAGE_IMPORT_BY_NAME.Hint全为0000,其低字节会作为前一个IMAGE_IMPORT_BY_NAME.Name字符串的结尾NULL。
脚本处理时坚持每个IMAGE_IMPORT_BY_NAME按字(Word)对齐。

4. 重建重定位表
这部分全部用脚本语句来实现时,发现实在太慢,不得已编写了一小段汇编代码。

5. 重建导出表
与重建导入表类似,不过要简单很多。IMAGE_EXPORT_DIRECTORY里的三张表:AddressOfFunctions、AddressOfNames和AddressOfNameOrdinals都完整保存,只需作地址转换后恢复到文件的对应位置、复制导出库名和函数名。

6. 重建资源表
需要恢复资源表的头部,压缩时移到".rsrc"段的ICON、GROUP_ICON、VERSION和MANIFEST数据也需要复制回原来的地方,并修改指针。
由于IMAGE_RESOURCE_DIRECTORY大多是嵌套的,所以学习源码,设计了一个递归子程序来遍历。有意思,用ODbgScript也可实现递归。在资源项比较多时,脚本处理比较耗时,但舍不得改为汇编。
提醒一下:在调试脚本重建导入表的子程序时发现ODbgScript的memcpy命令可能存在Bug(某几个函数名总是只复制一个DWORD的长度),详见脚本注释。

7. 附加数据(Overlay)的处理
脚本是支持Overlay的。因为不知道怎么用脚本来取得文件的实际大小,所以写了一小段汇编用API来实现。

脚本只经过有限的测试,包括还原UPX自身:UPX 1.20w(May 23rd 2001),UPX 1.25w(Jun 29th 2004),UPX 2.02w(Aug 13th 2006),UPX 3.09w(Feb 18th 2013)及UPX 3.91w (Sep 30th 2013)。
一些选项组合压缩的EXE和DLL测试样本。问题肯定是有的,欢迎指教!并借用UPX的一句话:
"This script comes with ABSOLUTELY NO WARRANTY!"


附件为脚本及以前写的一个"EmEditor Syntax File for ODbgScript"。
[Plain Text] 纯文本查看 复制代码
2013-11-14  23:15    39,599 UPX.Unpacker.for.Dummies.osc   MD5: 25EC5A0E5245B380FA33E0CD8957DB79
2013-01-31  01:21     6,874 ODbgScript.esy                 MD5: 3BFEA5E7B4A00FAC3097A0D880EBC957

ODbgScript.PNG

UPX.Unpacker.for.Dummies.osc.7z (10.08 KB, 下载次数: 2559)

免费评分

参与人数 14威望 +1 热心值 +13 收起 理由
Bedwell + 1 谢谢@Thanks!
liuyunz + 1 我很赞同!
JasonSafe + 1 我很赞同!
pojie_nightmare + 1 谢谢@Thanks!
caleb110 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
zxc1998gzp + 1 谢谢@Thanks!
5911521 + 1 我很赞同!
马斯维尔 + 1 MistHill的作品总是这么牛
07591343 + 1 我很赞同!
巅烽2 + 1 绝对的支持
l261178929 + 1 大神的帖子必须加热心+1
拉酷 + 1 我很赞同!
Hmily + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
xiao + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

xiao 发表于 2013-11-15 16:27
谢谢分享,留个记号。
′奶灬嘴丶 发表于 2013-11-15 17:36
吾乐乐丶小米 发表于 2013-11-15 16:54
fx1112 发表于 2013-11-15 16:51 来自手机
学习了,虽然不太懂,感谢分享。
拉酷 发表于 2013-11-15 16:46
感谢楼主分享,UPX原生脱壳在WIN7下有BUG,这个兼容强很多。
琦琦的爱 发表于 2013-11-15 17:47
这个有点牛叉了
adsmnt 发表于 2013-11-15 17:55
感谢楼主分享
yybyqq 发表于 2013-11-15 18:22
楼主真是高人啊
tle 发表于 2013-11-15 19:14
这个给力啊!亲
1
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2022-12-9 21:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表