rev-idapython

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

rev-idapython - IDAPython / IDALib Script Reference

rev-idapython - IDAPython / IDALib 脚本参考

IDAPython script snippets for IDA interactive use and IDALib headless analysis. Use as reference when generating IDAPython code.
  • IDAPython: scripts run inside IDA GUI (Script Command, plugin, or IDC console)
  • IDALib: headless mode introduced in IDA 9.0 — run analysis scripts without opening the IDA GUI

适用于IDA交互式使用和IDALib无头分析的IDAPython代码片段。生成IDAPython代码时可将其作为参考。
  • IDAPython:脚本在IDA GUI中运行(脚本命令、插件或IDC控制台)
  • IDALib:IDA 9.0引入的无头模式——无需打开IDA GUI即可运行分析脚本

Common API

常用API

Register Operations

寄存器操作

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

Debug Memory Operations

调试内存操作

python
idc.read_dbg_byte(addr)
idc.read_dbg_memory(addr, size)
idc.read_dbg_dword(addr)
idc.read_dbg_qword(addr)
idc.patch_dbg_byte(addr, val)
idc.add_bpt(0x409437)          # add breakpoint
idaapi.get_imagebase()         # get image base address
python
idc.read_dbg_byte(addr)
idc.read_dbg_memory(addr, size)
idc.read_dbg_dword(addr)
idc.read_dbg_qword(addr)
idc.patch_dbg_byte(addr, val)
idc.add_bpt(0x409437)          # 添加断点
idaapi.get_imagebase()         # 获取镜像基地址

Local Memory Operations (modifies IDB database)

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

python
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_db_byte(addr)
idc.get_bytes(addr, size)
idaapi.get_dword(addr)
idc.get_strlit_contents          # read string literal
python
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_db_byte(addr)
idc.get_bytes(addr, size)
idaapi.get_dword(addr)
idc.get_strlit_contents          # 读取字符串字面量

Disassembly

反汇编

python
GetDisasm(addr)                  # get disassembly text
idc.next_head(ea)                # get next instruction address
idc.create_insn(addr)            # c, Make Code
ida_bytes.create_strlit          # create string, same as 'A' key
ida_funcs.add_func(addr)         # p, create function
idc.del_items(addr)              # U, undefine
python
GetDisasm(addr)                  # 获取反汇编文本
idc.next_head(ea)                # 获取下一条指令地址
idc.create_insn(addr)            # 对应快捷键C,创建指令
ida_bytes.create_strlit          # 创建字符串,对应快捷键A
ida_funcs.add_func(addr)         # 对应快捷键P,创建函数
idc.del_items(addr)              # 对应快捷键U,取消定义

Address Conversion

地址转换

python
idc.get_name_ea(0, '_sub_6051')  # get address by function name
python
idc.get_name_ea(0, '_sub_6051')  # 通过函数名获取地址

Function Operations

函数操作

python
ida_funcs.get_func(ea)           # get function descriptor
python
ida_funcs.get_func(ea)           # 获取函数描述符

enumerate all functions

枚举所有函数

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

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

---

Code Snippets

代码片段

Byte Pattern Search

字节模式搜索

python
import ida_bytes
import ida_idaapi
import ida_funcs
import idc
python
import ida_bytes
import ida_idaapi
import ida_funcs
import idc

find_bytes_list("90 90 90 90 90")

find_bytes_list("90 90 90 90 90")

find_bytes_list("55 ??")

find_bytes_list("55 ??")

returns list of matching addresses

返回匹配地址的列表

def find_bytes_list(bytes_pattern): ea = -1 result = [] while True: ea = idc.find_bytes(bytes_pattern, ea + 1) if ea == ida_idaapi.BADADDR: break result.append(ea) return result
undefined
def find_bytes_list(bytes_pattern): ea = -1 result = [] while True: ea = idc.find_bytes(bytes_pattern, ea + 1) if ea == ida_idaapi.BADADDR: break result.append(ea) return result
undefined

Appcall - Call Debuggee Functions

Appcall - 调用被调试程序的函数

python
undefined
python
undefined

test check_passwd(char *passwd) -> int

测试 check_passwd(char *passwd) -> int

passwd = ida_idd.Appcall.byref("MyFirstGuess") res = ida_idd.Appcall.check_passwd(passwd) if res.value == 0: print("Good passwd !") else: print("Bad passwd...")

```python
passwd = ida_idd.Appcall.byref("MyFirstGuess") res = ida_idd.Appcall.check_passwd(passwd) if res.value == 0: print("密码正确!") else: print("密码错误...")

```python

Explicitly create the buffer as a byref object

