- 献词
- 致谢
- 前言
- 第一部分 IDA 简介
- 第 1 章 反汇编简介
- 第 2 章 逆向与反汇编工具
- 第 3 章 IDA Pro 背景知识
- 第二部分 IDA 基本用法
- 第 4 章 IDA 入门
- 第 5 章 IDA 数据显示窗口
- 第 6 章 反汇编导航
- 第 7 章 反汇编操作
- 第 8 章 数据类型与数据结构
- 第 9 章 交叉引用与绘图功能
- 第 10 章 IDA 的多种面孔
- 第三部分 IDA 高级应用
- 第 11 章 定制 IDA
- 第 12 章 使用 FLIRT 签名来识别库
- 第 13 章 扩展 IDA 的知识
- 第 14 章 修补二进制文件及其他 IDA 限制
- 第四部分 扩展 IDA 的功能
- 第 15 章 编写 IDA 脚本
- 第 16 章 IDA 软件开发工具包
- 第 17 章 IDA 插件体系结构
- 第 18 章 二进制文件与 IDA 加载器模块
- 第 19 章 IDA 处理器模块
- 第五部分 实际应用
- 第 20 章 编译器变体
- 第 21 章 模糊代码分析
- 第 22 章 漏洞分析
- 第 23 章 实用 IDA 插件
- 第六部分 IDA 调试器
- 第 24 章 IDA 调试器
- 第 25 章 反汇编器/ 调试器集成
- 第 26 章 其他调试功能
- 附录 A 使用 IDA 免费版本 5.0
- 附录 B IDC/SDK 交叉引用
19.5 定制现有的处理器
可能你正考虑开发处理器模块,但你会注意到,现有的处理器模块几乎能够执行你所需的任何操作。如果你拥有处理器模块的源代码,可以轻松地对其进行修改,以满足自己的需要。另一方面,如果你没有源代码,那么你可能不太幸运。幸好 IDA 提供了一种通过插件定制现有处理器的机制。通过“钩住”处理器通知,插件模块可以拦截对现有处理器的分析器、模拟器和输出器阶段的一次或多次调用。定制一个处理器的潜在应用包括以下几项。
扩展现有处理器的功能,使其能够识别其他指令。
更正现有处理器模块中受到破坏的功能(虽然告诉 Ilfak 你发现了一个缺陷,它会更快得到修复)。
定制现有处理器模块的输出,使其满足你的特殊要求。
下面的通知代码在 processor_t
中声明,在 idp.hpp 中讨论,想要拦截对处理器各个阶段的调用的插件可能会“钩住”这些代码。
custom_ana
:作用与u_ana
相同,但任何新指令必须使用一个等于或大于 0x8000 的cmd.itype
值。custom_emu
:模拟自定义指令类型。如果希望调用处理器现有的模拟器,可以调用(*ph.u_emu)()
custom_out
:为自定义指令提供输出,或为现有指令提供自定义输出。如果希望调用处理器的out
函数,可以调用(*ph.u_out)()
。custom_outop
:输出一个自定义操作数。如果你希望调用处理器现有的 outop 函数,可以调用(*ph.u_outop)(op)
。custom_mnem
:为一个自定义指令生成助记符。
下面的代码摘自一个插件,该插件修改 x86 处理器模块的输出,用一个 cya
指令替换 leave
指令,并交换包含两个操作数的指令中操作数的显示顺序(类似于 AT & T 语法):
int idaapi init(void) { ➊ if (ph.id != PLFM_386) return PLUGIN_SKIP; ➋ hook_to_notification_point(HT_IDP, hook, NULL); return PLUGIN_KEEP; } int idaapi hook(void *user_data, int notification_code, va_list va) { switch (notification_code) { case processor_t::custom_out: { ➌ if (cmd.itype == NN_leave) { //intercept the leave instruction ➍ MakeLine(SCOLOR_ON SCOLOR_INSN "cya" SCOLOR_OFF); return 2; } else if (cmd.Op2.type != o_void) { //intercept 2 operand instructions op_t op1 = cmd.Op1; op_t op2 = cmd.Op2; cmd.Op1 = op2; cmd.Op2 = op1; ➎ (*ph.u_out)(); cmd.Op1 = op1; cmd.Op2 = op2; return 2; } } } return 0; } plugin_t PLUGIN = { IDP_INTERFACE_VERSION, ➏ PLUGIN_PROC | PLUGIN_HIDE | PLUGIN_MOD, // plugin flags init, // initialize term, // terminate. this pointer may be NULL. run, // invoke plugin comment, // long comment about the plugin help, // multiline help about the plugin wanted_name, // the preferred short name of the plugin wanted_hotkey // the preferred hotkey to run the plugin };
这个插件的 init
函数确认当前处理器为 x86 处理器(➊ ),然后“钩住”处理器通知(➋)。在 hook
回调函数中,插件处理 custom_out
通知,以识别 leave
指令(➌),并生成一个替代的输出行(➍ )。对于包含两个操作数的指令, hook
函数会临时保存与当前指令关联的操作数,然后交换它们在指令中的顺序,最后调用 x86 处理器的 u_out
函数(➎)来处理与打印输出行有关的全部细节。在返回时,当前指令的操作数还原到它们最初的顺序。最后,插件的标志(➏)指出:插件应在处理器加载时加载,不得在 Edit ▶Plugins 菜单中列出,并可以修改数据库。下面的输出说明了该插件所进行的自定义效果:
.text:00401350 push ebp ➐ .text:00401351 mov 400000h, edx .text:00401356 mov esp, ebp ➐ .text:00401358 mov offset unk_402060, eax ➐ .text:0040135D sub 0Ch, esp .text:00401360 mov edx, [esp+8] .text:00401364 mov eax, [esp+4] ➐ .text:00401368 mov offset unk_402060, [esp] .text:0040136F call sub_401320 ➑ .text:00401374 cya .text:00401375 retn
可以看到,在这 4 条指令(➐)中,常量作为第一个操作数出现,且 cya 指令替代了 leave 指令(➑)。
在第 21 章中,我们将使用自定义处理器插件帮助分析特定类型的模糊二进制文件。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论