def main(): # Get current ea ea = ida_kernwin.get_screen_ea() # Get segment class seg = ida_segment.getseg(ea) # Loop from segment start to end func_ea = seg.start_ea # Get a function at the start of the segment (if any) func = ida_funcs.get_func(func_ea) if func is None: # No function there, try to get the next one func = ida_funcs.get_next_func(func_ea) seg_end = seg.end_ea while func is not None and func.start_ea < seg_end: funcea = func.start_ea print("Function %s at 0x%x" % (ida_funcs.get_func_name(funcea), funcea)) ref = ida_xref.get_first_cref_to(funcea) while ref != ida_idaapi.BADADDR: print(" called from %s(0x%x)" % (ida_funcs.get_func_name(ref), ref)) ref = ida_xref.get_next_cref_to(funcea, ref) func = ida_funcs.get_next_func(funcea)
def getFuncRanges(): funcs_addr = [] start = 0 next_func = ida_funcs.get_next_func(start) while next_func: size = next_func.size() if (size) < MIN_FUNC_SIZE: next_func = ida_funcs.get_next_func(next_func.start_ea) continue elif size > MAX_FUNC_SIZE: size = MAX_FUNC_SIZE yield (next_func.start_ea, size) funcs_addr.append(next_func.start_ea - start) next_func = ida_funcs.get_next_func(next_func.start_ea)
def RenameMod(orig, new): i = ida_funcs.get_next_func(0) while (i != ida_idaapi.BADADDR): n = ida_funcs.get_func_name(i) if n.startswith(orig+"_"): RenameFuncWithNewMod(i,new) i = NextFunction(i)
def Functions(start=None, end=None): """ Get a list of functions @param start: start address (default: inf.min_ea) @param end: end address (default: inf.max_ea) @return: list of heads between start and end @note: The last function that starts before 'end' is included even if it extends beyond 'end'. Any function that has its chunks scattered in multiple segments will be reported multiple times, once in each segment as they are listed. """ if not start: start = ida_ida.cvar.inf.min_ea if not end: end = ida_ida.cvar.inf.max_ea # find first function head chunk in the range chunk = ida_funcs.get_fchunk(start) if not chunk: chunk = ida_funcs.get_next_fchunk(start) while chunk and chunk.start_ea < end and (chunk.flags & ida_funcs.FUNC_TAIL) != 0: chunk = ida_funcs.get_next_fchunk(chunk.start_ea) func = chunk while func and func.start_ea < end: startea = func.start_ea yield startea func = ida_funcs.get_next_func(startea)
def _get_function_bounds(func, seg_ref): """Get the bounds of the function containing `ea`. We want to discover jump table targets that are missed by IDA, and it's possible that they aren't marked as being part of the current function, and perhaps are after the assumed range of the current function. Ideally they will fall before the beginning of the next function, though. We need to be pretty careful with the case that one function tail-calls another. IDA will sometimes treat the end of the tail-called function (e.g. a thunk) as if it is the end of the caller. For this reason, we start with loose bounds using the prev/next functions, then try to narrow with the bounds of the function containing `ea`. NOTE(pag): This does not handle function chunks. """ ea = func.start_ea seg = _find_segment_containing_ea(ea, seg_ref) if not seg: return ea, ea seg_start, seg_end = seg.start_ea, seg.end_ea min_ea = seg_start max_ea = seg_end if not _is_executable_seg(seg): return ea, ea # Get an upper bound using the next function. has_upper = False next_func = ida_funcs.get_next_func(ea) if next_func: next_func_seg = _find_segment_containing_ea(next_func.start_ea, seg_ref) if next_func_seg and _is_executable_seg(next_func_seg): max_ea = min(next_func.start_ea, max_ea) has_upper = True # Get a lower bound using the previous function. has_lower = False prev_func = ida_funcs.get_prev_func(ea) if prev_func: prev_func_seg = _find_segment_containing_ea(prev_func.start_ea, seg_ref) if prev_func_seg and _is_executable_seg(prev_func_seg): min_ea = max(prev_func.end_ea, min_ea) has_lower = True # Try to tighten the bounds using the function containing `ea`. if not has_lower: min_ea = max(min_ea, func.start_ea) if not has_upper: max_ea = min(max_ea, func.end_ea) return min_ea, max_ea
def fix_func_prolog(ea, end_ea=idc.BADADDR): global FUNC_BY_LS func_cnt = 0 func = ida_funcs.get_fchunk(ea) if func is None: func = ida_funcs.get_next_func(ea) ea = func.start_ea while func is not None and ea < end_ea: # if current function is small enough and there exists a function right # next to current function if (func.size() <= 8 and idc.get_func_attr( func.end_ea, idc.FUNCATTR_START) != idc.BADADDR): # If the next function can be connected, there must be a basic block reference. # xref.type == 21 means 'fl_F', which is an ordinary flow. if all( (func.start_ea <= xref.frm < func.end_ea) and xref.type == 21 for xref in XrefsTo(func.end_ea)): if func_cnt > 0 and func_cnt % 1000 == 0: print("%x <- %x: prolog merging (%d)." % (func.start_ea, func.end_ea, func_cnt)) ida_bytes.del_items(func.end_ea, ida_bytes.DELIT_EXPAND) ida_bytes.del_items(func.start_ea, ida_bytes.DELIT_EXPAND) ida_auto.auto_wait() status = idc.add_func(func.start_ea) if not status: print("Error merging 0x%x <- 0x%x" % (func.start_ea, func.end_ea)) else: func_cnt += 1 FUNC_BY_LS.discard(func.end_ea) ida_auto.auto_wait() func = ida_funcs.get_next_func(ea) if func: ea = func.start_ea print("Fixed %d functions" % func_cnt)
def __process_functions(self): functions = list() start = ida_ida.cvar.inf.min_ea end = ida_ida.cvar.inf.max_ea # find first function head chunk in the range chunk = ida_funcs.get_fchunk(start) if not chunk: chunk = ida_funcs.get_next_fchunk(start) while chunk and chunk.start_ea < end and (chunk.flags & ida_funcs.FUNC_TAIL) != 0: chunk = ida_funcs.get_next_fchunk(chunk.start_ea) func = chunk while func and func.start_ea < end: start_ea = func.start_ea func_flags = ida_bytes.get_full_flags(start_ea) func_name = ida_funcs.get_func_name(start_ea) func_name_demangled = ida_name.get_demangled_name( start_ea, 0xFFFF, 0, 0) func_autonamed = func_flags & ida_bytes.FF_LABL != 0 func_public = ida_name.is_public_name(start_ea) function = { 'start_rva': start_ea - self._base, 'name': func_name, 'name_demangled': func_name_demangled, 'is_public': func_public, 'is_autonamed': func_autonamed } # PE32/PE32+ only support binaries up to 2GB if function['start_rva'] >= 2**32: print('RVA out of range for function: ' + function['name'], file=sys.stderr) self.__process_function_typeinfo(function, func) function['labels'] = self.__process_function_labels(func) functions.append(function) func = ida_funcs.get_next_func(start_ea) return functions
def processFunctions(): functions = list() start = ida_ida.cvar.inf.min_ea end = ida_ida.cvar.inf.max_ea # find first function head chunk in the range chunk = ida_funcs.get_fchunk(start) if not chunk: chunk = ida_funcs.get_next_fchunk(start) while chunk and chunk.start_ea < end and (chunk.flags & ida_funcs.FUNC_TAIL) != 0: chunk = ida_funcs.get_next_fchunk(chunk.start_ea) func = chunk while func and func.start_ea < end: start_ea = func.start_ea flags = ida_bytes.get_full_flags(start_ea) function = { 'start_ea': start_ea, 'name': ida_funcs.get_func_name(start_ea), 'is_public': ida_name.is_public_name(start_ea), 'is_autonamed': flags & ida_bytes.FF_LABL != 0 } processFunctionTypeinfo(function) functions.append(function) func = ida_funcs.get_next_func(start_ea) return functions
def ProgramAddrRange() : return ida_funcs.get_prev_func(ida_idaapi.BADADDR) - ida_funcs.get_next_func(0)
def reanalyze_range_end(ea): return ida_funcs.get_next_func(ea).start_ea - 1
"jns", "jnz", "jo", "jp", "js", "jz" ] jump_pairs = [("ja", "jbe"), ("jb", "jnb"), ("jg", "jle"), ("jl", "jge"), ("jo", "jno"), ("jp", "jnp"), ("js", "jns"), ("jz", "jnz")] movs = ["mov", "xchg"] ida_api_is_new = False try: import ida_auto ida_api_is_new = True except ImportError: pass user_pos = ida_kernwin.get_screen_ea() after_function_before_user_pos = ida_funcs.get_prev_func(user_pos).end_ea + 1 before_function_after_user_pos = ida_funcs.get_next_func(user_pos).start_ea - 1 hopefully_a_sane_start_of_function = (after_function_before_user_pos & ~0x0F) + 0x10 make_fun_pos = None if ida_bytes.is_code(ida_bytes.get_flags(hopefully_a_sane_start_of_function)): make_fun_pos = hopefully_a_sane_start_of_function def re_analyze_relevant_range(): ida_bytes.del_items( after_function_before_user_pos, 0, before_function_after_user_pos - after_function_before_user_pos) if not make_fun_pos is None: assume_code_at(make_fun_pos) else: run_autoanalysis(after_function_before_user_pos,
def save_x(unique_name=None, start=None, size=None): ea = ida_kernwin.get_screen_ea() # signature if not unique_name: if not start: seg = ida_segment.getseg(ea) start = seg.start_ea sig_bytes = ida_bytes.get_bytes(start, SIGNATURE_SIZE) sig_hash = hashlib.md5(sig_bytes).hexdigest() unique_name = sig_hash if not start or not size: seg = ida_segment.getseg(ea) start = seg.start_ea size = seg.size() # (start_addr, end_addr, names, comms) saved_data = {} if MD5_hash_data_file and os.path.isfile(MD5_hash_data_file): with open(MD5_hash_data_file, "rb") as ifile: received_data = pickle.loads(ifile.read()) if received_data: saved_data = received_data # save names (func_names, labels, etc) # (addr, name, is_code) names_addr_name = [] names = idautils.Names() for addr, name in names: if start <= addr <= start + size: flags = ida_bytes.get_flags(addr) names_addr_name.append( (addr - start, name, ida_bytes.is_code(flags))) # save comments comms_addr_type_comm = [] # (addr, TYPE, comment) # type 0:comment 1:rpt_comment end = start + size for i in range(start, end + 1): if ida_bytes.get_cmt(i, 0): # 0 Comment comms_addr_type_comm.append((i - start, 0, ida_bytes.get_cmt(i, 0))) if ida_bytes.get_cmt(i, 1): # 1 RptCmt comms_addr_type_comm.append((i - start, 1, ida_bytes.get_cmt(i, 1))) # breakpoints bpts_addr_size_type = [] bpt = ida_dbg.bpt_t() global remove_on_exit_bpts for i in range(start, end + 1): if ida_dbg.get_bpt(i, bpt): bpts_addr_size_type.append((i - start, bpt.size, bpt.type)) remove_on_exit_bpts.append(i) # functions funcs_addr = [] flag = ida_bytes.get_flags(start) if ida_bytes.is_func(flag): funcs_addr.append(0) # start addr next_func = ida_funcs.get_next_func(start) while next_func: funcs_addr.append(next_func.start_ea - start) next_func = ida_funcs.get_next_func(next_func.start_ea) # SAVE saved_data[unique_name] = (start, start + end, names_addr_name, comms_addr_type_comm, bpts_addr_size_type, funcs_addr) if MD5_hash_data_file: with open(MD5_hash_data_file, "wb") as ifile: serial_data = pickle.dumps(saved_data) ifile.write(serial_data) print("dumpDyn::save:\n\ Name: {}\n\ Start address: {}".format(unique_name, hex(start)))