显式创建byref类型的缓冲区

s_in = Appcall.byref("SomeEncryptedBuffer")
s_in = Appcall.byref("SomeEncryptedBuffer")

Buffers are always returned byref

缓冲区始终以byref形式返回

s_out = Appcall.buffer(" ", SizeOfBuffer)
s_out = Appcall.buffer(" ", SizeOfBuffer)

Call the debuggee

调用被调试程序的函数

Appcall.decrypt_buffer(s_in, s_out, SizeOfBuffer)
Appcall.decrypt_buffer(s_in, s_out, SizeOfBuffer)

Print the result

打印结果

print "decrypted=", s_out.value

```python
loadlib = Appcall.proto("kernel32_LoadLibraryA", "int __stdcall loadlib(const char *fn);")
hmod = loadlib("dll_to_inject.dll")

getlasterror = Appcall.proto("kernel32_GetLastError", "DWORD __stdcall GetLastError();")
print "lasterror=", getlasterror()

getcmdline = Appcall.proto("kernel32_GetCommandLineA", "const char *__stdcall getcmdline();")
print "command line:", getcmdline()
print "解密结果=", s_out.value

```python
loadlib = Appcall.proto("kernel32_LoadLibraryA", "int __stdcall loadlib(const char *fn);")
hmod = loadlib("dll_to_inject.dll")

getlasterror = Appcall.proto("kernel32_GetLastError", "DWORD __stdcall GetLastError();")
print "最后错误码=", getlasterror()

getcmdline = Appcall.proto("kernel32_GetCommandLineA", "const char *__stdcall getcmdline();")
print "命令行:", getcmdline()

Cross References

交叉引用

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

shorthand

简写形式

[ref.frm for ref in idautils.XrefsTo(start_ea)]
undefined
[ref.frm for ref in idautils.XrefsTo(start_ea)]
undefined

Basic Block Traversal

基本块遍历

python
fn = 0x4800
f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags=idaapi.FC_PREDS)
for block in f_blocks:
    print(hex(block.start_ea))
python
undefined
python
fn = 0x4800
f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags=idaapi.FC_PREDS)
for block in f_blocks:
    print(hex(block.start_ea))
python
undefined

successor blocks

后继基本块

for succ in block.succs(): print hex(succ.start_ea)
for succ in block.succs(): print hex(succ.start_ea)

predecessor blocks

前驱基本块

for pred in block.preds(): print hex(pred.start_ea)
undefined
for pred in block.preds(): print hex(pred.start_ea)
undefined

Debug Memory Read/Write

调试内存读写

python
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)
python
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)

Read std::string (64-bit)

读取std::string(64位)

python
def dbg_read_cppstr_64(objectAddr):
    strPtr = idc.read_dbg_qword(objectAddr)
    result = ''
    i = 0
    while True:
        onebyte = idc.read_dbg_byte(strPtr + i)
        if onebyte == 0:
            break
        else:
            result += chr(onebyte)
            i += 1
    return result
python
def dbg_read_cppstr_64(objectAddr):
    strPtr = idc.read_dbg_qword(objectAddr)
    result = ''
    i = 0
    while True:
        onebyte = idc.read_dbg_byte(strPtr + i)
        if onebyte == 0:
            break
        else:
            result += chr(onebyte)
            i += 1
    return result

Read C String (64-bit)

读取C字符串(64位)

python
def dbg_read_cstr_64(objectAddr):
    strPtr = objectAddr
    result = ''
    i = 0
    while True:
        onebyte = idc.read_dbg_byte(strPtr + i)
        if onebyte == 0:
            break
        else:
            result += chr(onebyte)
            i += 1
    return result
python
def dbg_read_cstr_64(objectAddr):
    strPtr = objectAddr
    result = ''
    i = 0
    while True:
        onebyte = idc.read_dbg_byte(strPtr + i)
        if onebyte == 0:
            break
        else:
            result += chr(onebyte)
            i += 1
    return result

Parse GNU C++ std::map

解析GNU C++ std::map

python
import idautils
import idaapi
import idc

def parse_gnu_map_header(address):
    root = idc.read_dbg_qword(address + 0x10)
    return root

def parse_gnu_map_node(address):
    left  = idc.read_dbg_qword(address + 0x10)
    right = idc.read_dbg_qword(address + 0x18)
    data  = address + 0x20
    return left, right, data

def parse_gnu_map_travel(address):
    # address <- std::map struct address
    result = []
    worklist = [parse_gnu_map_header(address)]
    while len(worklist) > 0:
        addr = worklist.pop()
        (left, right, data) = parse_gnu_map_node(addr)
        if left > 0: worklist.append(left)
        if right > 0: worklist.append(right);
        result.append(data)
    return result
