-
-
[原创] 借助 x64dbg 的 UPX 手工脱壳
-
发表于:
2021-6-21 17:35
31823
-
[原创] 借助 x64dbg 的 UPX 手工脱壳
流程图排版异常可以移步至我的博客。
背景介绍
比赛过程中,一部分Re题会被加UPX壳。正常情况下只需要用upx -d /path/to/file
即可脱壳,但偶尔有题目使用魔改的UPX(如下图)无法直接脱壳,这时就需要手工脱壳。本文记录了一种借助x64dbg
及Scylla
的手工脱壳方法。
准备
首先准备一个Test程序,初始情况下用IDA打开情况如下:
现在使用upx -9 /path/to/file
进行加壳,结果如下:
使用IDA打开时会提示Some imported modules will not be visible because the IAT is located outside of memory range of the input file.
,忽略后的结果如图:
这样的代码完全无法阅读,字符串、函数信息等都已经没了。
下面开始手工脱壳。
脱壳
寻找入口点
首先要先在加壳后的程序中定位到原程序的入口点。使用x64dbg打开后直接运行一步,发现停在了pushad
上。该指令将所有寄存器的值压栈,而在UPX的执行流程里,这一步之后会加载UPX的解压代码用于将原始程序解压。
upx的工作原理其实是这样的:首先将程序压缩。所谓的压缩包括两方面,一方面在程序的开头或者其他合适的地方插入一段代码,另一方面是将程序的其他地方做压缩。压缩也可以叫做加密,因为压缩后的程序比较难看懂,主要是和原来的代码有很大的不同。最大的表现也就是他的主要作用就是程序本身变小了。变小之后的程序在传输方面有很大的优势。其次就是在程序执行时,实时的对程序解压缩。解压缩功能是在第一步时插入的代码完成的功能。联起来就是:upx可以完成代码的压缩和实时解压执行。且不会影响程序的执行效率。
upx和普通的压缩,解压不同点就算在于upx是实时解压缩的。实时解压的原理可以使用一下图形表示:
1 2 | graph LR;
1 - - > 2 - - > 3 - - > 4 - - > 5 - - > 6 ;
|
假设1是upx插入的代码,2,3,4是压缩后的代码。5,6是随便的什么东西。程序从1开始执行。而1的功能是将2,3,4解压缩为7,8,9。7,8,9就是2,3,4在压缩之前的形式。
1 2 | graph LR;
1 - - > 7 - - > 8 - - > 9 - - > 5 - - > 6 ;
|
连起来就是:
1 2 3 4 5 6 | graph LR;
1 = = > 2 - . - > 3 - . - > 4 - . - > 5 ;
7 = = > 8 = = > 9 = = > 5 = = > 6 ;
2 - - >解密 - - > 7 ;
3 - - >解密 - - > 8 ;
4 - - >解密 - - > 9 ;
|
参考文献:upx加壳原理_zacklin的专栏-CSDN博客
所以我们只要跟踪到这部分栈被弹出,就意味着解压完成。之后的代码就是原始代码。
那么如何跟踪这部分栈呢?只需要先F7
步进,pushad
执行完成后对当前栈顶的内存地址下一个硬件断点即可。
然后F5
继续执行。再次中断处如图:
可以看到EIP
上方就是popad
,说明UPX的解压过程已经结束,现在在进行一些清理工作。
看到下方00D01800
到00D01806
的代码,它们在将缺失的栈段空间补齐,会循环若干次。故在00D01809
这个jmp
上下断点。执行到该语句后再F7
步进一次,到达其跳转后的地点:
这里就是我们要找的入口点。
脱壳
找到入口点以后使用x64dbg
自带的Scylla
进行脱壳。
直接使用IAT Autosearch
功能,期间可能会提示使用IAT Search Advanced
,选“是”继续。然后Get Imports
,最后直接Dump
。
Dump出来的文件使用IDA打开,可能依旧会提示IAT表
缺失,不管它,直接看main
函数。
Done :)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-6-21 17:37
被Potat0编辑
,原因: 明确排版异常点