最后一次异常法定位 OEP
使用工具
- OllyDbg 1.10原版,简称
OD
; - OllyDbg修改版,简称
OD
; OD
汉化
和插件
均来自互联网;- UnPackMe来自互联网,仅供学习使用;
- 文中特殊数字均是
HEX
,为了书写方便采用DEC
;
分析思路
拿到 CM 后,第 1 想法就是栈平衡,将 CM 导入原版 OD:
首先弹出警告弹窗,说明程序有壳(这不是废话嘛)
然后到达 EP 位置,行首却不是 PUSHAD/PUSHFD,这就让人很尴尬了,不过又想到了栈平衡的第 2 种方法;
大胆的猜测一下,如果 OEP 行首是压栈指令,那么压栈的地址就是:0012FFC0:
所以,给 0012FFC0 设置硬件写入断点,然后运行程序;
程序会中断两次,第 2 次才会到达 OEP,因为第 2 中断时才处于代码段:
然后又尝试了设置访问断点来到达 OEP,两种方法皆是可行的,不过这 3 种方法并不是今天的重点;
将程序导入改版 OD,
F9
运行程序,待程序主窗体出现后,打开日志窗口(请不要关闭程序主窗体):来到日志窗口后,发现程序运行期间,有一大堆异常,但程序却正常运行了,很是奇怪;
程序可以正常运行,是因为 OD 的调试选项忽略了所有异常,如果不忽略异常,程序会在每一次异常时暂停,而在最后一次异常后,程序正常运行了;
如果在最后一次异常时(也可以说是程序运行前)给代码段设置内存访问断点,是否可以到达 OEP 呢?
首先设置 OD 调试选项:
在日志窗口可以看到,最后一次异常是 INT3,所以取消忽略 INT3 异常,同时取消忽略异常范围选项,因为从 00000000 ~ FFFFFFFF 就忽略了所有异常;
然后运行程序,在几次中断后,就来到了最后一次异常所在位置:
来到内存窗口,给代码段设置
内存执行断点
,然后按下Shift + F9
忽略异常并运行程序:程序到达 OEP,Perfect!
既然有那么多方法,问什么要用这么复杂的方法呢?
是因为,加壳不仅可以隐藏 OEP,还可以反调试,而为了绕过反调试,在执行部分代码后,再设置断点相对会更安全,这是一种好的思路;