python
import idautils
import idaapi
import idc

def parse_gnu_map_header(address):
    root = idc.read_dbg_qword(address + 0x10)
    return root

def parse_gnu_map_node(address):
    left  = idc.read_dbg_qword(address + 0x10)
    right = idc.read_dbg_qword(address + 0x18)
    data  = address + 0x20
    return left, right, data

def parse_gnu_map_travel(address):
    # address <- std::map结构体地址
    result = []
    worklist = [parse_gnu_map_header(address)]
    while len(worklist) > 0:
        addr = worklist.pop()
        (left, right, data) = parse_gnu_map_node(addr)
        if left > 0: worklist.append(left)
        if right > 0: worklist.append(right);
        result.append(data)
    return result

example

示例

elements = parse_gnu_map_travel(0x0000557518073EB0) for elem in elements: print(hex(elem))
undefined
elements = parse_gnu_map_travel(0x0000557518073EB0) for elem in elements: print(hex(elem))
undefined

Read XMM Register (Debug)

读取XMM寄存器(调试时)

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

Step Over and Wait for Debug Event

单步执行并等待调试事件

python
while ida_dbg.step_over():
    wait_for_next_event(WFNE_ANY, -1)
    rip = idc.get_reg_value("rip")
    # .....
python
while ida_dbg.step_over():
    wait_for_next_event(WFNE_ANY, -1)
    rip = idc.get_reg_value("rip")
    # .....

Iterate Instructions in a Function

遍历函数中的指令

python
for ins in idautils.FuncItems(0x401000):
    print(hex(ins))
python
for ins in idautils.FuncItems(0x401000):
    print(hex(ins))

Get Function Callees (Instruction-Based)

获取函数的被调用者(基于指令)

python
def ida_get_callees(func_addr: int) -> list:
    callees = []
    for head in idautils.Heads(func_addr, idaapi.get_func(func_addr).end_ea):
        if idaapi.is_call_insn(head):
            callee_ea = idc.get_operand_value(head, 0)
            callees.append(callee_ea)
    return callees
python
def ida_get_callees(func_addr: int) -> list:
    callees = []
    for head in idautils.Heads(func_addr, idaapi.get_func(func_addr).end_ea):
        if idaapi.is_call_insn(head):
            callee_ea = idc.get_operand_value(head, 0)
            callees.append(callee_ea)
    return callees

Double / Complex Number Memory Operations

双精度/复数内存操作

python
def float_to_double_bytearray(value):
    double_value = ctypes.c_double(value)
    byte_array = bytearray(ctypes.string_at(ctypes.byref(double_value), ctypes.sizeof(double_value)))
    return byte_array

def set_pos(x, y): # complex<double, double>
    rbp = idc.get_reg_value("rbp")
    complex_base = rbp - 0x260

    patch_dbg_mem(complex_base, float_to_double_bytearray(x))
    patch_dbg_mem(complex_base + 8, float_to_double_bytearray(y))

set_pos(5.0, 6.0)

python
def float_to_double_bytearray(value):
    double_value = ctypes.c_double(value)
    byte_array = bytearray(ctypes.string_at(ctypes.byref(double_value), ctypes.sizeof(double_value)))
    return byte_array

def set_pos(x, y): # complex<double, double>
    rbp = idc.get_reg_value("rbp")
    complex_base = rbp - 0x260

    patch_dbg_mem(complex_base, float_to_double_bytearray(x))
    patch_dbg_mem(complex_base + 8, float_to_double_bytearray(y))

set_pos(5.0, 6.0)

Import Table

导入表

Enumerate Import Table

枚举导入表

python
import ida_nalt

nimps = ida_nalt.get_import_module_qty()

print("Found %d import(s)..." % nimps)

for i in range(nimps):
    name = ida_nalt.get_import_module_name(i)
    if not name:
        print("Failed to get import module name for #%d" % i)
        name = "<unnamed>"

    print("Walking imports for module %s" % name)
    def imp_cb(ea, name, ordinal):
        if not name:
            print("%08x: ordinal #%d" % (ea, ordinal))
        else:
            print("%08x: %s (ordinal #%d)" % (ea, name, ordinal))
        return True
    ida_nalt.enum_import_names(i, imp_cb)

print("All done...")
python
import ida_nalt

nimps = ida_nalt.get_import_module_qty()

print("找到 %d 个导入模块..." % nimps)

