rev-idapython
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineserev-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 addresspython
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 literalpython
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, undefinepython
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 namepython
idc.get_name_ea(0, '_sub_6051') # 通过函数名获取地址Function Operations
函数操作
python
ida_funcs.get_func(ea) # get function descriptorpython
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 idcpython
import ida_bytes
import ida_idaapi
import ida_funcs
import idcfind_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
undefineddef 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
undefinedAppcall - Call Debuggee Functions
Appcall - 调用被调试程序的函数
python
undefinedpython
undefinedtest 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...")
```pythonpasswd = ida_idd.Appcall.byref("MyFirstGuess")
res = ida_idd.Appcall.check_passwd(passwd)
if res.value == 0:
print("密码正确!")
else:
print("密码错误...")
```pythonExplicitly 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)]
undefinedBasic 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
undefinedpython
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
undefinedsuccessor 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)
undefinedfor pred in block.preds():
print hex(pred.start_ea)
undefinedDebug 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 resultpython
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 resultRead 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 resultpython
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 resultParse 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 resultpython
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 resultexample
示例
elements = parse_gnu_map_travel(0x0000557518073EB0)
for elem in elements:
print(hex(elem))
undefinedelements = parse_gnu_map_travel(0x0000557518073EB0)
for elem in elements:
print(hex(elem))
undefinedRead 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 calleespython
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 calleesDouble / 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_findpython
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_findEnumerate 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_addrspython
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_addrsType 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 typespython
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 typesHex-Rays Decompiler API
Hex-Rays反编译器API
Decompile a Function
反编译函数
python
undefinedpython
undefinedverified: 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))
undefinedprint(str(dec))
undefinedPrint 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
undefinedpython
undefinedverified: 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
undefinedpython
undefinedverified: 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")
undefineddef 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("未找到")
undefinedGet 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 Nonepython
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 NoneInstruction Utilities
指令工具
Search Next Instruction by Keyword
按关键字搜索下一条指令
python
undefinedpython
undefinedverified: 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')
undefinedundefinedUndefine a Range (U key equivalent)
取消定义一段范围(对应快捷键U)
python
undefinedpython
undefinedverified: 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)
undefinedundefinedSearch Disassembly Text
搜索反汇编文本
python
undefinedpython
undefinedverified: 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.pybash
cd idalib/python
pip install .
python py-activate-idalib.pyBasic Usage
基本用法
python
import idapro # must be the first import
import idautils
import idcpython
import idapro # 必须是第一个导入的模块
import idautils
import idcopen 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)
undefinedida.close_database(save=True)
undefinedBatch 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)