February 25, 2022

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

(简称《逆向工程核心原理》第十四章和第十五章学习)

X.exe与X_upx.exe的比较

image-20220225094721376

  1. PE头的大小一样(0~400h)
  2. 节区名称改变(“.text” -> “UPX0”, “.data” -> “”UPX1)
  3. 第一个节区的RawDataSize = 0(文件中的大小为0)
  4. EP位于第二个节区(原nodepad.exe的EP在第一个节区)
  5. 资源区(.rsrc)大小几乎无变化

可以发现Size of Raw Data为0,可Virtual Size设置为10000,说明在运行瞬间讲代码压缩到第一个节区

image-20220225095122762

两种方法找到OEP

首先可以看下OEP的位置在100739Dh

10073B4处与10073C0地址处是比较MZ与PE签名

image-20220225095744515

单步跟踪法

这两条指令设置了upx1和upx0的起始位置

1001000是upx0 待解压缩区

1011000是upx1 资源区

image-20220225100612978

(跟踪UPX文件,遇到LOOP时,先了解作用再跳出)

1. 循环#1(初始化)

从EDX(1001000)中读取一个字节写入EDI(1001001)

(感觉就是初始化upx0节区)

image-20220225101519176

2. 循环#2(解压缩循环)

这个循环比较大,一共有三处从upx1放入upx0

第一处放入

image-20220225102348391

第二处放入

(这里有点不理解edx指向的也是upx0的区域,然后又放入upx0,为什么是upx1解压到upx0)

image-20220227145525947

第三处放入

(和第二处同疑问)

image-20220227150518763

3. 循环#3(修复重定位)

恢复E9的重定位,低八位直接舍弃了,减原来基地址,再加当前upx0的基地址

image-20220227160054930

4. 循环#4(恢复IAT)

从upx1存放的API函数名称,GetProcAddress获取IAT地址再放到nodepad的IAT地址

image-20220227161744467

5. 跳转到OEP

再往下一点就是跳转到OEP的位置了

image-20220227162329809

ESP定律法

1. 设置内存断点

pushad是把八个通用寄存器放入堆栈,这样不会影响寄存器初始状态

所以当upx恢复完了,会有对应的popad,那么在这八个寄存器的数据下个断点

F9直接运行,当dbg断下来,说明已经恢复完了

image-20220227162545774

2. 找到OEP

可以发现已经快到跳OEP的位置了

image-20220227162740358

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

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