for i in range(nimps):
    name = ida_nalt.get_import_module_name(i)
    if not name:
        print("无法获取第%d个导入模块的名称" % i)
        name = "<未命名>"

    print("遍历模块 %s 的导入项" % name)
    def imp_cb(ea, name, ordinal):
        if not name:
            print("%08x: 序号 #%d" % (ea, ordinal))
        else:
            print("%08x: %s (序号 #%d)" % (ea, name, ordinal))
        return True
    ida_nalt.enum_import_names(i, imp_cb)

print("完成...")

Check if Address is an Import Function

检查地址是否为导入函数

python
def ida_is_import_function(addr: int) -> bool:
    is_find = False

    nimps = ida_nalt.get_import_module_qty()

    for i in range(nimps):
        def imp_cb(ea, name, ordinal):
            nonlocal is_find
            if ea == addr:
                is_find = True
                return False
            return True
        ida_nalt.enum_import_names(i, imp_cb)

    return is_find
python
def ida_is_import_function(addr: int) -> bool:
    is_find = False

    nimps = ida_nalt.get_import_module_qty()

    for i in range(nimps):
        def imp_cb(ea, name, ordinal):
            nonlocal is_find
            if ea == addr:
                is_find = True
                return False
            return True
        ida_nalt.enum_import_names(i, imp_cb)

    return is_find

Enumerate Import Addresses

枚举导入地址

python
def ida_enum_import_addr() -> List[int]:
    import_addrs = []
    nimps = ida_nalt.get_import_module_qty()
    for i in range(nimps):
        def imp_cb(ea, name, ordinal):
            nonlocal import_addrs
            import_addrs.append(ea)
            return True
        ida_nalt.enum_import_names(i, imp_cb)
    return import_addrs

python
def ida_enum_import_addr() -> List[int]:
    import_addrs = []
    nimps = ida_nalt.get_import_module_qty()
    for i in range(nimps):
        def imp_cb(ea, name, ordinal):
            nonlocal import_addrs
            import_addrs.append(ea)
            return True
        ida_nalt.enum_import_names(i, imp_cb)
    return import_addrs

Type Information

类型信息

Struct Member Traversal

遍历结构体成员

python
def extract_struct_members(type_name):
    fields = []
    tif = ida_typeinf.tinfo_t()
    if tif.get_named_type(None, type_name):
        offset = 0
        for iter in tif.iter_struct(): # udm
            fsize = iter.type.get_size()
            fields.append({
                "offset": iter.offset // 8, # bit offset
                "size": fsize,
                "type": iter.type._print()
            })
            offset += fsize
    else:
        print(f"Unable to get {type_name} type info.")
    return fields

extract_struct_members("sqlite3_vfs")
python
def extract_struct_members(type_name):
    fields = []
    tif = ida_typeinf.tinfo_t()
    if tif.get_named_type(None, type_name):
        offset = 0
        for iter in tif.iter_struct(): # udm
            fsize = iter.type.get_size()
            fields.append({
                "offset": iter.offset // 8, # 位偏移
                "size": fsize,
                "type": iter.type._print()
            })
            offset += fsize
    else:
        print(f"无法获取 {type_name} 的类型信息。")
    return fields

extract_struct_members("sqlite3_vfs")

Enumerate All Types

枚举所有类型

python
til = ida_typeinf.get_idati()
for type_name in til.get_type_names():
    print(type_name)
python
til = ida_typeinf.get_idati()
for type_name in til.get_type_names():
    print(type_name)

List All Struct Types

列出所有结构体类型

python
def list_struct_types():
    types = []
    til = ida_typeinf.get_idati()
    for type_name in til.get_type_names():
        tif = ida_typeinf.tinfo_t()
        if tif.get_named_type(None, type_name):
            if tif.is_struct():
                types.append(type_name)
    return types

python
def list_struct_types():
    types = []
    til = ida_typeinf.get_idati()
    for type_name in til.get_type_names():
        tif = ida_typeinf.tinfo_t()
        if tif.get_named_type(None, type_name):
            if tif.is_struct():
                types.append(type_name)
    return types

Hex-Rays Decompiler API

Hex-Rays反编译器API

Decompile a Function

反编译函数

python
undefined
python
undefined

verified: IDA 9.0

已验证:IDA 9.0

dec = ida_hexrays.decompile(func_addr)
dec = ida_hexrays.decompile(func_addr)

dec is an object, str(dec) converts to text

dec是对象,str(dec)转换为文本

print(str(dec))
undefined
print(str(dec))
undefined

Print Microcode at Different Maturity Levels

打印不同成熟度的微代码

