1.第一步,查壳,无法识别出编译语言和linker是什么
2.将文件用od打开,可以看到pushad和pushfd,f8两步之后对esp下硬件断点。
3.f9执行到刚下的断点,f8继续,会看到popad,继续f8,到下一个jmp,f8进入jmp,发现下一条指令是jmp eax,f8继续跟,这时,出现的界面是否觉得很熟悉,没错,这里就是oep,记住这个oep的地址:47148B。
4.看到oep下面最近的那个call没,选中它,f4执行过去,然后右键——数据窗口跟随——内存地址,然后再左下角内存区域那边,右键——长型——地址。可以发现存的地址不像正常的地址,是IAT填充的
5.点击左下角,如图对内存下硬件访问断点
6.下好断点以后,重新开始运行程序,根据多次调试的结果,我推测程序有通过异或对断点隐藏的机制,所以需要先f9一次,发现程序直接跑完了,这时再ctr +f2,重启程序,f9,断到第三句的call,再f9,断到ntdll,再f9就断到IAT被填充的地址,这里只取偏移,因为其地址是通过申请内存得到的,可以看到偏移为:0897(偏移=当前地址—基址)
7.基址怎么来的?当然是用virtualalloc申请的。来,跟上。首先在od最下面一栏对该api下断点,使用alt+b可以看到断点已经被下好了。然后f9运行到断点,查看内存窗口,发现其来自地址47a37d。在左上角那个窗口区域ctr+G,然后输入该地址,在下一行打好断点,f4运行过去,可以看到申请到的内存地址存在eax中。在47a37f处接收eax的值作为脚本要用的基址。
8.清除所有断点,重新开始程序,按照2—6的步骤,执行到偏移0897位置,此时清除所有硬件断点,并在此处打一个软件断点(f2),然后,选择菜单栏的调试,打开或清除run跟踪,跟踪步入
9.菜单栏:查看,run跟踪,弹出一个界面,此时跟踪停止了
10.再点击一次调试窗口的跟踪步入,然后点击一下该界面,会发现出现许多指令,这时先别急,泡杯茶坐着等。att+c可以跳转到我们熟悉的od界面,等跟踪完成,会发现跟踪变成了暂停。此时点击图片中的三个点图标,进入run的查看。
11.将查看界面拖到最底下,一条一条向上看,找到最像地址(40万开头或者70万开头那种)的那一条记录,点击那条记录,跳过去。
12.选中地址,f4执行到这里,然后f7,发现其寄存器edx果然存的是个地址,记录当前指令的偏移:10f7,此地是获取真实函数地址指令,真实函数地址存放在edx
13.用以上几步,我们成功的获取了如下几个数据
oep:47148B
申请堆空间代码的地址:47A37F
填充IAT的指令的偏移:0897
获取真实函数地址指定的偏移:10F7
14.接下来就是用已有的四个数据,将被填充的IAT修复回来,这里用到了od脚本(可以将代码复制到txt,再将扩展名改成osc就能运行)。脚本代码如下:
//存放真实的函数地址
MOV dwGetAPIAddr,0010F7
//存放开始修改IAT的地址
MOV dwWriteAPIAddr,000897
//oep大家都懂的
MOV dwOEP,0047148B
//申请堆空间的地址
mov dwAlloc,47A37F
//清除所有的断点
BPHWC
BPMC
BC
//设置两个断点,位于申请堆内存和oep
BPHWS dwAlloc,"x"
BPHWS dwOEP,"x"
//开始循环
LOOP0:
RUN
//比较当前eip和申请堆内存的地址是否相同,如果相同,
//则将申请到的基址分别加上两个偏移组成va
//对两个va下断点
CMP dwAlloc,eip
JNZ tat_get
ADD dwGetAPIAddr,eax
ADD dwWriteAPIAddr,eax
BPHWS dwGetAPIAddr,"x"
BPHWS dwWriteAPIAddr,"x"
JMP LOOP0
//比较当前eip和填充IAT的地址是否一致
//如果相等,则将edx传给dwAddr
//相当于将真实地址偏移传给dwAddr
tat_get:
CMP dwGetAPIAddr,eip
JNZ tat_write
mov dwAddr,edx
JMP LOOP0
//比较eip和填充IAT指令的地址是否相等
//如果是,则将dwAddr的值给edx
//相当于edx现在存的就是真实地址的偏移了
tat_write:
CMP dwWriteAPIAddr,eip
JNZ tat_oep
MOV [edx],dwAddr
JMP LOOP0
//如果到了oep,代表壳代码执行完毕
//同时我们还原真实地址的操作也完成了
tat_oep:
CMP dwOEP,eip
JNZ LOOP0
//弹窗提示oep已经到了
MSG "oep is ok"
14.脚本写好以后,在od中右键,运行脚本
15.脚本运行完毕,会看到下面有很多api
16.接下来按照常规的脱壳方式进行就可以了,最终脱壳成功