def run(self, arg): # 查找需要的函数 ea, ed = getSegAddr() search_result = [] for func in idautils.Functions(ea, ed): try: functionName = str(idaapi.ida_funcs.get_func_name(func)) if len(list(idautils.FuncItems(func))) > 10: # 如果是thumb模式,地址+1 arm_or_thumb = idc.get_sreg(func, "T") if arm_or_thumb: func += 1 search_result.append(hex(func)) except: pass so_path, so_name = getSoPathAndName() search_result = [ f"-a '{so_name}!{offset}'" for offset in search_result ] search_result = " ".join(search_result) script_name = so_name.split(".")[0] + "_" + str(int( time.time())) + ".txt" save_path = os.path.join(so_path, script_name) with open(save_path, "w", encoding="utf-8") as F: F.write(search_result) print("使用方法如下:") print(f"frida-trace -UF -O {save_path}")
def find_scatter_table(): scatter_load_bytes = { "__scatterload": [ "0A A0 90 E8 00 0C 82 44", "2C 00 8F E2 00 0C 90 E8 00 A0 8A E0 00 B0 8B E0", # For 5G ], } tables = {} for name, prefixes in scatter_load_bytes.items(): for prefix in prefixes: addrs = create_func_by_prefix(name, prefix, force=True) for addr in addrs: if addr == idc.BADADDR: continue offset_addr = idc.get_operand_value(addr, 1) if offset_addr == -1: old_flag = idc.get_sreg(addr, "T") idc.split_sreg_range(addr, "T", not old_flag, idc.SR_user) offset_addr = idc.get_operand_value(addr, 1) offset = ida_bytes.get_dword(offset_addr) offset2 = ida_bytes.get_dword(offset_addr + 4) start = (offset + offset_addr) & 0xFFFFFFFF end = (offset2 + offset_addr) & 0xFFFFFFFF if not idc.is_loaded(start): continue tables[start] = end print("__scatter_table: 0x%x -> 0x%x" % (start, end)) func_name = set_entry_name(start, "__scatter_table") return tables
def run(self, arg): # 查找需要的函数 ea, ed = getSegAddr() search_result = [] for func in idautils.Functions(ea, ed): try: functionName = str(idaapi.ida_funcs.get_func_name(func)) demangled = idc.demangle_name(functionName, idc.get_inf_attr( idc.INF_SHORT_DN)) functionName = demangled if demangled else functionName if len(list(idautils.FuncItems(func))) > 10: # 如果是thumb模式,地址+1 arm_or_thumb = idc.get_sreg(func, "T") if arm_or_thumb: func += 1 search_result.append([hex(func), functionName]) except: pass so_path, so_name = getSoPathAndName() search_result = [f"{so_name}!{a}!{b}" for a, b in search_result] search_result = "\n".join(search_result) save_path = os.path.join(so_path, so_name.split(".")[0] + ".txt") with open(save_path, "w", encoding="utf-8")as F: F.write(search_result) print("使用方法如下:") print(f"frida-trace -UF -z {save_path}")
def _is_thumb_ea(self, ea): if idaapi.ph.id == idaapi.PLFM_ARM and not idaapi.ph.flag & idaapi.PR_USE64: if idaapi.IDA_SDK_VERSION >= 700: t = idc.get_sreg(ea, "T") # get T flag else: t = get_segreg(ea, 20) # get T flag return t is not idc.BADSEL and t is not 0 else: return False
def _is_thumb_ea(self, ea): if idaapi.ph.id == idaapi.PLFM_ARM and not idaapi.ph.flag & idaapi.PR_USE64: if idaapi.IDA_SDK_VERSION >= 700: t = idc.get_sreg(ea, "T") # get T flag else: t = get_segreg(ea, 20) # get T flag return t is not idc.BADSEL and t is not 0 else: return False
def codeType(self, ea): """Query IDA for the code type at the given address. Args: ea (int): effective code address Return Value: The current code type at the given address """ return idc.get_sreg(ea, "mips16")
def thumb_or_arm(offset): offset = int(offset, 16) arm_or_thumb = idc.get_sreg(offset, "T") if arm_or_thumb: offset += 1 return offset
def is_thumb(ea): return idc.get_sreg(ea, "T") == 1
def isThumbMode(self, addr): return idc.get_sreg(addr, "T") == 1
def analyze_func_ptr(start_ea, end_ea): global FUNC_BY_PTR, FUNC_BY_PTR_TIME if "FUNC_BY_PTR" not in globals() or len(FUNC_BY_PTR) == 0: FUNC_BY_PTR = set() ea = start_ea func_cnt = 0 name_cnt = 0 start_time = time.time() while ea != idc.BADADDR and ea <= end_ea: status, ea = is_assigned(ea) if status: continue # now check function pointer func_ptr = ida_bytes.get_dword(ea) # TODO: skip other segments that are not code. # for those already assigned functions, we need to check the segment range. if not (start_ea <= func_ptr < end_ea): ea = next_addr_aligned(ea, 4) continue # we only target thumb function to reduce false positives if func_ptr & 1 == 0: ea = next_addr_aligned(ea, 4) continue func_ptr = func_ptr - 1 func_start = idc.get_func_attr(func_ptr, idc.FUNCATTR_START) if func_start != idc.BADADDR and func_start != func_ptr: # this is not a proper function pointer ea = next_addr_aligned(ea, 4) continue # new thumb function has been found! if func_start == idc.BADADDR: old_flag = idc.get_sreg(func_ptr, "T") idc.split_sreg_range(func_ptr, "T", 1, idc.SR_user) status = idc.add_func(func_ptr) if not status: # IDA automatically make code, and this remains even # though add_func fails. ida_bytes.del_items(func_ptr, ida_bytes.DELIT_EXPAND) idc.split_sreg_range(func_ptr, "T", old_flag, idc.SR_user) ea = next_addr_aligned(ea, 4) continue func_cnt += 1 FUNC_BY_PTR.add(ea) if func_cnt % 10000 == 0: print("%x: %d functions has been found. (%0.3f secs)" % (ea, func_cnt, time.time() - start_time)) # If we find a function, we try to assign a name. The name may be # derived by C++ structure. if analyze_funcname(ea, func_ptr): name_cnt += 1 func_name = idc.get_func_name(func_ptr) if name_cnt % 10000 == 0: print("%x: %d names has been found. (%0.3f secs)" % (ea, name_cnt, time.time() - start_time)) # print("%x: %x => %s" % (ea, func_ptr, func_name)) ea = next_addr_aligned(ea, 4) FUNC_BY_PTR_TIME = time.time() - start_time print("Found %d functions, renamed %d functions (%0.3f secs)" % (len(FUNC_BY_PTR), name_cnt, FUNC_BY_PTR_TIME))
def analyze_linear_sweep(start_ea, end_ea=idc.BADADDR): global FUNC_BY_LS, FUNC_BY_LS_TIME if "FUNC_BY_LS" not in globals() or len(FUNC_BY_LS) == 0: FUNC_BY_LS = set() cand_cnt = 0 func_cnt = 0 ea = start_ea start_time = time.time() while ea < end_ea and ea != idc.BADADDR: ea, mode = find_next_func_cand(ea, end_ea) if ea == idc.BADADDR: break cand_cnt += 1 if cand_cnt % 10000 == 0: print("%x: %d/%d function has been found (%d secs)" % (ea, func_cnt, cand_cnt, time.time() - start_time)) # set IDA segment register to specify ARM mode old_flag = idc.get_sreg(ea, "T") if mode == THUMB: idc.split_sreg_range(ea, "T", 1, idc.SR_user) elif mode == ARM: idc.split_sreg_range(ea, "T", 0, idc.SR_user) else: print("Unknown mode") raise NotImplemented # add_func ignores the existing function, but existing function is # already filtered when finding the candidate status = idc.add_func(ea) if status: func_cnt += 1 FUNC_BY_LS.add(ea) # Wait IDA's auto analysis ida_auto.auto_wait() # even though add_func succeed, it may not be correct. # TODO: how to check the correctness? we may check the function end? func_end = idc.get_func_attr(ea, idc.FUNCATTR_END) if func_end > ea: ea = func_end else: # sometimes, ida returns wrong addr ea = next_addr_aligned(ea) else: if idc.get_func_attr(ea, idc.FUNCATTR_START) == idc.BADADDR: # IDA automatically make code, and this remains even though # add_func fails. ida_bytes.del_items(ea, ida_bytes.DELIT_EXPAND) # reset IDA segment register to previous ARM mode idc.split_sreg_range(ea, "T", old_flag, idc.SR_user) # Wait IDA's auto analysis ida_auto.auto_wait() ea = next_addr_aligned(ea) # linear sweep may choose wrong prologs. We merge the prologs of two # adjacent functions. if func_cnt > 0: fix_func_prolog(start_ea, end_ea) FUNC_BY_LS_TIME = time.time() - start_time print("Found %d/%d functions. (%d sec)" % (len(FUNC_BY_LS), cand_cnt, FUNC_BY_LS_TIME))
def _is_thumb_ea(self, ea): if idaapi.ph.id == idaapi.PLFM_ARM and not idaapi.ph.flag & idaapi.PR_USE64: t = idc.get_sreg(ea, "T") # get T flag return t is not idc.BADSEL and t is not 0 else: return False