python
def print_microcode(func_ea):
    maturity = ida_hexrays.MMAT_GLBOPT3
    #   maturity:
    #   MMAT_ZERO,         ///< microcode does not exist
    #   MMAT_GENERATED,    ///< generated microcode
    #   MMAT_PREOPTIMIZED, ///< preoptimized pass is complete
    #   MMAT_LOCOPT,       ///< local optimization of each basic block is complete.
    #                      ///< control flow graph is ready too.
    #   MMAT_CALLS,        ///< detected call arguments
    #   MMAT_GLBOPT1,      ///< performed the first pass of global optimization
    #   MMAT_GLBOPT2,      ///< most global optimization passes are done
    #   MMAT_GLBOPT3,      ///< completed all global optimization. microcode is fixed now.
    #   MMAT_LVARS,        ///< allocated local variables
    hf = ida_hexrays.hexrays_failure_t()
    pfn = idaapi.get_func(func_ea)
    rng = ida_hexrays.mba_ranges_t(pfn)
    mba = ida_hexrays.gen_microcode(rng, hf, None,
                ida_hexrays.DECOMP_WARNINGS, maturity)
    vp = ida_hexrays.vd_printer_t()
    mba._print(vp)
print_microcode(0x1229)
python
def print_microcode(func_ea):
    maturity = ida_hexrays.MMAT_GLBOPT3
    #   maturity:
    #   MMAT_ZERO,         ///< 微代码不存在
    #   MMAT_GENERATED,    ///< 已生成微代码
    #   MMAT_PREOPTIMIZED, ///< 预优化阶段完成
    #   MMAT_LOCOPT,       ///< 每个基本块的本地优化完成,控制流图也已就绪
    #   MMAT_CALLS,        ///< 已检测到调用参数
    #   MMAT_GLBOPT1,      ///< 完成第一轮全局优化
    #   MMAT_GLBOPT2,      ///< 大部分全局优化阶段完成
    #   MMAT_GLBOPT3,      ///< 完成所有全局优化,微代码已固定
    #   MMAT_LVARS,        ///< 已分配局部变量
    hf = ida_hexrays.hexrays_failure_t()
    pfn = idaapi.get_func(func_ea)
    rng = ida_hexrays.mba_ranges_t(pfn)
    mba = ida_hexrays.gen_microcode(rng, hf, None,
                ida_hexrays.DECOMP_WARNINGS, maturity)
    vp = ida_hexrays.vd_printer_t()
    mba._print(vp)
print_microcode(0x1229)

Custom Instruction to User-Defined Call

将自定义指令转换为用户定义的调用

python
class udc_exit_t(ida_hexrays.udc_filter_t):
    def __init__(self, code, name):
        ida_hexrays.udc_filter_t.__init__(self)
        if not self.init("int __usercall %s@<R0>(int status@<R1>);" % name):
            raise Exception("Couldn't initialize udc_exit_t instance")
        self.code = code
        self.installed = False

    def match(self, cdg):
        return cdg.insn.itype == ida_allins.ARM_svc and cdg.insn.Op1.value == self.code

    def install(self):
        ida_hexrays.install_microcode_filter(self, True);
        self.installed = True

    def uninstall(self):
        ida_hexrays.install_microcode_filter(self, False);
        self.installed = False

    def toggle_install(self):
        if self.installed:
            self.uninstall()
        else:
            self.install()

udc_exit = udc_exit_t(0x900001, "svc_exit")
udc_exit.toggle_install()
python
class udc_exit_t(ida_hexrays.udc_filter_t):
    def __init__(self, code, name):
        ida_hexrays.udc_filter_t.__init__(self)
        if not self.init("int __usercall %s@<R0>(int status@<R1>);" % name):
            raise Exception("无法初始化udc_exit_t实例")
        self.code = code
        self.installed = False

    def match(self, cdg):
        return cdg.insn.itype == ida_allins.ARM_svc and cdg.insn.Op1.value == self.code

    def install(self):
        ida_hexrays.install_microcode_filter(self, True);
        self.installed = True

    def uninstall(self):
        ida_hexrays.install_microcode_filter(self, False);
        self.installed = False

    def toggle_install(self):
        if self.installed:
            self.uninstall()
        else:
            self.install()

udc_exit = udc_exit_t(0x900001, "svc_exit")
udc_exit.toggle_install()

Hexrays_Hooks

Hexrays_Hooks

python
class MicrocodeCallback(ida_hexrays.Hexrays_Hooks):
    def __init__(self, *args):
        super().__init__(*args)
    def microcode(self, mba: ida_hexrays.mba_t) -> "int":
        print("microcode generated.")
        return 0
r = MicrocodeCallback()
r.hook()

