文章目录

  • 程序分析
  • 分析过程
  • 1.找OEP
  • 2.反反调试
  • 3.解密IAT
  • 4.OD脚本还原IAT
  • 5.内存重建IAT表
  • 6.Dump文件,修复


程序分析

查壳:PESpin壳,连接器版本也没有

反调试 android 反调试壳_异常处理

分析过程

1.找OEP

用OD载入文件,F7单步走几步就可以看到pushad,用ESP定律

反调试 android 反调试壳_API_02


程序直接运行完毕,并没有断下来,这说明这个壳有清除硬件断点的反调试

反调试 android 反调试壳_API_03


得换条路,下API断点,常见的入口API

VB程序:GetStartupInfoA

Delphi/BC++:GetModuleHandleA

VC6/易语言:GetVersion

VS2013:GetSystemTimeAsFileTime

F9运行程序,直到调用模块是来自用户模块,通过调用堆栈查看是否是程序OEP

反调试 android 反调试壳_反调试 android_04

2.反反调试

一般找到OEP之后,会在OEP处下断点,然后在壳代码运行过程中解密IAT,现在程序中有反调试会清除硬件断点。此时,是不能在OEP处下int3断点或者内存断点,这会造成壳解密代码段失败。
反硬件断点的方法:

  1. 异常回调中可以将调试寄存器清0
  2. SetThreadContext函数以及这个函数的下层函数
  3. SetUnhandledExceptionFilter设置顶层异常函数
    API下断没有断下,说明反调试在异常处理函数中,设置OD接收所有异常
  4. 异常设置,去掉忽略异常勾选
  5. StrongOD设置,去掉Skip Some Exceptions选项

Ctrl+F2重新运行程序,程序会在异常发生处断下来,该程序一共有7个异常,需要挨个做判断

验证思路:

首先我们在第二个异常发生处下硬件断点,重新运行程序,若不能断下,则说明反调试在第一个异常处理函数中。

一个个判断,最终确定反调试在第三个异常处理函数中,OD->查看->SEH链可以查看异常处理函数

反调试 android 反调试壳_反调试 android_05


在异常处理函数下断,nop掉清除代码,继续分析

3.解密IAT

FF15调用,0x43CFCD可以看到IAT表处于加密状态

反调试 android 反调试壳_异常处理_06


在0x43CFCD处下硬件写入断点,程序会在填充IAT的时候断下

程序第一断下,字节填充,显然不是

反调试 android 反调试壳_API_07


程序第二次断下,4字节填充,这里就是填充IAT了,IAT表每个元素都是4字节

反调试 android 反调试壳_反调试_08


F7单步运行,跟一遍IAT加密的流程,找三个关键点:获取API函数地址位置、加密IAT位置、填充IAT位置。因为壳有混淆功能,最好不要用F8,很容易跑飞。

第一步:找到首字母是l的函数

反调试 android 反调试壳_API_09


第二步:计算字符串hash值

反调试 android 反调试壳_反调试 android_10


第三步:获取函数地址

找到hash值是0xF9B697A2的字符串

反调试 android 反调试壳_异常处理_11


得到函数地址

反调试 android 反调试壳_异常处理_12


加密过程比较复杂,从汇编层改算法就算了,借助OD脚本还原IAT表

4.OD脚本还原IAT

基本思路:

nop掉反调试代码
保存获取到的API函数地址
在填充IAT后把函数地址再次填充进IAT,覆盖加密值
运行到OEP停止

VAR dwSehAddr
VAR dwGetAPIAddr
VAR dwWriteAPIAddr
VAR dwOEP

//1.定义变量
MOV dwSehAddr,43AF57
MOV dwGetAPIAddr,438F9F
MOV dwWriteAPIAddr,43918C
MOV dwOEP,00409486

//2.去除所以断点
BPHWC //清除硬件断点
BPMC //清除内存断点
BC //清除软件断点

//3.设置断点
BPHWS dwSehAddr,"x"
BPHWS dwGetAPIAddr,"x"     
BPHWS dwWriteAPIAddr,"x"
BPHWS dwOEP,"x"

//4.构造循环
LOOP0:
RUN

CMP dwSehAddr,eip
JNZ tag_get
FILL dwSehAddr,1C,90 //NOP 0x1C个字节
JMP LOOP0

tag_get:
CMP dwGetAPIAddr,eip
JNZ tag_write
MOV dwAddr,eax
JMP LOOP0

tag_write:
CMP dwWriteAPIAddr,eip
JNZ tag_oep
MOV [edi],dwAddr
JMP LOOP0

tag_oep:
CMP dwOEP,eip
JNZ LOOP0

MSG "到达OEP!"

反调试 android 反调试壳_异常处理_13


当所有的都修复完毕后,发现IAT不是典型的IAT数组,而是被修改过的,每一个地址后都多了个0x00,所以需要在内存中重建输入表

反调试 android 反调试壳_API_14

5.内存重建IAT表

使用工具Universal Import Fixer在内存中重建输入表

反调试 android 反调试壳_异常处理_15

6.Dump文件,修复

脱壳成功

反调试 android 反调试壳_API_16