IDAPython

  1. IDA Python 脚本编程
    1. 常用脚本接口介绍
    2. 实战部分

记录ida脚本

IDA Python 脚本编程

内存分为:

  • 本地内存
  • 调试内存

常用脚本接口介绍

寄存器操作(调试)

idc.get_reg_value('rax’)
idaapi.set_reg_val("rax", 1234)

读取 xmm 寄存器

def read_xmm_reg(name):
    rv = idaapi.regval_t()
    idaapi.get_reg_val(name,rv)
    return (struct.unpack("Q",rv.bytes())[0])

调试内存操作 dbg 是指debug内存(调试内存)

idc.read_dbg_byte(addr)
idc.read_dbg_word(addr)
idc.read_dbg_dword(addr)
idc.read_dbg_qword(addr)
idc.read_dbg_memory(addr,size)
idc.patch_dbg_byte(addr,val)

调试内存读写封装

def patch_dbg_mem(addr,data):
    for i in range(len(data)):
        idc.patch_dbg_byte(addr+i,data[i])
        
def read_dbg_mem(addr,size):
    dd = []
    for i in range(size):
        dd.append(idc.read_dbg_byte(addr+i))
    return bytes(dd)

本地内存操作(会修改idb数据库)

idc.get_qword(addr)
idc.patch_qword(addr,val)
idc.patch_dword(addr,val)
idc.patch_word(addr,val)
idc.patch_byte(addr,val)
idc.get_bytes(addr,size)

反汇编操作

idc.GetDisasm(addr) # 只能返回一条汇编指令
idc.next_head(addr) # 获取下一条汇编指令的地址

交叉引用分析

for ref in idautils.XrefsTo(ea):
    print(hex(ref.frm))

杂项常用接口

idc.add_bpt(addr) # 添加断点
idaapi.get_imagebase() # 获取基地址
idc.create_insn(addr) # 生成汇编指令,相当于快捷键C 常用于固件分析
ida_funcs.add_func(addr) # 生成函数,相当于快捷键p
ida_bytes.create_strlit(addr) # 生成字符串,相当于快捷键A

函数遍历

for func in idautils.Functions():
    print("0x%x,%s" % (func,idc.get_func_name(func)))

基本块的遍历

fn = 目标函数地址
f_blocks = idaapi.FlowChart(idaapi.get_func(fn),flags=idaapi.FC_PREDS)
for blocks in f_blocks:
    print(hex(blocks.start_ea))
    # 基本块的前驱
    for pre in blocks.preds():
        print(hex(pre.start_ea))
    # 基本块的后继
    for sucess in blocks.succs():
        print(hex(sucess.start_ea))

指令遍历

for ins in idautils.FuncItems(addr):
    print(hex(ins))

实战部分

ollvm批量断点设置:

实验材料:ollvm-flat

注意:判断真实块的依据是查找 ollvm 汇集点基本块的交叉引用,不一定准确

断点脚本:

import idc
import idaapi
import struct
import idautils

# ollvm函数地址
fn = 0x401F60
# ollvm基本块汇集地址
ollvm_tail = 0x405D4B
# 拿到函数基本块的迭代器
f_blocks = idaapi.FlowChart(idaapi.get_func(fn),flags=idaapi.FC_PREDS)
# 然后遍历函数基本块
for block in f_blocks:
    # 拿到每个基本块的后驱
    for sucess in block.succs():
        if sucess.start_ea == ollvm_tail:
            print(hex(block.start_ea))
            idc.add_bpt(block.start_ea)

复制到ida下面,摁回车两次就行

image-20230119182419401

成功打上断点,打上断点的基本块都是真实块

image-20230119182530944

断点管理

image-20230119182636581

全选右键生成文件夹

image-20230119182727613

点击文件夹,进行断点的批量禁用或启用

image-20230119182906812

条件断点脚本编写:

实验材料:dump_test.exe

目标:设置一个条件断点,当 rand 函数返回值为 16949 时停下

找到random函数

image-20230119183303757

设置断点

image-20230119183327074

在断点处右键编辑断点

image-20230119183413079

脚本:

import idc
import idaapi
import struct
import idautils

def bp():
    rax = idc.get_reg_value('rax')
    return rax == 16949

先在ida中执行脚本

然后编辑断点,增加condition条件

image-20230119183620480

然后运行程序

程序停下来后,就查看rax寄存器,经过16进制转10进制,结果正确

image-20230119183829577

条件断点运用:dump rand 函数每一次执行结果,不让程序停下来

脚本:条件断点函数返回 False,IDA 不会命中该断点,利用这个特性提取运行时数据

def bp():
    rax = idc.get_reg_value('rax')
    print(rax,end=',')
    return False

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