def get_xref(self, objc_selrefs, objc_msgrefs, objc_const): #We're looking for references to the selector string (think char **) #Which is either a selref, a msgref, or a pointer to the selector from the class's const method list name_ptr = self.name_pointer is_msg_ref = False selector_ref = None #how many references from __objc_const are there? This indicates how many classes #reference this selector const_ref_count = 0 for xref in XrefsTo(name_ptr): #Is this cross reference in the range of selector references? if objc_selrefs and xref.frm >= objc_selrefs[ 0] and xref.frm < objc_selrefs[1]: is_msg_ref = False selector_ref = xref #else, is this cross reference in the range of msg references? elif objc_msgrefs and xref.frm >= objc_msgrefs[ 0] and xref.frm < objc_msgrefs[1]: is_msg_ref = True selector_ref = xref #else, is this cross reference a pointer from a (const) method list? elif objc_const and xref.frm >= objc_const[ 0] and xref.frm < objc_const[1]: const_ref_count += 1 return (is_msg_ref, selector_ref, const_ref_count)
def walk_selector_refs(self): #sel_ref_va is the address of the selref, which itself is a pointer to the selector string #we're looking for cross references *to* the the address of the selref #If we find ones we like and replace them with a cross reference to the actual method implementation, rather than the selector for xref in XrefsTo(self.sel_ref_va): if print_insn_mnem(xref.frm) == self.CALL_MNEMONIC: continue #We found a xref *from* somewhere *to* our selref. We need to replace that with a reference #To the actual method implementation method_xref = self.add_method_xref(xref) self.patched_xrefs.append(method_xref)
def eFunc(self, address=None, retAddr=None, args=[]): if address == None: address = here() func = get_func(address) if retAddr == None: refs = [ref.frm for ref in XrefsTo(func.start_ea, 0)] if len(refs) != 0: retAddr = refs[0] + get_item_size(refs[0]) else: print("Please offer the return address.") return self._emulate(func.start_ea, retAddr, args) res = self.curUC.reg_read(self.REG_RES) return res
def _get_xref_to_calls(ea): """Return a generator to iterate over all function addresses which call the given function. :param int ea: Start address of the function. """ for xref in XrefsTo(ea): if xref.type not in CALL_JUMP_FLAGS: continue if GetFunctionName(xref.to).startswith('_ZThn'): continue yield xref.to
def find_chain_helper(chain, cfg_whitelist, startaddress, depth): xrefs = set() for xref in XrefsTo(startaddress, 0): for f in Functions(xref.frm, xref.frm): xrefs.add(f) for xref in xrefs: if xref in cfg_whitelist: newchain = chain[:] newchain.append(maybe_get_name(xref)) print_chain(newchain) if depth <= 1: return for xref in xrefs: newchain = chain[:] newchain.append(maybe_get_name(xref)) find_chain_helper(newchain, cfg_whitelist, xref, depth - 1)
def eFunc(self, target=None, retAddr=None, args=[]): if target == None: target = here() address = target_to_ea(target) func = idaapi.get_func(address) if retAddr == None: refs = [ref.frm for ref in XrefsTo(func.start_ea, 0)] if len(refs) != 0: retAddr = refs[0] + get_item_size(refs[0]) else: print("Please offer the return address.") return func_address = func.start_ea | 1 if self._is_thumb_ea( func.start_ea) else func.start_ea self._emulate(func_address, retAddr, args) res = self.uc.reg_read(self.REG_RES) return res
def _listRefsTo(self, start: int) -> List[Tuple[int, int]]: """Make a list of all the references to the given function. Args: func : The function references to which we are searching. start : The function's start offset. Returns: list : A list of tuples. Each tuple represents: the offsets: 0 : the offset from where the given function was referenced by the foreign function 1 : the function's start address """ func_refs_to = XrefsTo(start, 1) refs_list = [] for ref in func_refs_to: if idc.print_insn_mnem(ref.frm) == "": continue refs_list.append((ref.frm, start)) return refs_list
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 _add_function_strings(self): """Add the strings to the functions that use them.""" for ea in self.strings.keys(): references = tuple(XrefsTo(ea)) del_count = 0 for xref in references: func_ea = GetFunctionAttr(xref.frm, FUNCATTR_START) # Is the reference not a function? # Actually, we should compare func_ea == -1, but this seems to # be buggy. The -1 is probably returned as an unsigned int, # which results in 4294967295. if func_ea == 4294967295: del_count += 1 continue self.get_function(func_ea).add_string(ea) # No need to keep strings without a reference or without a # reference to a function. if del_count == len(references): del self.strings[ea]
def export(self, vtables): """ @vtables: List of tuples with vtable information [(ins_addr, vtable), ... ] There is a small mistake. Some .data references will be tagged as being vtables. This is due to the way we detect them on pin. In IDA pro it should be easy to mark just only the ones that refer to .text but I could not find a way to get that information from idapython. """ # We build a dictionary with the ins addr referencing the vtable as the key dict_ = {} for vtable in vtables: # Add all the vtable references found while tracing to the set dict_.setdefault(vtable[0], set()).add(vtable[1]) for (key, val) in dict_.iteritems(): prev_comment = idc.GetCommentEx(vtable[0], False) # Check if we already have commented this line. This will avoid duplicating info. if not prev_comment or "VTables found:" in prev_comment: prev_comment = "VTables found:\n" prev_comment += "\n".join(map(lambda x: "0x%.8x" % x, val)) # vtable[0] == instruction address idc.MakeComm(key, prev_comment) # Check if we already have a cross reference for v in val: if key in [ref.frm for ref in XrefsTo(v, 0)]: continue # Add a data reference if add_dref(key, v, dr_R) != True: idaapi.msg( "Could not create cross reference from %x to %x\n" % (key, v))
def _get_iOS6_syscall_addrs(self): """ currently always returns True bottom of syscall table __DATA:__const:802F2A28 sysent <2, 0, 0, 0x801CED69, 0, 0, _SYSCALL_RET_INT_T, 8, 0> __DATA:__const:802F2A40 unk_802F2A40 DCB 5 ; DATA XREF: sub_801CF720+40o __DATA:__const:802F2A40 ; sub_801CF720+48o __DATA:__const:802F2A41 DCB 0 __DATA:__const:802F2A42 DCB 0 __DATA:__const:802F2A43 DCB 0 __DATA:__const:802F2A44 DCD sub_801D0FC0+1 __DATA:__const:802F2A48 DCD sub_801D0FC4+1 __DATA:__const:802F2A4C DCD sub_801D0FC8+1 __DATA:__const:802F2A50 DCD sub_801D0FCC+1 __DATA:__const:802F2A54 DCD sub_801D1188+1 __DATA:__const:802F2A58 DCD sub_801D119C+1 __DATA:__const:802F2A5C DCD sub_801D1230+1 """ curr_addr = self.sysent while curr_addr < self.data_seg.endEA: if len(list(XrefsTo(curr_addr, 0))) > 0 and curr_addr != self.sysent: break if Dword(curr_addr + 0x10) > 10: # curr max return type is 7 break addr = Dword(curr_addr + 4) # should add check verify target in text segment self.syscall_addrs.append(addr) curr_addr += 0x18 return True
def _lookup_syscall_names_from_kernel(self): """ returns syscall list 6.1.2 kernel has syscall names as strings in __TEXT:__cstring segment """ syscall_ea = LocByName(string_prefix + "Syscall") if syscall_ea < self.cstring_seg.startEA or syscall_ea > self.cstring_seg.endEA: return False seg_start_ea = self.cstring_seg.startEA seg_end_ea = self.cstring_seg.endEA xrefs = list(XrefsTo(syscall_ea, 0)) if len(xrefs) != 1: return False xref = xrefs[0] addr = xref.frm while addr != BADADDR: t = Dword(addr) # test if in __TEXT:__cstring segment if t < seg_start_ea or t > seg_end_ea: break # get Name, check for str tname = Name(t) if tname.find(string_prefix) == 0: str_content = GetString(t) self.syscall_names.append(str_content) addr += 4 return True
def export(self, resolved_branches): dict_ = {} for r in resolved_branches: dict_.setdefault(r[0], set()).add(r[1]) for key, val in dict_.iteritems(): prev_comment = idc.GetCommentEx(key, False) if not prev_comment or "Resolved:" in prev_comment: prev_comment = "Resolved:\n" for v in val: prev_comment += "%s : %.8x\n" % (GetAddressName(v), v) # Check if we already have a cross reference if key in [ref.frm for ref in XrefsTo(v, 0)]: continue if AddCodeXref(key, v, fl_CN) != True: idaapi.msg( "Could not create cross reference from %x to %x\n" % (key, v)) idc.MakeComm(key, prev_comment)
from idc import GetFunctionName, SegName, get_type from sys import exit current_function = GetFunctionName(get_screen_ea()) print('Will generate forwards for all calls from {}'.format(current_function)) called_functions = [] function_name_to_address = {} for segea in Segments(): if SegName(segea) != '.text': continue for funcea in Functions(segea, SegEnd(segea)): called_functions.extend( filter(lambda x: GetFunctionName(x.frm) == current_function, XrefsTo(funcea))) function_name_to_address[GetFunctionName(funcea)] = funcea called_functions = map(lambda x: GetFunctionName(x.to), called_functions) called_functions = list(set(called_functions)) print('It calls {} functions!'.format(len(called_functions))) def forwarder_generator(prototype, address): until_arguments = prototype[:prototype.find('(')].split(' ') arguments = prototype[prototype.find('(') + 1:-1] pointer_levels = '' for i, _ in enumerate(until_arguments):