返回介绍

19.5 定制现有的处理器

发布于 2024-10-11 21:05:48 字数 3819 浏览 0 评论 0 收藏 0

可能你正考虑开发处理器模块,但你会注意到,现有的处理器模块几乎能够执行你所需的任何操作。如果你拥有处理器模块的源代码,可以轻松地对其进行修改,以满足自己的需要。另一方面,如果你没有源代码,那么你可能不太幸运。幸好 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文