python
class MicrocodeCallback(ida_hexrays.Hexrays_Hooks):
    def __init__(self, *args):
        super().__init__(*args)
    def microcode(self, mba: ida_hexrays.mba_t) -> "int":
        print("微代码已生成。")
        return 0
r = MicrocodeCallback()
r.hook()

Obfuscation Helpers

混淆处理工具

OLLVM - Set Breakpoints on Real Blocks

OLLVM - 在真实代码块上设置断点

Set breakpoints on all real block entry addresses. Real blocks are identified by finding predecessors of the OLLVM dispatcher merge point.
Note: identifying real blocks by xrefs to the merge point is a heuristic and may not be fully accurate. Use IDA breakpoint groups for batch management.
python
fn = 0x401F60
ollvm_tail = 0x405D4B # OLLVM real block merge point
f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags=idaapi.FC_PREDS)
for block in f_blocks:
    for succ in block.succs():
        if succ.start_ea == ollvm_tail:
            print(hex(block.start_ea))
            idc.add_bpt(block.start_ea)
在所有真实代码块的入口地址设置断点。真实代码块通过查找OLLVM分发器合并点的前驱来识别。
注意:通过合并点的交叉引用识别真实代码块是一种启发式方法,可能并不完全准确。使用IDA断点组进行批量管理。
python
fn = 0x401F60
ollvm_tail = 0x405D4B # OLLVM真实代码块合并点
f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags=idaapi.FC_PREDS)
for block in f_blocks:
    for succ in block.succs():
        if succ.start_ea == ollvm_tail:
            print(hex(block.start_ea))
            idc.add_bpt(block.start_ea)

Batch Add Breakpoints

批量添加断点

python
def brkall(l):
    for addr in l:
        idc.add_bpt(addr)

python
def brkall(l):
    for addr in l:
        idc.add_bpt(addr)

Firmware Helpers

固件处理工具

Search x86 Function Prologues and Create Functions

搜索x86函数序言并创建函数

python
undefined
python
undefined

verified: IDA 9.0

已验证:IDA 9.0

def make_x86_func(): func_headers = find_bytes_list("55 8B") for h in func_headers: idc.del_items(h) idc.create_insn(h) ida_funcs.add_func(h)

---
def make_x86_func(): func_headers = find_bytes_list("55 8B") for h in func_headers: idc.del_items(h) idc.create_insn(h) ida_funcs.add_func(h)

---

Basic Block Utilities

基本块工具

Get Basic Block Size

获取基本块大小

python
undefined
python
undefined

verified: IDA 9.0

已验证:IDA 9.0

def get_bb_size(bbaddr): fn = bbaddr f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags=idaapi.FC_PREDS) for block in f_blocks: if block.start_ea == bbaddr: return block.end_ea - block.start_ea raise Exception("Not found")
undefined
def get_bb_size(bbaddr): fn = bbaddr f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags=idaapi.FC_PREDS) for block in f_blocks: if block.start_ea == bbaddr: return block.end_ea - block.start_ea raise Exception("未找到")
undefined

Get Basic Block by Address

通过地址获取基本块

python
def ida_get_bb(ea):
    f_blocks = idaapi.FlowChart(idaapi.get_func(ea), flags=idaapi.FC_PREDS)
    for block in f_blocks:
        if block.start_ea <= ea and ea < block.end_ea:
            return block
    return None

python
def ida_get_bb(ea):
    f_blocks = idaapi.FlowChart(idaapi.get_func(ea), flags=idaapi.FC_PREDS)
    for block in f_blocks:
        if block.start_ea <= ea and ea < block.end_ea:
            return block
    return None

Instruction Utilities

指令工具

Search Next Instruction by Keyword

按关键字搜索下一条指令

python
undefined
python
undefined

verified: IDA 9.0

已验证:IDA 9.0

def search_next_insn(addr, insnkey, max_search=0x100): cnt = 0 while cnt < max_search: addr = idc.next_head(addr) dis = GetDisasm(addr) if insnkey in dis: return addr cnt += 1 return None
def search_next_insn(addr, insnkey, max_search=0x100): cnt = 0 while cnt < max_search: addr = idc.next_head(addr) dis = GetDisasm(addr) if insnkey in dis: return addr cnt += 1 return None

example

示例

search_next_insn(addr, 'movdqa')

search_next_insn(addr, 'movdqa')

undefined
undefined

Undefine a Range (U key equivalent)

取消定义一段范围(对应快捷键U)

python
undefined
python
undefined

verified: IDA 9.0

已验证:IDA 9.0

