首页
论坛
课程
招聘
[原创]新版IDA SDK的变化
2022-4-16 00:35 8835

[原创]新版IDA SDK的变化

2022-4-16 00:35
8835

前言

相信大多数人都阅读过神书《IDA Pro权威指南》,但是这本书是基于比较老版的IDA,里面讲的许多概念和代码都无法在最新的IDA上使用。本文打算以IDA7.5为基础讲讲其中编写IDA处理器模块的变化,如果你打算编写IDA模块,这篇文章希望对你有所帮助。如有错误,欢迎指正。

准备工作

IDA7.6、IDA SDK7.6、Visual studio

概念

模块:IDA二次开发的功能之一,分为加载器、处理器和插件。
加载器:用于分析文件结构,处理文件数据,为后面处理器作准备。常见的有PE文件加载器和ELF文件加载器。
处理器:提供二进制文件的反汇编功能,包含函数识别、分支处理、代码着色等任何跟处理器相关的功能
插件:开发者可以使用插件定制任何功能,著名的有hex-rays开发的F5插件。
脚本:IDA二次开发的功能之一,作为插件的补充,可以使用IDC或python开发。插件能够调用大部分的SDK API并且拥有大量的封装函数,使其非常容易开发。

SDK

SDK的目录结构

  • include,该文件夹包含了SDK导出的所有头文件
  • module,该文件夹包含了一些处理器模块的样例
  • plugins,该文件夹包含了一些插件模块的样例
  • ldr,该文件夹包含了一些加载器模块的样例
  • lib,sdk导出的lib库,配合include使用
  • install_visual.txt,该文件描述了如何在VS中创建一个IDA模块
  • readme.txt,该文件大致描述了include中每个头文件的基本作用
  • module/idaidp.hpp,该文件提供了处理器模块使用的一些便捷函数、类和宏定义

官方SDK文档

新版的IDA的一些变化

  • IDA从7.5开始支持多idb加载和处理,如果你需要使用IDA的idb功能,你可能需要使用set_module_data、clr_module_data、get_module_data这三个函数与你的模块进行绑定。

  • IDA模块支持事件处理机制,处理器模块导出的LPH中的u_ana、u_emu等回调函数在新版IDA SDK中已被删除,取而代之的是一个notify的回调函数,在该函数中可以处理IDA消息(例如ev_ana_insn和ev_emu_insn)。

  • IDA从7.4开始把所有的脚本函数统一规范化了,如果你使用python进行IDA脚本开发,需要注意这点,否则你可能发现你的脚本在7.3上能运行而在7.4上无法运行。IDA官网提供了函数的映射关系Porting from IDAPython 6.x-7.3, to 7.4

processor_t结构体

处理器模块导出LPH相比旧版sdk已经少了很多字段,但该结构体仍然有26个字段需要初始化,这是一个非常繁琐的工作。幸运的是,大多数时候,某些字段不会用到,我们只需要初始化其中几个关键的字段即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//[*]表示必须设置的字段
struct processor_t
{
    int32  version;    //[*]必须为IDP_INTERFACE_VERSION
    int32  id;    //[*]自定义的处理器模块必要大于0x8000
    uint32  flag;    //以PR_开头的flag组合,根据需要添加,可以设置为0
    uint32  flag2;    //以PR2_开头的flag组合,根据需要添加,可以设置为0
    int32  cnbits;    //[*]代码段中1个字节有多少个bit可用,设置为8即可
    int32  dnbits;    //[*]非代码段中1个字节有多少个bit可用,设置为8即可
    const char *const *  psnames;    //[*]处理器模块的短名称,最多9个字符,数组以NULL指针结尾
    const char *const *  plnames;    //[*]处理器模块的长名称,长度不限,数组以NULL指针结尾
    const asm_t *const *  assemblers ;    //汇编清单,可以设置为{ NULL },数组以NULL指针结尾
    hook_cb_t *  _notify;    //[*]事件通知的回调函数,在该函数中处理IDA发出的各种事件,包括ev_ana_insn、ev_emu_insn、ev_out_insn、ev_out_operand,上述四个事件分别对应旧版SDK的4个回调函数
    const char *const *  reg_names;    //[*]寄存器名称数组
    int32 regs_num;    //[*]寄存器名称数组的元素个数
    int32 reg_first_sreg;    //第一个段寄存器的序号,可以设置为rVcs
    int32 reg_last_sreg;    //最后一个段寄存器的序号,可以设置为rVds
    int32 segreg_size;    //段寄存器大小,单位为字节,可以设置为0
    int32 reg_code_sreg;    //代码段寄存器,可以设置为rVcs
    int32 reg_data_sreg;    //数据段寄存器,可以设置为rVds
    const bytes_t *codestart;  //代码/函数开始的特征码,可以设置为NULL
    const bytes_t *retcodes;    //代码/函数结束的特征码,可以设置为NULL
    int32   instruc_start;    //[*]指令枚举的第一个数
    int32   instruc_end;    //[*]指令枚举的最后一个数,枚举最后一个数设置为XXX_LAST,
    const instruc_t *instruc;     //[*]定义指令的汇编输出和操作数属性,要与指令枚举一一对应
    size_t tbyte_size;    //长浮点(long double)类型的大小,单位为字节,可以设置为0
    char real_width[4];    //浮点数中小数点后位数,用于浮点数显示时保留多少位,可以设置为{0}
    int32 icode_return;    //返回指令的指令码(指令枚举),可以设置为非指令枚举中的元素,一般设置为XXX_NULL(指令枚举的第一个元素)
    void *unused_slot;    //预留,设置为NULL
};

