1.进行查壳操作

因其是自制的壳,所以用工具是查不到壳的特征码,也就查不出壳;
2.确定重定位已分离
如果不进行重定位分离的话,会产生随机基址,从而导致脱壳失败
3.查找OEP
①使用ESP定理
②寻找OEP位置(OEP:47148B)
记得“右键”点击“分析”选择“删除分析”
4.查看导入地址表IAT
由于已经找到了OEP,而导入地址表IAT的加载在OEP后的不远处,通过单步步过,可以发现004714B1 FF15 80504700 call dword ptr ds:[0x475080]是导入地址表IAT的加载,在此处右键单击“数据窗口中跟随”选择“内存地址”
我们可以看到其地址所存的内存地址数值在0027XXXX的位置,是一块堆空间,而正常的IAT的地址应当在7XXXXXXXX的地方,所以,判定IAT被加密。
5.进入IAT被加密位置
①在IAT修改处下硬件断点
在图中的00275039的位置下硬件写入断点,就能跳转到IAT被加密的位置
②重新开始,运行找修改处
第一次运行,命中的是ntdll模块
再继续运行,找到001E0895,此处就是在填充IAT
此处的地址为001E0897,这是一个VA地址,是申请在堆内存中的一个地址,所以我们只需要记录其的RVA地址0897,而01E0000就是程序动态申请的地址,在写脚本的时候需要动态获取这个地址。
001E0895 8902 mov dword ptr ds:[edx],eax
001E0897 E8 39000000 call 001E08D5
③如何确定其申请的动态基址
从新加载程序,进行单步步入跟踪,我们知道,程序比如会先加载壳代码,也就必然会开辟堆空间,,而开辟堆空间会用到VirtualAlloc,这样我们可以通过函数名快速的找到申请堆空间位置。
由图可以看到,在0047A37D处会显示字符串“VirtualAlloc”,由此,我们确定申请的堆空间地址会直接存入eax中,再单步一下,就能看到eax寄存器中出现堆空间地址001E0000
6.脱壳思路
此壳的加密行为为,申请一块堆空间,将原本的IAT数据写人到堆空间中,再用堆空间内存地址覆盖IAT,相当于做了一次中间转换,如果能其加密结束处将正确的IAT原始数据重新写入IAT中进行覆盖操作,就能顶掉壳的中间跳转操作,达到脱壳效果。
7.找到关键地址
①找回原始函数地址思路
我们知道了填充加密IAT的代码位置,就能找到存放原始函数API地址的堆空间,就能找回原始函数,就在执行用堆空间地址覆盖IAT代码的前不远处。
②Run追踪
我们需要使用Run跟踪来帮助我们快速找到,获得存放原始函数地址的位置。首先在填充IAT的位置,删除之前的硬件断点,再在这个位置下软件断点,点击导航栏的调试,单击“打开RUN追踪”,再选择跟踪步入
打开RUN追踪窗口,在导航栏点击“查看“,再点击“RUN追踪”即可
等待片刻
③找到关键位置
查看RUN跟踪记录的指令信息,重点关注这次循环过程中,寄存器发生的变化,从最后一条记录向前找,找寄存器中的值像真实函数地址的指令

为了确认,双击此条信息,反汇编窗口跟随,设置软件短句,运行到此处,右键单击,数据窗口跟随,点击“隐含堆栈地址”,再在数值处,右键选择“反汇编窗口中跟随”
④确认关键点
我们需要在获取函数地址指令的下一行,获取EXD的值,用来引向正确的IAT,记录其偏移10F7
001710F6 5A pop edx ; kernel32.HeapFree
001710F7 E8 02F4FFFF call 001704FE
8.编写OD脚本恢复IAT
①准备阶段
0047148B == OEP
0047A37F == 申请的堆空间,里面有壳代码,返回值EAX
0x0897 == 填充IAT的下一行指令位置,我们需要用真实地址覆盖填充过的加密IAT
0x10F7 == 获取真实函数地址的下一行,真实地址保存在EDX中
MOV ddEDX,0
MOV dwAddress,0
MOV ddGetVirtualAlloc,0047A37F
MOV dwGetFunctionRVA,10F7
MOV dwWriteIATRVA,0897
MOV ddOEPAddr,0047148B
BC
BPHWCALL
BPHWS ddGetVirtualAlloc,"x"
BPHWS ddOEPAddr,"x"
LOOP1:
RUN
GetVir:
CMP eip,ddGetVirtualAlloc
JNE CASE1
MOV dwAddress,eax
ADD dwGetFunctionRVA,dwAddress
MSG dwGetFunctionRVA
ADD dwWriteIATRVA,dwAddress
MSG dwWriteIATRVA
BPHWS dwGetFunctionRVA,"x"
BPHWS dwWriteIATRVA,"x"
JMP LOOP1
CASE1:
CMP eip,dwGetFunctionRVA
JNE CASE2
MOV ddEDX,edx
JMP LOOP1
CASE2:
CMP eip,dwWriteIATRVA
JNE CASE3
MOV [edx],ddEDX
JMP LOOP1
CASE3:
CMP eip,ddOEPAddr
JNE LOOP1
MSG "到达OEP,可以dump了!!!"x
1
MOV ddEDX,02
MOV dwAddress,03
MOV ddGetVirtualAlloc,0047A37F4
MOV dwGetFunctionRVA,10F75
MOV dwWriteIATRVA,08976
MOV ddOEPAddr,0047148B7
BC8
BPHWCALL9
BPHWS ddGetVirtualAlloc,"x"10
BPHWS ddOEPAddr,"x"11
LOOP1:12
RUN13
GetVir:14
CMP eip,ddGetVirtualAlloc15
JNE CASE116
MOV dwAddress,eax17
ADD dwGetFunctionRVA,dwAddress18
MSG dwGetFunctionRVA19
ADD dwWriteIATRVA,dwAddress20
MSG dwWriteIATRVA21
BPHWS dwGetFunctionRVA,"x"22
BPHWS dwWriteIATRVA,"x"23
JMP LOOP124
CASE1:25
CMP eip,dwGetFunctionRVA26
JNE CASE227
MOV ddEDX,edx28
JMP LOOP129
CASE2:30
CMP eip,dwWriteIATRVA31
JNE CASE332
MOV [edx],ddEDX33
JMP LOOP134
CASE3:35
CMP eip,ddOEPAddr36
JNE LOOP137
MSG "到达OEP,可以dump了!!!"