def undefine_range(start, end): for i in range(start, end): idc.del_items(i)
def undefine_range(start, end): for i in range(start, end): idc.del_items(i)

example

示例

undefine_range(func_start, func_end)

undefine_range(func_start, func_end)

undefined
undefined

Search Disassembly Text

搜索反汇编文本

python
undefined
python
undefined

verified: IDA 9.0

已验证:IDA 9.0

def search_text_all(text): import idaapi, idc start_ea = 0 result = [] while True: start_ea = idaapi.find_text(ustr=text, x=0, y=0, sflag=idaapi.SEARCH_DOWN, start_ea=start_ea) if start_ea == idc.BADADDR: break result.append(start_ea) start_ea = idc.next_head(start_ea) return result
def search_text_all(text): import idaapi, idc start_ea = 0 result = [] while True: start_ea = idaapi.find_text(ustr=text, x=0, y=0, sflag=idaapi.SEARCH_DOWN, start_ea=start_ea) if start_ea == idc.BADADDR: break result.append(start_ea) start_ea = idc.next_head(start_ea) return result

example

示例

for x in search_text_all('movdqa'): print(GetDisasm(x))

---
for x in search_text_all('movdqa'): print(GetDisasm(x))

---

NOP Function

NOP函数

python
import idaapi
import idautils
import idc

def nop_func(addr_func, arch='arm'):
    func = ida_funcs.get_func(addr_func)
    if not func:
        print("Function not found!")
        return

    start = func.start_ea
    end = func.end_ea

    print(f"Nopping function at: 0x{start:x} - 0x{end:x}")

    if arch == 'x86':
        nop_bytes = [0x90]  # x86 NOP
    elif arch == 'arm':
        nop_bytes = [0x1F, 0x20, 0x03, 0xD5]  # ARM NOP
    else:
        print(f"Unsupported architecture: {arch}")
        return

    ea = start
    while ea < end:
        insn = ida_ua.insn_t()
        length = ida_ua.decode_insn(insn, ea)
        if length == 0:
            print(f"Failed to decode instruction at: 0x{ea:x}")
            break

        nop_len = len(nop_bytes)
        for i in range(0, length, nop_len):
            for j in range(nop_len):
                if i + j < length:
                    idc.patch_byte(ea + i + j, nop_bytes[j])

        ea += length

    print("Nopping complete.")
python
import idaapi
import idautils
import idc

def nop_func(addr_func, arch='arm'):
    func = ida_funcs.get_func(addr_func)
    if not func:
        print("未找到函数!")
        return

    start = func.start_ea
    end = func.end_ea

    print(f"正在将函数转换为NOP: 0x{start:x} - 0x{end:x}")

    if arch == 'x86':
        nop_bytes = [0x90]  # x86架构的NOP指令
    elif arch == 'arm':
        nop_bytes = [0x1F, 0x20, 0x03, 0xD5]  # ARM架构的NOP指令
    else:
        print(f"不支持的架构: {arch}")
        return

    ea = start
    while ea < end:
        insn = ida_ua.insn_t()
        length = ida_ua.decode_insn(insn, ea)
        if length == 0:
            print(f"无法解码地址0x{ea:x}处的指令")
            break

        nop_len = len(nop_bytes)
        for i in range(0, length, nop_len):
            for j in range(nop_len):
                if i + j < length:
                    idc.patch_byte(ea + i + j, nop_bytes[j])

        ea += length

    print("NOP转换完成。")

example

示例

nop_func(0x401000, 'arm')

---
nop_func(0x401000, 'arm')

---

IDALib (Headless IDA, IDA 9.0+)

IDALib(无头IDA,IDA 9.0+)

IDALib allows running IDAPython analysis scripts without opening the IDA GUI.
IDALib允许无需打开IDA GUI即可运行IDAPython分析脚本。

Installation

安装

bash
cd idalib/python
pip install .
python py-activate-idalib.py
bash
cd idalib/python
pip install .
python py-activate-idalib.py

Basic Usage

基本用法

python
import idapro # must be the first import
import idautils
import idc
python
import idapro # 必须是第一个导入的模块
import idautils
import idc

open idb/binary file

打开idb/二进制文件

ida.open_database("samples/patch.so", True)
ida.open_database("samples/patch.so", True)

enumerate functions

枚举函数

for func in idautils.Functions(): func_name = idc.get_func_name(func) print("Function Name: {}, Address: {}".format(func_name, hex(func)))
for func in idautils.Functions(): func_name = idc.get_func_name(func) print("函数名称: {}, 地址: {}".format(func_name, hex(func)))

close and save idb

关闭并保存idb

