IDA python script cheatsheet - aeskkkey/reverse GitHub Wiki
个人笔记,转载请注明出处。
ida8.0, arm64, 仅供api使用参考
常用代码
# so开始地址
idc.get_inf_attr(idc.INF_MIN_EA)
# so结束地址
idc.get_inf_attr(idc.INF_MAX_EA)
# 遍历函数的所有引用
ea = ida_xref.get_first_cref_to(ea)
while ea != idc.BADADDR:
ea = ida_xref.get_next_cref_to(decode_string_func, ea)
# 或者
for ea in idautils.CodeRefsTo(ea, 1):
print(hex(ea))
# 或者idautils.XrefsTo(ea, 1)
# 获取某地址指令字符串,带备注的
insn = idc.GetDisasm(addr) # 例如返回 insn="MOV X1, #0x35; msg"
# 获取某地址指令的操作数,例如 MOV X1, #0x35
x1 = idc.get_operand_value(addr, 0) # x1 = 83,指寄存器X1/W1
imm = idc.get_operand_value(addr, 1) # imm = 0x35,指立即数值
t = idc.get_operand_type(addr, 1) # t = 1 = idc.o_reg,代表寄存器
# 遍历段
def iter_seg():
addr = idc.get_first_seg()
while addr != idc.BADADDR:
print('seg', f'{hex(addr)}-{hex(idc.get_segm_end(addr))}', idc.get_segm_name(addr))
addr = idc.get_next_seg(addr)
# 或者idautils.Segments()
# 获取段
text_seg = ida_segment.get_segm_by_name(".text")
# 有时候dump出来的so没有修复text段
start = text_seg.start_ea if text_seg else idc.get_inf_attr(idc.INF_MIN_EA)
end = text_seg.end_ea if text_seg else idc.get_inf_attr(idc.INF_MAX_EA)
def get_top_ref(top=5):
"""
获取各个函数引用次数
:param top: 引用次数前n个
:return: 返回排序后的(ea, count) 列表
"""
funcs = list(idautils.Functions())
m = {}
for ea in funcs:
for xref in idautils.XrefsTo(ea):
m.setdefault(ea, 0)
m[ea] += 1
sm = sorted(m.items(), key=lambda x: x[1], reverse=True)
return sm[:top]
def get_called_func(func_ea):
"""
获取函数里调用的其他函数
:param func_ea: 函数地址
:return: 调用的函数地址-名称 dict
"""
called_funcs = {}
ea = func_ea
while ea != idc.find_func_end(func_ea):
try:
if idc.get_operand_type(ea, 0) == idc.o_near:
called_funcs[ea] = idc.get_func_name(idc.get_operand_value(ea, 0))
ea = idc.next_head(ea)
except Exception as e:
print(ea, e)
return called_funcs
def get_all_switch():
"""
遍历所有的jump table
:return: 返回dict,key是table地址,value是(case数量, 各case长度)
"""
text_seg = idaapi.get_segm_by_name('.text')
jump_table = dict()
# iterate through all items within the segment
for head_ea in idautils.Heads(text_seg.start_ea, text_seg.end_ea):
if idc.is_code(ida_bytes.get_flags(head_ea)):
switch_info = idaapi.get_switch_info(head_ea)
if switch_info and switch_info.jumps != 0:
loc = switch_info.jumps
element_num = switch_info.get_jtable_size()
element_size = switch_info.get_jtable_element_size()
jump_table[loc] = (element_num, element_size)
# for num in range(0, element_num):
# table_entry = loc + num * element_size
# print(hex(loc), hex(table_entry), element_size)
return jump_table
def find_svc():
"""ARM64 svc code: 01 00 00 D4"""
text_seg = ida_segment.get_segm_by_name(".text")
start = text_seg.start_ea if text_seg else idc.get_inf_attr(idc.INF_MIN_EA)
end = text_seg.end_ea if text_seg else idc.get_inf_attr(idc.INF_MAX_EA)
ret = []
for ea in range(start, end, 4):
if ida_bytes.get_dword(ea) == 0xd4000001:
for i in range(0, 0x40, 0x4):
if idaapi.is_func(idaapi.get_flags(ea)):
break
if idc.get_operand_type(ea - i, 0) == idc.o_reg and idc.get_operand_value(ea - i, 0) == 0x89:
if idc.get_operand_type(ea - i, 1) == idc.o_imm: # MOV X8, 0x1;
svc_num = idc.get_operand_value(ea - i, 1)
print(hex(ea), 'syscall', f'num_{svc_num}')
ret.append(ea)
break
if idc.get_operand_type(ea - i, 1) == idc.o_reg: # MOV X8, X0
print('[find_svc]', hex(ea), 'syscall', f'reg_x{idc.get_operand_value(ea - i, 1) - 0x81}')
ret.append(ea)
break
return ret
ida结合emu
emu基本基于unicorn实现,可以直接python代码手搓模拟器,也可以用
用途:
- 修复简单混淆,例如简单的br跳转,lr跳转。
- 主动调用字符串解密函数,还原明文。
例子:修复块内计算的BR寄存器跳转,仅限于简单混淆
g_eh = flare_emu.EmuHelper()
def arm642bin(arm_code, addr=0):
ks = keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN)
asm = ks.asm(arm_code, addr=addr)
bs = asm[0]
return bs[0] | bs[1] << 8 | bs[2] << 16 | bs[3] << 24
def fix_br(ea):
idc.get_manual_insn(ea)
match = re.match(r'BR\s+(X\d+)', idc.GetDisasm(ea))
if match:
reg = match.group(1)
else:
return
g_eh.emulateRange(startAddr=idaapi.get_func(ea).start_ea, endAddr=ea, count=1000)
ret = g_eh.getRegVal(reg)
if ret != 0:
print(reg, '=', hex(ret))
idc.patch_dword(ea, arm642bin(arm_code=f"B {hex(ret)}", addr=ea)) # patch br
def patch_all_br():
for ea in list(idautils.Functions()):
end = idaapi.get_func(ea).end_ea - 4
if re.match(r'BR\s+X(\d+)', idc.GetDisasm(end)) and 0x20 < end - ea < 0x200 and \
ida_bytes.is_data(ida_bytes.get_full_flags(end + 4)):
print(hex(end), idc.GetDisasm(end))
try:
fix_br(end)
except Exception as e:
print(hex(ea), 'error', e)