IDA Python(二)

如果要分析的二进制文件比较大,又要知道某些指令的个数,或者查找某种含有特征的指令,这个时候肉眼去搜索显然是比较耗时的,这个时候就可以充分体验到IDA python脚本的便利;

这里要讲到idautils.FuncItems(ea)这个函数,idautils.FuncItems(ea)实际上返回的是一个迭代器,但是我们将它强制转换为 list 类型。这个 list 以一种连续的方式存储着所有指令的起始地址。现在我们已经完全掌握了如何循环遍历程序中的段,函数和指令,那我们就开始 show 一个非常有用的例子。有时候我们会逆向一个加壳的代码,这时知道代码中哪里进行了动态调用对分析是非常有帮助的。一个动态的调用可能是由 call 或者 jump 加上一个操作数来实现的,比如说 call eax,或者 jmp edi。

在这里插入图片描述
在这里插入图片描述
Python脚本实现描述功能:

import idautils
def example_1():
    for func in idautils.Functions():
        flags = idc.GetFunctionFlags(func)
        if flags & FUNC_LIB or flags & FUNC_THUNK:
             print hex(func), "FUNC_LIB", GetFunctionName(func)
             continue
        dism_addr = list(idautils.FuncItems(func))
        for line in dism_addr:
            m = idc.GetMnem(line)
            if m == 'call' or m == 'jmp':
                op = idc.GetOpType(line, 0)
                if op == o_reg:
                    print "0x%x %s" % (line, idc.GetDisasm(line))

def main():
    example_1()
    
if __name__ == "__main__":
    main()                    

使用 idautils.Functions()获取所有的函数,然后利用 idc.GetFunctionFlags(ea)获取每个函数的标志,如果这个函数是库函数或者这个函数是 thunk 函数,那我们就跳过对它的处理,接下来我们使用idautils.FuncItems(ea) 获取函数中每个指定的起始地址。然后使用
idc.GetMnem(ea)来获取每条指令的操作符,判断操作符是否为 call 或者 jmp。如果是的话,我们就使用 idc.GetOpType(ea, n)来获取操作数,这个函数返回的一个 opt.type 类型的数值(int 类型),这个数值可表示的类型为寄存器,内存引用等等;

效果(op==o_reg):

#call register
0xffffffff81c54e11 call    r13
0xffffffff81c54e6c call    r12
0xffffffff81c5ad0f call    r12
0xffffffff81c5ae03 call    r13
0xffffffff81c61e7e call    rax
0xffffffff81c66a72 call    r12
0xffffffffff600053 call    rax ; qword_FFFFFFFFFF6001A0

这里对操作数进行解释一下:
o_void
如果指令没有任何操作数,它将返回 0;
o_reg
如果操作数是寄存器,则返回这种类型,它的值为 1;

//jmp to register
0xffffffff8102cba5 jmp     rax
0xffffffff81431300 jmp     rcx
0xffffffff8143132c jmp     rax

o_mem
如果操作数是直接寻址的内存,那么返回这种类型,它的值是 2,这种类型对寻找 DATA的引用非常有帮助。

0xffffffff81c3219b jmp     ds:off_FFFFFFFF81602A40[rax*8]; switch jump
0xffffffff81c375c4 jmp     ds:off_FFFFFFFF816097A0[rax*8]; switch jump
0xffffffff81c3828a jmp     ds:off_FFFFFFFF816097C8[rax*8]; switch jump
0xffffffff81c3ce16 jmp     ds:off_FFFFFFFF81609940[rax*8]; switch jump
0xffffffff81c5def2 jmp     ds:off_FFFFFFFF816476E8[r15*8]; switch jump

o_phrase
如果操作数是利用基址寄存器和变址寄存器的寻址操作的话,那么返回该类型,值为 3;

0xffffffff8118c548 mov     [rsp+10h+var_10], rbx
0xffffffff8118c5f8 mov     [rsp+10h+var_10], rbx
0xffffffff8118c6a8 mov     [rsp+10h+var_10], rbx
0xffffffff8118c758 mov     [rsp+10h+var_10], rbx
0xffffffff8118c808 mov     [rsp+10h+var_10], rbx
0xffffffff8118c8b8 mov     [rsp+10h+var_10], rbx

o_displ
如果操作数是利用寄存器和位移的寻址操作的话,返回该类型,值为 4;

0xffffffff81075e44 mov     dword ptr [rax+1000h], 0
0xffffffff81075e4e mov     dword ptr [rax+1004h], 0
0xffffffff81075ed8 mov     [rbp+var_18], rbx
0xffffffff81075edc mov     [rbp+var_10], r12
0xffffffff81075ee0 mov     [rbp+var_8], r13

o_imm
如果操作数是一个确定的数值的话,那么返回类型,值为 5;
o_f ar
这种返回类型在 x86 和 x86_64 的逆向中不常见。它用来判断直接访问远端地址的操作数,值为 6;
o_near
这种返回类型在 x86 和 x86_64 的逆向中不常见。它用来判断直接访问近端地址的操作数,值为 7;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值