手工脱壳之 未知IAT加密壳 【IAT加密+混淆+花指令】【哈希加密】【OD脚本】

一、工具及壳介绍

使用工具:Ollydbg,PEID,ImportREC,LoadPE,OllySubScript

未知IAT加密壳

二、初步脱壳 

尝试用ESP定律。

   

   

疑似OEP,VC6.0特征

   

   

进第一个CALL查看

   

   

确认是OEP。

OEP地址 = 47148b,RVA = 7148b

   

   

导入表函数信息出了问题。

查看IAT引用。

IAT表被加密。所以ImproREC才检测失败。

   

   

三、解析IAT加密方式

先API方面考虑。 

壳修复exe IAT时,需要调用相关API,用LoadPE查看壳的导入表信息。

可见,推测,LoadLibrary 和 GetProAddress 是 隐藏调用 或 自我实现的。

   

   

采取硬件断点的方式:

在被加密的IAT表的最顶端,下硬件断点。

   

   

首次断下,执行代码是在内存地址上,说明壳是在自己申请的内存上执行代码的。

回溯分析函数。

   

进一步分析,确认是memcoy

查看memcoy参数,数据窗口跟随,发现是壳首次调用解密TEXT段

改换在memcpy下断点,第二次断下。

第二次断下,是往IAT填RVA。

   

   

接下来断下的每一次,是往IAT填内存地址,内存地址数据窗口跟随。

   

IAT引用的顺序是这样的:

CALL à 壳的内存代码 à 真正的API

所以壳是在中间加了一层内存代码,并且内存代码里包含混淆花指令。

三、锁定IAT加密点

在memcpy进RVA后,依旧在IAT首部下硬件断点。

得知壳进行内存的操作后,顺便在API下断,VirtualAlloc

   

记录一下,一共申请了三次内存。

   

在硬件断点断下的地方。

由于汇编中掺杂着混淆和花指令,(具体见最后部分)。 

确定目标:在壳修复IAT过程,寻 取出的函数地址 和 475000(往IAT填的内存地址)。

操作:多观察寄存器窗口 和 堆栈窗口

在当前指令下硬件断点,并开始单步步入(混淆代码的CALL F8会跑飞)

记录异样:

DLL基地址

查看地址,是遍历时的RVA

 出现字符串,并在代码循环中逐步减少,疑似DLL INT取得的函数名。

 查看地址,确认是。

   

按经验,在壳中,比较函数名的汇编代码有两种规律:

壳调用比较函数:在字符串完整或全没时,跟踪到返回指令,回溯分析函数和函数周围的函数调用。

壳采用比较循环:纯代码循环比较字符串。找到字符串比较条件的临界点,一般下一条是条件跳转指令,跳出循环。

由于代码是混淆过的,跳来跳出乱跳,很明显是属于比较循环。

   

比较字符串,如果采用rep的方式的话,结果一般会设置标志位跳转,再返回布尔值。

上面是TEST AL, AL,判断字符串是否结尾。壳可能进行长度记录,或是对整个字符串进行了特殊操作。

当比较结束时,跟踪结果,寻找函数地址 

发现壳是对函数名进行哈希加密,并拿哈希值与 要寻函数的哈希值比较,来锁定函数。

下条件断点,当匹配正确后,下一步应该就是从DLL IAT取函数地址了

   

取出的函数地址:

   

为后面OD脚本做准备:

跳过CALL,需在下一条指令下硬件断点:

记录下一条指令地址:0x002E08D5,RVA = 08D5

   

接下来找 把函数地址放进exe IAT的指令,观察475000开始的地址。

 中间经过memcpy,应该是把内存代码往刚申请的内存上填,然后把内存地址赋给IAT。

   

寻到IAT的地址: 

然后就是把内存地址IAT地址上填了

   

 为后面OD脚本做准备:

跳过CALL,需在下一条指令下硬件断点:

记录下一条指令地址:0x2E1A36,RVA =1A36

由于壳代码是在申请出来的内存上执行的,需要确定内存基址,就需要确定申请内存的指令。

寻到申请内存的指令:

   

  为后面OD脚本做准备:

记录下一条指令地址:0x47A381。

   

四、OD脚本

前面的准备材料:

OEP 地址 = 0x47148b

得到申请内存地址:0x47A381

取IAT指令地址RVA:08D5

存IAT指令地址RVA:1A36

   

OD脚本:

//清除所有硬件断点

BPHWC

//清除所有软件断点

BC

//清除所有内存断点

BPMC


//壳申请内存基地址

VAR BaseAddress

//IAT地址

VAR IATAddress

   
//得到申请内存基地址指令

BPHWS 47A381,"x"

//OEP断点

BPHWS 47148b,"x"


_LOOP:

RUN

   
//内存基地址判断

CMP eip,47A381

JNZ _Sign1

   
MOV BaseAddress,eax


//取IAT指令

BPHWS BaseAddress+1A36,"x"

//存IAT指令

BPHWS BaseAddress+08D5,"x"

   
_Sign1:


//取IAT判断

CMP eip,BaseAddress+1A36

JNZ _Sign2


MOV IATAddress,eax


_Sign2:


//存IAT的地方

CMP eip,BaseAddress+8D5

JNZ _Sign3


MOV [edx],IATAddress


_Sign3:

   
//OEP

CMP eip,47148b

JNZ _LOOP


MSG "到达OEP"

再次Dump,成功解析。 

   

成功运行。

   

五、混淆和花指令 

代码中出现很多这样的指令:

call xxx

xxx    LEA ESP,DWORD PTR SS:[ESP+0x4]

实际上等价于jmp    xxx

很多地方都是 混淆和花指令结合:

   

有关混淆和花指令详细,可以参考下一篇,下一个壳采用了大量的花指令和混淆:

手工脱壳之 PESpin加密壳【SHE链硬件反调试】【IAT重定向】【混淆+花指令】

   

个人总结:

附件:

 未知加密壳

KIDofot

原文地址:https://www.cnblogs.com/KIDofot/p/8641380.html