ida.close_database(save=True)
undefined
ida.close_database(save=True)
undefined

Batch Decompile to JSON

批量反编译为JSON

bash
Usage: decompile.py <input_file_elf> <output_file_json>
decompile.py:
python
import idapro

import ida_hexrays
import idautils
import idc

import os
import sys
import json

def _decompile_internal():
    result = []
    for func in idautils.Functions():
        func_name = idc.get_func_name(func)
        print("Function Name: {}, Address: {}".format(func_name, hex(func)))
        dec_obj = ida_hexrays.decompile(func)
        if dec_obj is None:
            continue
        dec_str = str(dec_obj)
        result.append({
            'name': func_name,
            'address': hex(func),
            'decompiled': dec_str
        })
    return result

def decomple_export(file, out_file):
    ida.open_database(file, True)
    r = _decompile_internal()
    ida.close_database(save=False)
    open(out_file, "w").write(json.dumps(r, indent=4))

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: {} <input_file_elf> <output_file_json>".format(sys.argv[0]))
        sys.exit(1)
    decomple_export(sys.argv[1], sys.argv[2])
bash
用法: decompile.py <输入ELF文件> <输出JSON文件>
decompile.py:
python
import idapro

import ida_hexrays
import idautils
import idc

import os
import sys
import json

def _decompile_internal():
    result = []
    for func in idautils.Functions():
        func_name = idc.get_func_name(func)
        print("函数名称: {}, 地址: {}".format(func_name, hex(func)))
        dec_obj = ida_hexrays.decompile(func)
        if dec_obj is None:
            continue
        dec_str = str(dec_obj)
        result.append({
            'name': func_name,
            'address': hex(func),
            'decompiled': dec_str
        })
    return result

def decomple_export(file, out_file):
    ida.open_database(file, True)
    r = _decompile_internal()
    ida.close_database(save=False)
    open(out_file, "w").write(json.dumps(r, indent=4))

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("用法: {} <输入ELF文件> <输出JSON文件>".format(sys.argv[0]))
        sys.exit(1)
    decomple_export(sys.argv[1], sys.argv[2])

Multiprocess Batch Decompile

多进程批量反编译

python
import os
import time
from multiprocessing import Pool

args = {
    "NUM_WORKERS": 8,
    "INPUT_DIR": "/Users/ctf/idek2024/baby2/baby",
    "OUTPUT_DIR": "/Users/ctf/idek2024/baby2/decompiled",
    "NUM_MAX_RETRY": 3
}

def decomple_one(file, out_file):
    retry = 0
    while True:
        os.system("python3 decompile.py {} {}".format(file, out_file))
        if os.path.exists(out_file):
            break
        retry += 1
        if retry >= args["NUM_MAX_RETRY"]:
            return "Failed to decompile {}".format(file)
        time.sleep(1)
    return None

if __name__ == "__main__":
    if not os.path.exists(args["OUTPUT_DIR"]):
        os.makedirs(args["OUTPUT_DIR"])
    files = os.listdir(args["INPUT_DIR"])

    files = [os.path.join(args["INPUT_DIR"], f) for f in files]
    out_files = [os.path.join(args["OUTPUT_DIR"], os.path.basename(f) + ".json" ) for f in files]
    with Pool(args["NUM_WORKERS"]) as p:
        r = p.starmap(decomple_one, zip(files, out_files))
        for i in r:
            if i is not None:
                print(i)
python
import os
import time
from multiprocessing import Pool

args = {
    "NUM_WORKERS": 8,
    "INPUT_DIR": "/Users/ctf/idek2024/baby2/baby",
    "OUTPUT_DIR": "/Users/ctf/idek2024/baby2/decompiled",
    "NUM_MAX_RETRY": 3
}

def decomple_one(file, out_file):
    retry = 0
    while True:
        os.system("python3 decompile.py {} {}".format(file, out_file))
        if os.path.exists(out_file):
            break
        retry += 1
        if retry >= args["NUM_MAX_RETRY"]:
            return "无法反编译 {}".format(file)
        time.sleep(1)
    return None

if __name__ == "__main__":
    if not os.path.exists(args["OUTPUT_DIR"]):
        os.makedirs(args["OUTPUT_DIR"])
    files = os.listdir(args["INPUT_DIR"])

    files = [os.path.join(args["INPUT_DIR"], f) for f in files]
    out_files = [os.path.join(args["OUTPUT_DIR"], os.path.basename(f) + ".json" ) for f in files]
    with Pool(args["NUM_WORKERS"]) as p:
        r = p.starmap(decomple_one, zip(files, out_files))
        for i in r:
            if i is not None:
                print(i)