OllyDbg 即时调试功能的强大用途
使用工具
- OllyDbg修改版,简称
OD
; OD
汉化
和插件
均来自互联网;- UnPackMe来自互联网,仅供学习使用;
- Dump 工具为PETools,来自互联网;
- IAT 重建工具为ImportREC,来自互联网;
- PE 编辑工具为LoadPE,来自互联网;
- 文中特殊数字均是
HEX
,为了书写方便采用DEC
;
操作流程
最开始使用的是原版 OD,后续发现定位 OEP 比较麻烦,遂替换为修改版 OD,使用
内存执行断点
即可轻松到达 OEP;运行 CM 后会发现虚拟机变得非常卡,打开任务管理器会发现当前 CM 的 CPU 占用率为 99%;
使用 OD 打开 CM,会弹出错误弹窗:
提示不是一个有效的 32 位可执行程序,这个肯定是 PE 头有问题,点击确定后,EP 停留在系统 DLL 区段;
打开内存映射窗口,发现程序只有一个区段;
F9 运行后,又弹出错误弹窗:
提示不知道如何继续,因为某个地址不可读,同时查看内存窗口,发现没有提示的区段;
打开 LoadPE,在设置中勾选
外壳扩展选项
保存并退出:这样就将 LoadPE 添加到了系统的右键菜单;
在 CM 上右键选择在 LoadPE 的 PE 编辑器中打开:
大部分数据看起来都很正常,唯一异常的是
NumberOfRvaAndSize
也就是数据目录表(DataDirectory)的项数,好像这个数值自 Windows NT 发布以来一直是 16(也就是 16 进制的 10);修改 NumberOfRvaAndSize 的值为 10,然后保存;
运行修改的程序,发现打不开了,难道是改坏了?导入 OD 看看:
首先是弹窗提示入口点超出代码段范围,这是加壳程序载入 OD 后的正常反应;
点击确定后,程序暂停在 00405000 处,查看内存映射窗口,发现修改之前的 1 个区段变成了 5 个区段(不含 PE 头);
通过区段描述判断,当前处于壳所在的区段,暂停在程序的入口点(EP),看来修改 NumberOfRvaAndSize 的值是为了反调试;
F9 运行程序,又是访问不存在区段的弹窗:
既然程序都不能正常运行,常规定位 OEP 的方法肯定是不行的;
有没有可能是把程序改坏了,恢复 NumberOfRvaAndSize 的值试试:
还是不能运行,看来还是有某些反调试没有绕过;
打开 OD,设置即时调试功能:
恢复按钮可用时表示即时调试功能设置成功,然后退出 OD;
尝试使用 LoadPE 设置 INT3 断点的功能直接到达 EP,看程序是否能运行:
点击确定后,OD 自动附加到了 CM 上,可以看到入口的 PUSHAD 被替换为 INT3:
手动修改 INT3 为 PUSHAD,然后运行程序:
还是这个错误,只能另寻它法了;
在前面已经知道,程序正常运行后会有 5 个区段,通常情况下,外壳会依次解压各区段,然后调用代码段的代码,最后程序正常运行:
使用 LoadPE 查看程序的区段,.text 是第 1 区段,也就是说,正常情况下,外壳会首先解压该区段,至于后面的区段是运行时解压还是全部解压后运行,.text 段都已经解压完成了;
此时如果让后面的某个区段产生异常并中断程序,然后给代码段设置访问断点,是不是就可以到达 OEP 了;
以相邻的 .rdata 段为例,当外壳解压 .rdata 区段的数据时,肯定是要将解压的数据写入该区段,此时如果 .rdata 区段没有写入权限,程序肯定会产生异常并中断,这时, .text 段可能已经解压完成了,如果给代码段设置内存访问断点(并恢复 .rdata 段的写入权限)然后运行程序,是不是就可以到达 OEP 了;
当然,不能保证 .rdata 段就一定是在 .text 段之后解压,如果 .rdata 不行,还有其它 3 个区段可以尝试;
不过,作为只读数据段,像 IAT 之类的只读数值应该只会写入此区段;
取消 .rdata 段的写入权限,并保存(有 save 点 save,没 save 点 ok);
修改完成后,运行修改权限后的程序,OD 自动附加到了程序上,说明程序产生异常并崩溃了:
通过查看 EAX 和提示信息可以得知,是这条指令尝试将 MessageBoxA 的地址写入 .rdata 区段时,由于(.rdata)没有写入权限而产生了异常;
接下来,手动恢复 .rdata 区段的权限,当前只有 1 个区段,说明解压写入都是在这个区段中进行的,所以需要给这个区段赋予所有权限;
然后 F7 单步执行指令,可以看到数据被成功写入 .rdata 对应的地址中:
接下来就要验证代码段是否解压完成了,goto 到 00401000:
可以看到代码段已经解压了,但还有一个问题:
按照预想,代码段解压后给代码段设置内存访问断点就可以到达 OEP 了,但现实是当前只有 1 个区段;
既然代码段已经解压,那就可以在数据窗口 goto 到代码段占用的内存空间,给代码段占用的内存单元设置内存访问断点,和直接给代码段设置内存访问断点是一样的:
无法保证所有程序都会顺序访问代码段的地址,所以给代码段占用的所有单元设置访问断点会更有保障;
断点设置好后,运行程序,成功到达 OEP;
使用 PETools 将程序数据 Dump 下来;
跟随任意调用,定位 IAT:
此处为间接调用;
IAT 没有被重定向;
使用 ImportREC 获取输入表并修复 Dumped 的程序:
修复后的程序可以运行,但导入 OD 后会提示不是有效的 32 位可执行文件,需要修改 NumberOfRvaAndSize 的值为 10;
修改后再次导入 OD,完美!
最后,用完即时调试功能后,需要手动关闭,不然任何程序崩溃后都会被 OD 附加;