新版的sdk推荐以下形式创建一个处理器模块,注意SET_MODULE_DATA需要使用一个名称为data_id作为全局变量并且该名称不能改变。

1
2
3
4
5
6
7
int data_id; //for SET_MODULE_DATA
static ssize_t idaapi notify(void *, int msgid, va_list)
{
  if ( msgid == processor_t::ev_get_procmod )
    return size_t(SET_MODULE_DATA(tms6_t));
  return 0;
}

plugin_t结构体

新版sdk的plugin_t为了兼容旧版插件无太大变化,但其中一些成员变量已经不再使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
//[*]表示必须设置的字段
struct plugin_t
{
    int version;                        //[*]必须为IDP_INTERFACE_VERSION
    int flags;                            //[*]插件的属性
    plugmod_t *(idaapi *init)(void);    //插件初始化的回调函数,新版sdk需要设置一个返回plugmod_t的指针
    void (idaapi *term)(void);            //插件销毁时的回调函数,新版sdk应该置NULL
    bool (idaapi *run)(size_t arg);        //插件调用时的回调函数,新版sdk应该置NULL
    const char *comment;                //插件的注释
    const char *help;                    //插件的使用帮助
    const char *wanted_name;            //[*]插件名称,显示在编辑-插件
    const char *wanted_hotkey;            //快捷键
};

新版sdk中plugin_t的init函数一般来说很简单,只需要返回一个plugmod_t类的实例指针即可。以下是一个init函数的参考。

1
2
3
4
5
6
static plugmod_t* idaapi init()
{
    if (ph.id != (PLFM_TMSC6))    //ph为SDK导出的全局变量
        return PLUGIN_SKIP;
    return new plugin_ctx_t;    //该插件仅在处理器模块为tmsc6时启用
}

旧版sdk中plugin_t的init、term和run函数分别对应plugmod_t类的构造函数、析构函数和纯虚函数run。
在编写插件时,需要编写一个类继承plugmod_t类并实现run函数,然后将该类的实例指针在init中返回。以下为继承类的参考。

1
2
3
4
5
6
7
8
//继承event_listener_t接口可以让插件优先处理器模块处理IDA发出的事件
struct plugin_ctx_t : public plugmod_t, public event_listener_t
{
    plugin_ctx_t() { hook_event_listener(HT_IDP, this); }
    ~plugin_ctx_t(){ unhook_event_listener(HT_IDP, this); }
    virtual bool idaapi run(size_t) override;
    virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;    //处理ev_xxx事件
};

2022 KCTF春季赛【最佳人气奖】火热评选中!快来投票吧~

收藏
点赞1
打赏
分享
最新回复 (3)
雪    币: 1109
活跃值: 活跃值 (1178)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
fengyunabc 活跃值 1 2022-4-16 14:59
2
0
感谢分享!
雪    币: 104
活跃值: 活跃值 (691)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaomajia 活跃值 2022-4-16 19:50
3
0
跟老版本相比,没有什么太大的变化,无非就是舍弃了一些多余的设计和api,扩展的一些更细节的东西,其实我觉得最主要的变化就是现在支持用python3写插件了,这个是最爽的。
雪    币: 4966
活跃值: 活跃值 (1639)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bluefish蓝鱼 活跃值 2022-4-17 23:19
4
0
xiaomajia 跟老版本相比,没有什么太大的变化,无非就是舍弃了一些多余的设计和api,扩展的一些更细节的东西,其实我觉得最主要的变化就是现在支持用python3写插件了,这个是最爽的。
以前的IDA也能用python2写脚本呀,最主要脚本函数大改了,以前我的7.0脚本都要在7.6上重写
游客
登录 | 注册 方可回帖
返回