首页
社区
课程
招聘
[原创]IDA分析器指南
2022-4-15 23:55 9773

[原创]IDA分析器指南

2022-4-15 23:55
9773

前言

IDA处理器模块主要分析为三大块,分析器、模拟器和输出器。其中分析器的功能是分析单条指令,模拟器的功能是对指令的模拟,输出器的功能是着色输出反汇编文本。

分析器

分析器的工作包括分析单条指令,用与指令有关的信息填充数据结构insn_t。分析器要充分解析指令的每个比特,填充操作数信息,方便模拟器和输出器的工作。
SDK无法考虑到所有处理器架构,故相关的结构体包含通用字段和额外字段。在开始编写分析器代码前,你需要充分了解目标处理器的指令形式,按需使用额外字段来存储相关的指令信息。
例如:tms320c6系列的指令形式如下所示,你应该使用insn_t中额外字段来存储parallel、cond、unit、cross path这些信息。
[parallel] [cond] ins [.unit][cross path] [op1], [op2], [op3], ...

  • parallel:并行指令符号
  • cond:指令执行的条件
  • ins:指令操作码
  • unit:指令操作的单元
  • cross path:寄存器路径交叉
  • op:操作数

分析器相关数据结构

与分析器相关的数据结构有insn_t和op_t,前者存储指令的信息,后者存储操作数信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//[*]表示必须设置的字段
struct insn_t
{
    ea_t cs;    //代码段寄存器地址,由IDA设置
    ea_t ip;    //当前程序计数器地址,由IDA设置
    ea_t ea;    //当前指令所在地址,由IDA设置,一般与ip相同
    uint16 itype;    //[*]指令类型,一般为指令枚举中的一个元素
    uint16 size;    //[*]指令所占的长度
    union            //额外字段,由开发者决定该字段的作用,可以随意使用
    {
        uint32 auxpref;
        uint16 auxpref_u16[2];
        uint8  auxpref_u8[4];
    };
    char segpref;    //额外字段,由开发者决定该字段的作用,可以随意使用
    char insnpref;    //额外字段,由开发者决定该字段的作用,可以随意使用
    int16 flags;    //以INSN_开头的flag组合,很少用到
    op_t ops[UA_MAXOP];        //[*]操作数信息,指令用了哪些操作数是由LPH中的instruc字段决定的
}
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//[*]表示必须设置的字段
struct op_t
{
    uchar n;    //操作数的序号,一般不需要修改
    optype_t type;    //[*]操作数类型,后面会讲解
    char offb;    //指令字节中偏移所在位置,很少用到
    char offo;    //offb的补充,很少用到
    uchar flags;    //以OF_开头的flag组合,
    op_dtype_t dtype;    //[*]操作数本身的类型
    union    //[*]当type=o_reg、o_phrase、o_displ时使用
    {
        uint16 reg;
        uint16 phrase;
    };
    union    //[*]当type=o_imm、o_displ时使用
    {
        uval_t value;
        struct
        {
            uint16 low;
            uint16 high;
        } value_shorts;
    };
    union    //[*]当type=o_mem、o_displ、o_far、o_near时使用
    {
        ea_t addr;
        struct
        {
            uint16 low;
            uint16 high;
        } addr_shorts;
    };
    union    //额外字段,由开发者决定该字段的作用,可以随意使用
    {
        ea_t specval;
        struct
        {
            uint16 low;
            uint16 high;
        } specval_shorts;
    };
    char specflag1; //额外字段,由开发者决定该字段的作用,可以随意使用
    char specflag2; //额外字段,由开发者决定该字段的作用,可以随意使用
    char specflag3; //额外字段,由开发者决定该字段的作用,可以随意使用
    char specflag4; //额外字段,由开发者决定该字段的作用,可以随意使用
}

操作数类型

指令的操作数个数很多时候不是唯一的,具体要看处理器指令集,以下列举一些例子,可以看到操作数的类型有寄存器、立即数、寻址偏移,常量地址。

  • 0个操作数:如nop | ret
  • 1个操作数:如inc al | push eax | jmp 0x401000
  • 2个操作数:如add eax,1 | mov eax, dword ds:[0x7068000]
  • 3个操作数:如MUL RAX, RBC, RDX

IDA归纳总结这些操作类型,为我们提供了以下操作数类型。像R15[R0+4]这种寻址操作,它是一个操作数,还是是两个或者三个操作数,这取决于你,但只会影响模拟器和输出器的复杂程度。
一般我们会其整体看作一个操作数,并将R0存储到phrase中,4存储到value中,而R15存储到额外字段中,操作数类型选择o_displ,这样可以在输出器中把整个操作数一次性输出。

1
2
3
4
5
6
7
8
9
o_void     =  0, //空操作数,操作数未使用时的值
o_reg      =  1, //寄存器,使用reg字段
o_mem      =  2, //常量地址,使用addr字段
o_phrase   =  3, //寄存器+寄存器的寻址方式,不包含任何立即数,使用phrase(存储寄存器)和额外字段(存储另一个寄存器)
o_displ    =  4, //寄存器+立即数偏移的寻址方式,使用phrase、value和额外字段
o_imm      =  5, //立即数,使用value字段
o_far      =  6, //特殊的地址映射使用该类型,一般很少用到,使用addr字段
o_near     =  7, //跳转地址使用该类型,包含绝对地址和偏移地址,使用addr字段
o_idpspec0 =  8, //额外类型,当上述类型无法满足时可以使用该类型

可能用到的函数

分析器用到的sdk函数不多,因为只是给insn_t结构体赋值。

API 描述
ushort get_word(ea_t ea) 获取指定地址的2字节数据
uint32 get_dword(ea_t ea) 获取指定地址的4字节数据

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回