def make_array(ea, size): if ea != idc.BADADDR and ea != 0: flags = idc.get_full_flags(ea) if not idc.isByte(flags) or idc.get_item_size(ea) != 1: idc.del_items(ea, idc.DOUNK_SIMPLE, 1) idc.MakeByte(ea) idc.MakeArray(ea, size)
def crefs_from(ea, only_one=False, check_fixup=True): flags = idc.get_full_flags(ea) if not idc.is_code(flags): return fixup_ea = idc.BADADDR seen = False has_one = only_one if check_fixup: fixup_ea = idc.get_fixup_target_off(ea) if not is_invalid_ea(fixup_ea) and is_code(fixup_ea): seen = only_one has_one = True yield fixup_ea if has_one and _stop_looking_for_xrefs(ea): return for target_ea in _xref_generator(ea, idaapi.get_first_cref_from, idaapi.get_next_cref_from): if target_ea != fixup_ea and not is_invalid_ea(target_ea): seen = only_one yield target_ea if seen: return if not seen and ea in _CREFS_FROM: for target_ea in _CREFS_FROM[ea]: seen = only_one yield target_ea if seen: return
def make_head(ea): flags = idc.get_full_flags(ea) if not idc.is_head(flags): # idc.SetFlags(ea, flags | idc.FF_DATA) idc.create_data(ea, idc.FF_BYTE, 1, idc.BADADDR) idaapi.auto_wait() return is_head(ea) return True
def read_bytes_slowly(start, end): bytestr = [] for i in xrange(start, end): if idc.has_value(idc.get_full_flags(i)): bt = idc.get_wide_byte(i) bytestr.append(chr(bt)) else: bytestr.append("\x00") return "".join(bytestr)
def make_xref(from_ea, to_ea, data_type, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.get_full_flags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format( from_ea, to_ea)) return False make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. # or in the middle of structure. Return False in such case # # NOTE(artem): Commenting out since this breaks recovery of C++ applications # with IDA7. The failure occurs when processign references in .init_array # when the below code is enabled, those references are not treated as # references because make_head fails. # #if not make_head(from_ea + xref_size): # return False ida_bytes.del_items(from_ea, idc.DELIT_EXPAND, xref_size) if data_type == idc.FF_QWORD: data_size = 8 elif data_type == idc.FF_DWORD: data_size = 4 else: raise ValueError("Invalid data type") idc.create_data(from_ea, data_type, data_size, idaapi.BADADDR) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER | idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format( from_ea, to_ea)) return True
def is_internal_code(ea): if is_invalid_ea(ea): return False if is_external_segment(ea): return False if is_code(ea): return True # find stray 0x90 (NOP) bytes in .text that IDA # thinks are data items. flags = idc.get_full_flags(ea) if idaapi.is_align(flags): if not try_mark_as_code(ea): return False return True return False
def make_xref(from_ea, to_ea, data_type, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.get_full_flags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format(from_ea, to_ea)) return False make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. # or in the middle of structure. Return False in such case # # NOTE(artem): Commenting out since this breaks recovery of C++ applications # with IDA7. The failure occurs when processign references in .init_array # when the below code is enabled, those references are not treated as # references because make_head fails. # #if not make_head(from_ea + xref_size): # return False ida_bytes.del_items(from_ea, idc.DELIT_EXPAND, xref_size) if data_type == idc.FF_QWORD: data_size = 8 elif data_type == idc.FF_DWORD: data_size = 4 else: raise ValueError("Invalid data type") idc.create_data(from_ea, data_type, data_size, idaapi.BADADDR) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER|idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format(from_ea, to_ea)) return True
def get_ea_from_highlight(): view = idaapi.get_current_viewer() thing = ida_kernwin.get_highlight(view) if thing and thing[1]: # we have a highligh, is it a valid name ? ea = idc.get_name_ea_simple(thing[0]) if ea != idaapi.BADADDR: return ea else: # Try to get full highlight name place = idaapi.get_custom_viewer_place(view, False) if place and len(place) == 3: # (plate_t, x, y) ea = place[0].toea() far_code_refs = [xref.to for xref in idautils.XrefsFrom(ea, ida_xref.XREF_FAR) \ if idc.is_code(idc.get_full_flags(xref.to))] if far_code_refs: return far_code_refs[0] # Reach now, we do not have any valid name, return current screen ea return idc.get_screen_ea()
def check_vtable(start, end=None): # We recognize a vtable by looking for an array of at least 2 pointers to code followed by a # NULL. # If no end was specified, go until the end of the segment. if end is None: end = idc.get_segm_end(start) # Check each address in the table. Stop once we've found something other than a pointer to # code. ended_with_zero = False ea = start while ea < end: method = idc.get_qword(ea) if method == 0: ended_with_zero = True break if not idc.is_code(idc.get_full_flags(method)): break ea += 8 # Compute the length. length = (ea - start) / 8 possible_vtable = ended_with_zero and length >= 2 return possible_vtable, length
def make_xref(from_ea, to_ea, data_type, xref_size): """Force the data at `from_ea` to reference the data at `to_ea`.""" if not idc.get_full_flags(to_ea) or is_invalid_ea(to_ea): DEBUG(" Not making reference (A) from {:x} to {:x}".format( from_ea, to_ea)) return False make_head(from_ea) if is_code(from_ea): _CREFS_FROM[from_ea].add(to_ea) _CREFS_TO[to_ea].add(from_ea) else: _DREFS_FROM[from_ea].add(to_ea) _DREFS_TO[to_ea].add(from_ea) # If we can't make a head, then it probably means that we're at the # end of the binary, e.g. the last thing in the `.extern` segment. # or in the middle of structure. Return False in such case if not make_head(from_ea + xref_size): return False ida_bytes.del_items(from_ea, idc.DELIT_EXPAND, xref_size) if data_type == idc.FF_QWORD: data_size = 8 elif data_type == idc.FF_DWORD: data_size = 4 else: raise ValueError("Invalid data type") idc.create_data(from_ea, data_type, data_size, idaapi.BADADDR) if not is_code_by_flags(from_ea): idc.add_dref(from_ea, to_ea, idc.XREF_USER | idc.dr_O) else: DEBUG(" Not making reference (B) from {:x} to {:x}".format( from_ea, to_ea)) return True
def get_symbol_name(from_ea, ea=None, allow_dummy=False): if ea is None: ea = from_ea global _FORCED_NAMES if ea in _FORCED_NAMES: return _FORCED_NAMES[ea] flags = idc.get_full_flags(ea) if not allow_dummy and idaapi.has_dummy_name(flags): return "" name = "" try: name = name or idc.get_name(ea, 0) #calc_gtn_flags(from_ea, ea)) except: pass try: name = name or idc.get_func_name(ea) except: pass return name
def ida_make_functions(location, require_term=True): """ Description: Attempts to create functions based on the assumption that there should be continuous contiguous functions defined since the previous function or align. Stops creating functions once a function containing <location> is created or the next created function would be past <location>. Only identifies potential start EAs and lets IDA find the ends. Input: location - The EA at which IDA should attempt to make a function. require_term - When True, requires the last instruction in all defined functions to be retn or jmp Output: True if it made a function or a function was already present, False otherwise. """ sanity = sanity_checks(location) if sanity is None: # There was already a function return True elif sanity is False: # There was something preventing function creation return False target_location = location function_start = location ea = location while not (idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea))): function_start = ea ea = idc.prev_head(ea) function_start = trim_func(function_start, idc.next_head) if try_make_function(function_start, require_term=require_term): if not idaapi.get_func(target_location): return ida_make_functions(target_location, require_term) else: return True else: return False
def get_value_type(ea): addr_type = T_VALUE if not idaapi.is_loaded(ea): return addr_type segm_name = idc.get_segm_name(ea) segm = idaapi.getseg(ea) flags = idc.get_full_flags(ea) is_code = idc.is_code(flags) if "stack" in segm_name.lower() or \ (dbg.stack_segm and dbg.stack_segm.start_ea == segm.start_ea): addr_type = T_STACK elif "heap" in segm_name.lower(): addr_type = T_HEAP elif segm is not None: if not is_code and segm.perm & idaapi.SEGPERM_READ and \ segm.perm & idaapi.SEGPERM_WRITE and \ segm.perm & idaapi.SEGPERM_EXEC: addr_type = T_RWX elif is_code or \ (segm.perm & idaapi.SEGPERM_READ and segm.perm & idaapi.SEGPERM_EXEC): addr_type = T_CODE elif segm.perm & idaapi.SEGPERM_READ and \ segm.perm & idaapi.SEGPERM_WRITE: addr_type = T_DATA elif segm.perm & idaapi.SEGPERM_READ: addr_type = T_RODATA return addr_type
def is_code_by_flags(ea): if not is_code(ea): return False flags = idc.get_full_flags(ea) return idc.is_code(flags)
def is_user_name(ea): f = idc.get_full_flags(ea) return idc.hasUserName(f)
def is_unknown(va): return ida_bytes.is_unknown(idc.get_full_flags(va))
def is_head(va): return ida_bytes.is_head(idc.get_full_flags(va))
# # extern:0000000000023558 ; Segment type: Externs # extern:0000000000023558 ; extern # extern:0000000000023558 ; const __int32_t **_ctype_toupper_loc(void) # extern:0000000000023558 extrn __ctype_toupper_loc:near # # Python>idautils.DecodeInstruction(0x23558).get_canon_mnem() # 'retn' if idc.get_segm_attr(seg, SEGATTR_TYPE) == idc.SEG_XTRN: #print("skipping segment ", idc.get_segm_name(seg)) continue for fn in idautils.Functions(seg, idc.get_segm_end(seg)): #func_name = idc.get_name(fn) for (chunk_start, chunk_end) in idautils.Chunks(fn): for head in idautils.Heads(chunk_start, chunk_end): flags = idc.get_full_flags(head) if not is_code(flags): # Skip non-code heads. These may appear in functions containing # inlined jump tables or alignment directives. continue #inst = idc.GetDisasm(head) inst_addr = head insts[inst_addr] = True for inst_addr in insts: inst_addrs.append(inst_addr) inst_addrs.sort() inst_addrs_json = "[" for inst_addr in inst_addrs: inst_addrs_json += "\n\t\"0x%08X\"," % (inst_addr)
def is_head(ea): return idc.is_head(idc.get_full_flags(ea))
def cmd_get_flags(self, a): return "0x{:08X}".format(idc.get_full_flags(int(a, 0)))
def update_vtable_struct( functions_ea, vtable_struct, class_name, this_type=None, get_next_func_callback=get_vtable_line, vtable_head=None, ignore_list=None, add_dummy_member=False, pure_virtual_name=None, parent_name=None, add_func_this=True, force_rename_vtable_head=False, # rename vtable head even if it is already named by IDA # if it's not named, then it will be renamed anyway ): # pylint: disable=too-many-arguments,too-many-locals,too-many-branches # TODO: refactor if this_type is None: this_type = utils.get_typeinf_ptr(class_name) if not add_func_this: this_type = None func_ea, next_func = get_next_func_callback( functions_ea, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name, ) dummy_i = 1 offset = 0 while func_ea is not None: new_func_name, _ = update_func_name_with_class(func_ea, class_name) func_ptr = None if ida_hexrays.init_hexrays_plugin(): fix_userpurge(func_ea, idc.TINFO_DEFINITE) update_func_this(func_ea, this_type, idc.TINFO_DEFINITE) func_ptr = utils.get_typeinf_ptr(utils.get_func_tinfo(func_ea)) else: func_ptr = make_funcptr_pt(func_ea, this_type) # TODO: maybe try to get or guess type? if add_dummy_member: utils.add_to_struct(vtable_struct, "dummy_%d" % dummy_i, func_ptr) dummy_i += 1 offset += utils.WORD_LEN ptr_member = utils.add_to_struct( vtable_struct, new_func_name, func_ptr, offset, overwrite=True, is_offs=True ) if ptr_member is None: log.error( "Couldn't add %s(%s) to vtable struct 0x%X at offset 0x%X", new_func_name, str(func_ptr), vtable_struct.id, offset, ) offset += utils.WORD_LEN if not ida_xref.add_dref(ptr_member.id, func_ea, ida_xref.XREF_USER | ida_xref.dr_I): log.warn( "Couldn't create xref between member %s and func %s", ida_struct.get_member_name(ptr_member.id), idc.get_name(func_ea), ) func_ea, next_func = get_next_func_callback( next_func, ignore_list=ignore_list, pure_virtual_name=pure_virtual_name, ) vtable_size = ida_struct.get_struc_size(vtable_struct) if vtable_head is None: vtable_head = functions_ea # ida_bytes.del_items(vtable_head, ida_bytes.DELIT_SIMPLE, vtable_size) ida_bytes.create_struct(vtable_head, vtable_size, vtable_struct.id) if not idc.hasUserName(idc.get_full_flags(vtable_head)) or force_rename_vtable_head: if parent_name is None and this_type: parent = utils.deref_struct_from_tinfo(this_type) parent_name = ida_struct.get_struc_name(parent.id) if parent_name == class_name: parent_name = None idc.set_name( vtable_head, get_vtable_instance_name(class_name, parent_name), ida_name.SN_CHECK | ida_name.SN_FORCE, )
def is_offset(self, ea): return idc.is_off0(idc.get_full_flags(ea))
def make_func_sigs(config): logger = logging.getLogger("idb2pat:make_func_sigs") sigs = [] if config.mode == USER_SELECT_FUNCTION: f = idaapi.choose_func("Choose Function:", idc.BADADDR) if f is None: logger.error("No function selected") return [] idc.jumpto(f.start_ea) if not idaapi.has_any_name(idc.get_full_flags(f.start_ea)): logger.error("Function doesn't have a name") return [] try: sigs.append(make_func_sig(config, f)) except Exception as e: logger.exception(e) logger.error("Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_func_name(f.start_ea) or "") elif config.mode == NON_AUTO_FUNCTIONS: for f in get_functions(): # HTC - remove check FUNC_LIB flag to include library functions if idaapi.has_name(idc.get_full_flags(f.start_ea)): # and f.flags & idc.FUNC_LIB == 0: try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == LIBRARY_FUNCTIONS: for f in get_functions(): if idaapi.has_name(idc.get_full_flags( f.start_ea)) and f.flags & idc.FUNC_LIB != 0: try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == PUBLIC_FUNCTIONS: for f in get_functions(): if idaapi.is_public_name(f.start_ea): try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == ENTRY_POINT_FUNCTIONS: for i in zrange(idaapi.get_func_qty()): f = idaapi.get_func(idaapi.get_entry(idaapi.get_entry_ordinal(i))) if f is not None: try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == ALL_FUNCTIONS: n = idaapi.get_func_qty() for i, f in enumerate(get_functions()): try: logger.info("[ %d / %d ] %s %s", i + 1, n, idc.get_name(f.start_ea), hex(f.start_ea)) sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") return sigs
def is_code_ptr(ea): return is_mapped_data(ea, 4) and idc.is_code( idc.get_full_flags(idc.get_qword(ea)))
def is_code(self, ea): flags = idc.get_full_flags(ea) return idc.is_code(flags)
def is_code_ea(ea): if idaapi.cvar.inf.procname == "ARM": flags = idc.get_full_flags(ea & -2) # flags_t else: flags = idc.get_full_flags(ea) return idc.is_code(flags)
def find_function_ends(location, end_mnem_bytes=None): """ Description: Identifies all possible function ends before the next function or Align. Input: location - The EA to search after end_mnem_bytes - Try to end functions on a particular instruction Instructions are entered as space separated bytes (i.e. 'C2' for 'retn') The specified pattern will be used first, then the defaults will be used If no pattern is specified, the defaults will be used, which prefers 'retn' Output: ends - A list of function end EAs sorted: end_mnem_bytes, retn, jmp """ # foreach target bytes: # step instructions down # if instruction matches the target bytes, add to the corresponding output list # if we hit a function or an align, quit # return ends in the order: # end_nmem_bytes # retn # jmp # others, sorted ascending max_location = None ea = location while max_location is None: ea = idc.next_head(ea) if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)): max_location = ea elif ea == idc.BADADDR: max_location = idaapi.getseg(location).end_ea max_location = min(max_location, idaapi.getseg(location).end_ea) targets = ['C3', 'C2', 'E9', 'EA', 'EB'] if end_mnem_bytes: targets.insert(0, end_mnem_bytes) ends = {} for target in targets: function_ends = [] ea = find_binary_instruction_start(location, idc.SEARCH_DOWN, target, max_location=max_location) while ea != idc.BADADDR: if ea > max_location: break else: function_ends.append(ea) ea = find_binary_instruction_start(ea + 11, idc.SEARCH_DOWN, target, max_location=max_location) ends[target] = function_ends return [ end + idc.get_item_size(end) for end in ( (ends[end_mnem_bytes] if end_mnem_bytes else []) + sorted(ends['C3'] + ends['C2']) + sorted( itertools.chain.from_iterable(ends[target] for target in targets[-3:]))) ]