UPX解码步骤

1.先初始化
2.进行代码还原
3.进行CALL修复
4.进行函数表还原
5.节表初始化
6.解码完毕飞向程序入口

方法

  • 单步跟踪法
  • ESP定律法

解释

单步跟踪法:基于UPX解压缩的步骤,ep开头会先push所有寄存器到栈,然后执行三个循环(见前一节),然后pop弹出所有寄存器后,重建表,进入程序oep。因此,只要一直f8,遇到循环就f4跳过,直到看到pop,然后跳过小循环,进入最后一个就,jmp即可进入oep,基于以上原理,由于upx解压部分和跳转都是连在一起的,所以直接alt+t搜索pop指令找到最后的位置(push对应pop,pusha或pushad对应popa和popad)

ESP定律法:根据原理push之后是解压,解压完为了跳回oep要获得之前的寄存器值即栈一定会平衡,开始时的栈和最后进入oep的栈状态相同,因此开始调试后先f8,使ESP(RSP)下浮一个值创建栈,如果之后的指令需要这时栈底的寄存器值,一定会回到这里读取这个值.然后复制这时栈顶的地址,G跳到那个地址,在这里下硬件断点,点f9后运行到硬件断点就是pop的位置之后的指令,然后如上即可.

实例

实例一(使用IDA)

1,脱一个x64程序的UPX壳,使用ida:

初始对比:

a

可以看出加壳之后比源程序小了约四分之三.用ida打开加壳程序:

b c

可以看出,压缩后函数变得极少,可以作为判断是否有壳的方法.

在开始处点f2下断点并进行动态调试:

d e

f8单步调试并观察栈:

f

复制栈对应地址并g跳转然后下硬件断点:

g h

观察到栈已经下了断点,这时直接f9,弹出

i

跳转到

j

转换汇编视图可以发现

k

指针点击循环下面的位置点f4运行到对应位置,再几次f8进大跳转就进入oep了,这个地方注意要先把硬件断点删了,点击上面工具栏的断点列表del键删掉

实例2(使用OD)

这是一个x32程序,使用od

进入后发现:

l

和上面方法一样,先f8,然后对寄存器下断点(右键sep值复制,在下面的命令窗口输入hr (对应的地址))这表示是硬件读取断点.回车

m

然后直接f9,删掉硬件断点:调试-硬件断点-删除.就找到了pop,小循环,大跳转

n

之后与第一个写的相同

或者在开始的时候,ctrl+f搜索popad

o

然后找到对应位置:

p

然后直接f4即可