-
-
[原创]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漏洞挖掘与利用;代码审计。