壳常用函数定位 OEP
使用工具
分析思路
GetProcAddress
将程序导入 OD,goto 到 GetProcAddress 函数的行首,设置 F2 断点,然后运行程序;
程序中断在函数的行首,使用
shift + F4设置条件记录断点:![设置条件记录断点]()
表达式的值填写
[esp],表示获取 ESP 中的数据,同时勾选记录表达式的值以及函数参数选项;清空 log 窗口,然后运行程序,条件记录断点会在 log 窗口记录每次调用 GetProcAddress 函数的调用地址及参数:
![记录每次调用]()
通过查看内存窗口得知,外壳程序对 GetProcAddress 的最后一次调用位于:0047009A:
![外壳程序的最后一次调用]()
重载程序,编辑条件记录断点:
![编辑条件记录断点]()
勾选
按条件中断选项,同时将条件设置为[ESP] == 0047009A,表示当 ESP 的值为 0047009A 时中断;运行程序后,程序中断在条件记录断点位置,来到内存窗口,给代码段设置内存执行断点:
![内存执行断点]()
多次运行程序后,程序到达 OEP:
![程序到达 OEP]()
这里需要运行太多次了,所以这种方法因程序而异,灵活使用;
其实,设置了内存执行断点后,就可以将条件访问断点取消了,取消之后就和异常法大同小异了,好处是可以绕过部分反调试;
ExitThread
因为本例中有终止线程的动作,且位于代码段之外,可以使用 ExitThread;
将程序导入 OD,
F9运行程序后,打开日志窗口:![打开日志窗口]()
可以看到,在一堆异常中,有一个线程结束日志,位于最后一次异常之前;
打开 OD 调试设置菜单,事件选项卡,选中
中断于线程结束选项:![中断于线程结束]()
重载并运行程序,程序中断:
![提示信息]()
看提示信息可以得知,中断原因是某个线程结束了;
在内存窗口,给代码段设置内存执行断点,然后运行程序:
![程序中断在 OEP]()
程序到达 OEP;









