def parse_xrefs(xrefs): rsas = set() for xref in xrefs: name = None rsa = None ea = xref for i in range(0, 7): decoded_instruction = idautils.DecodePreviousInstruction(ea) xrefs_from = idautils.XrefsFrom(decoded_instruction.ea) for ref in xrefs_from: if ref.type == 1: s = idc.GetString(ref.to) if s: rsa = s elif ref.type == 21 and idc.GetDisasm(ref.to).find("cfstr") != -1: cfstr_xrefs = idautils.XrefsFrom(ref.to) for cfstr_xref in cfstr_xrefs: if cfstr_xref.type == 1: for cfstr_xref2 in idautils.XrefsFrom(cfstr_xref.to): s = idc.GetString(cfstr_xref2.to) if s and s.strip() != "": name = s if name and rsa: rsas.add((name, rsa)) ea = decoded_instruction.ea return [{"name": x[0].strip(), "rsa": x[1].strip()} for x in rsas]
def getXRefsFrom(self): # type: () -> (list[int], list[int]) """ computes code references called from this function, and data references accessed if the data reference accessed is a pool variable, and it's a pointer, the pointer is given instead (as compliant with the LDR RX =<refInPool> syntax) This defines all data and code dependencies in the function :return: """ crefs = [] drefs = [] # normalFlow = True # for ref in idautils.CodeRefsFrom(self.func_ea, normalFlow): # XrefsFrom # crefs.append(ref) # for ref in idautils.CodeRefsFrom(self.func_ea, not normalFlow): # XrefsFrom # crefs.append(ref) # for ref in idautils.CodeRefsFrom(self.func_ea-1, normalFlow): # XrefsFrom # crefs.append(ref) # for ref in idautils.CodeRefsFrom(self.func_ea-1, not normalFlow): # XrefsFrom # crefs.append(ref) # needed to identify pool variables. drefs accessing the pool may access pointers # in the pool. the pointers should be retrieved instead size_pool = self.getSize(withPool=True) # for each instruction for i in idautils.FuncItems(self.func_ea): for xref in idautils.XrefsFrom(i, 0): # if the xref is to a far or near called function if xref.type == idc.fl_CN or xref.type == idc.fl_CF: if xref.to not in crefs: crefs.append(xref.to) # if the xref is to a read or write data access if xref.type == idc.dr_W or xref.type == idc.dr_R: if xref.to not in drefs: # if xref.to is in the pool, then retrieve content if it's a pointer if xref.to < self.func_ea + size_pool: # those are the references found at the pool location iteratedOnce = False for poolRef in idautils.XrefsFrom(xref.to, 0): if iteratedOnce: raise (FunctionException( "%08X: there should only be one data xref in pool variable" % (self.func_ea))) # there should only be one in the pool refernce if poolRef.to not in drefs: drefs.append(poolRef.to) iteratedOnce = True else: drefs.append(xref.to) # for ref in idautils.DataRefsFrom(self.func_ea): # drefs.append(ref) # for ref in idautils.DataRefsFrom(self.func_ea - 1): # drefs.append(ref) return crefs, drefs
def rename_func_by_handle(startAddr, endAddr, offset1=8, offset2=4): # offset1 -> handle string -> get new func name # offset2 -> handle func -> get func addr for addr in range(startAddr, endAddr, offset1): for xref in idautils.XrefsFrom(addr, 0): name = idc.get_strlit_contents(xref.to) print('[INFO]{}'.format(name)) for xref in idautils.XrefsFrom(addr + offset2, 0): func_addr = xref.to # name = name.replace(b'*',b'').decode() name = 'func_' + name.decode() print(name) print(hex(func_addr)) idc.set_name(func_addr, name)
def scan_functions(self): from mybase import function self.logger.info("For function %s:" % idc.GetFunctionName(self.ea)) for ea in function.iterate(self.ea): for xref in idautils.XrefsFrom(ea, 0): if idautils.XrefTypeName(xref.type) == 'Code_Near_Call' or\ idautils.XrefTypeName(xref.type) == 'Code_Far_Call': self.logger.info("found call at %s --> %s" % (hex(ea), idc.GetFunctionName(xref.to))) #skip constructors fn = FunctionName(idc.GetFunctionName(xref.to)) if fn.namespace == fn.basename: continue tif = idaapi.tinfo_t() if idaapi.get_tinfo2(xref.to, tif): funcdata = idaapi.func_type_data_t() tif.get_func_details(funcdata) #funcdata.get_call_method() if funcdata.size() >= 1 and funcdata[0].name == "this": self.funcs.add( FunctionName(idc.GetFunctionName(xref.to))) self.logger.info("Call to %s found" % idc.GetFunctionName(xref.to)) else: self.logger.info("idaapi.get_tinfo2 failed") self.logger.info("%d subcalls found" % len(self.funcs))
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 # get name at screen ea ea = idc.get_screen_ea() name = idc.get_name(ea, idaapi.GN_DEMANGLED) if name and thing[0] in name: return ea # 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 far_code_refs: return far_code_refs[0] # First xref # Reach now, we do not have any valid name, return current screen ea return idc.get_screen_ea()
def is_split_jmp(ea): xrefs = [an_xref for an_xref in idautils.XrefsFrom(ea) if an_xref.type in FLOW_FLAGS] if len(xrefs) == 0: return False if len(xrefs) > 1: return True return False
def _get_api(sea): calls = 0 api = [] flags = idc.GetFunctionFlags(sea) # ignore library functions if flags & idc.FUNC_LIB or flags & idc.FUNC_THUNK: return calls, api # list of addresses addresses = list(idautils.FuncItems(sea)) for instr in addresses: tmp_api_address = "" if idaapi.is_call_insn(instr): for xref in idautils.XrefsFrom(instr, idaapi.XREF_FAR): if xref.to is None: calls += 1 continue tmp_api_address = xref.to break if tmp_api_address == "": calls += 1 continue api_flags = idc.GetFunctionFlags(tmp_api_address) if api_flags & idaapi.FUNC_LIB is True \ or api_flags & idaapi.FUNC_THUNK: tmp_api_name = idc.NameEx(0, tmp_api_address) if tmp_api_name: api.append(tmp_api_name) else: calls += 1 return calls, api
def graph_down(ea, path=set()): """ Recursively collect all function calls. Copied with minor modifications from http://hooked-on-mnemonics.blogspot.com/2012/07/renaming-subroutine-blocks-and.html """ path.add(ea) # # extract all the call instructions from the current function # call_instructions = [] instruction_info = idaapi.insn_t() for address in idautils.FuncItems(ea): # decode the instruction if not idaapi.decode_insn(instruction_info, address): continue # check if this instruction is a call if not idaapi.is_call_insn(instruction_info): continue # save this address as a call instruction call_instructions.append(address) # # iterate through all the instructions in the target function (ea) and # inspect all the call instructions # for x in call_instructions: # TODO for r in idautils.XrefsFrom(x, idaapi.XREF_FAR): #print(0x%08X" % h, "--calls-->", "0x%08X" % r.to) if not r.iscode: continue # get the function pointed at by this call func = idaapi.get_func(r.to) if not func: continue # ignore calls to imports / library calls / thunks if (func.flags & (idaapi.FUNC_THUNK | idaapi.FUNC_LIB)) != 0: continue # # if we have not traversed to the destination function that this # call references, recurse down to it to continue our traversal # if r.to not in path: graph_down(r.to, path) return path
def is_jmp(ea): xrefs = [ an_xref for an_xref in idautils.XrefsFrom(ea) if an_xref.type in JUMP_FLAGS ] if len(xrefs) > 0: return True return False
def get_succ(func_start): succ = set() for h in idautils.FuncItems(func_start): for r in idautils.XrefsFrom(h, 0): if r.type == fl_CF or r.type == fl_CN: #print hex(h), "-->", hex(r.to) succ.add(r.to) return succ
def calls_from(self) -> Iterable[Tuple[int, int]]: """Iterates call address and callee address of the calls within this function.""" for ea in self.heads(): if idc.print_insn_mnem(ea) == "call": for xref in idautils.XrefsFrom(ea, idaapi.XREF_FAR): func_ea = xref.to if func_ea: yield ea, func_ea
def _get_call_target(self, instruction): for xref in idautils.XrefsFrom(instruction, 0): if xref.type == 17: #Code_Near_Call callsite_function_name = idc.GetFunctionName(xref.to) #XXX: sometimes IDA can't identify the function (e.g., athwx.sys) if callsite_function_name is not None and len( callsite_function_name) > 0: return xref.to return 0
def processRefs(output): """ process all the xrefs that ida recognizes params: output: protobuf file path returns: """ refInf = refInf_pb2.RefList() # iterate over all valid terms for head in idautils.Heads(): is_code = False candidateRefs = None if idc.is_code(idc.get_full_flags(head)): is_code = True decoded_inst = ida_ua.insn_t() insn_len = ida_ua.decode_insn(decoded_inst, head) if insn_len > 0: candidateRefs = getCandidateRefsFromInsn(decoded_inst) if is_code and candidateRefs == None: continue for xref in idautils.XrefsFrom(head, 0): ref_from = head target_addr = xref.to # check if target_addr is in current instruction internal representation if is_code: if target_addr not in candidateRefs: continue else: ref_from = candidateRefs[target_addr] if is_invalid_ea(target_addr): continue logging.debug( "Ref: 0x%x -> 0x%x, type is %s" % (ref_from, target_addr, idautils.XrefTypeName(xref.type))) ref = refInf.ref.add() ref.ref_va = ref_from ref.target_va = target_addr # default value ref.ref_size = 8 target_is_code = idc.is_code(idc.get_full_flags(target_addr)) if is_code and target_is_code: ref.kind = 0 # c2c elif is_code and not target_is_code: ref.kind = 1 # c2d elif not is_code and target_is_code: ref.kind = 2 # d2c else: ref.kind = 3 # d2d ## save the protobuf result with open(output, 'wb') as pbOut: pbOut.write(refInf.SerializeToString())
def idautils_getXrefs_from(): """ IDA GUI: Right click on any address and click List Cross-references from. This is just a list of all those locations in all segments that this address refers to. While this code will work, it makes more sense to iterate over an entire function and check every location for Cross references. """ print "Getting all cross references from a specific address" xrefs = idautils.XrefsFrom(0x000000004A6811E0, 0) for ref in xrefs: print hex(ref.to)
def calls_from(self) -> Iterable[Tuple[int, int]]: """Iterates call address and callee address of the calls within this function.""" for ea in self.heads(): insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) if ida_idp.is_call_insn(insn): for xref in idautils.XrefsFrom(ea, idaapi.XREF_FAR): func_ea = xref.to if func_ea: yield ea, func_ea
def xFrom(self): """ Property which allow to get all xrefs generated (from) by the element. This is the equivalent to ``XrefsFrom`` from idapython. :return: A list of :class:`BipXref` with the ``src`` being this element. """ return [ bip.base.xref.BipXref(x) for x in idautils.XrefsFrom(self._idelt) ]
def generate_graph(): callees = {} # loop through all functions for function_ea in idautils.Functions(): f_name = idc.get_func_name(function_ea) callees[str(f_name)] = set() for h in idautils.FuncItems(function_ea): for r in idautils.XrefsFrom(h, 0): caller_name = idc.get_func_name(r.to) callees[str(f_name)].add(str(caller_name)) return callees
def _get_call_target(self, instructions): ct = [] for (instruction, ret) in instructions: for xref in idautils.XrefsFrom(instruction, 0): if xref.type == 17: # code_Near_Call callsite_function_name = idc.GetFunctionName(xref.to) # TODO: handle indirect calls ? if callsite_function_name is not None and len( callsite_function_name) > 0: ct.append((instruction, xref.to, ret)) return ct
def trace(self, ea): ''' Given an EA where an argument register is set, attempt to trace what function call that argument is passed to. @ea - The address of an instruction that modifies a function argument register. Returns a tuple of (function EA, argv index, argument register name) on success. Returns None on failure. ''' insn = ida_shims.decode_insn(ea) features = ida_shims.get_canon_feature(insn) if self.arch.unknown: return (None, None, None) for n in range(0, len(self.CHANGE_OPND)): ops = ida_shims.get_operands(insn) if ops[n].type in [idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase]: try: regname = self.arch.registers[ops[n].reg] index = self.arch.argv.index(regname) except ValueError: continue if features & self.CHANGE_OPND[n]: ea = ea - (self.arch.delay_slot * self.arch.insn_size) while True: insn = ida_shims.decode_insn(ea) if idaapi.is_call_insn(ea): for xref in idautils.XrefsFrom(ea): if xref.type in [idaapi.fl_CF, idaapi.fl_CN]: return (xref.to, index, regname) # If we couldn't figure out where the function call # was going to, just quit break try: is_block_end = idaapi.is_basic_block_end(ea) except TypeError: is_block_end = idaapi.is_basic_block_end(ea, True) if is_block_end: break # TODO: Use idc.NextHead(ea) instead... ea += self.arch.insn_size return (None, None, None)
def post_struct_member_type_change(member): xrefs = idautils.XrefsFrom(member.id) xrefs = filter(lambda x: x.type == ida_xref.dr_I and x.user == 1, xrefs) for xref in xrefs: if utils.is_func(xref.to): function_ptr_tinfo = idaapi.tinfo_t() ida_struct.get_member_tinfo(function_ptr_tinfo, member) if function_ptr_tinfo.is_funcptr(): function_tinfo = function_ptr_tinfo.get_pointed_object() if function_tinfo is not None: ida_typeinf.apply_tinfo( xref.to, function_tinfo, idaapi.TINFO_DEFINITE )
def argv(self, func): ''' Attempts to identify what types of arguments are passed to a given function. Currently unused. ''' args = [None for x in self.arch.argv] if not self.arch.unknown: start_ea = ida_shims.start_ea(func) for xref in idautils.XrefsTo(start_ea): if idaapi.is_call_insn(xref.frm): insn = ida_shims.decode_insn(xref.frm) ea = xref.frm + (self.arch.delay_slot * self.arch.insn_size) end_ea = (xref.frm - (self.arch.insn_size * 10)) while ea >= end_ea: if idaapi.is_basic_block_end(ea) or \ (ea != xref.frm and idaapi.is_call_insn(ea)): break insn = ida_shims.decode_insn(ea) features = ida_shims.get_canon_feature(insn) for n in range(0, len(self.CHANGE_OPND)): ops = ida_shims.get_operands(insn) if ops[n].type in [ idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase ]: try: regname = self.arch.registers[ops[n].reg] index = self.arch.argv.index(regname) except ValueError: continue if features & self.CHANGE_OPND[n]: for xref in idautils.XrefsFrom(ea): # TODO: Where is this xref type defined? if xref.type == 1: string = \ ida_shims.get_strlit_contents( xref.to) if string and len(string) > 4: args[index] = str break ea -= self.arch.insn_size yield args
def getChildren(self, blockID): if (blockID in self.children): return self.children[blockID] else: children = set([]) for x in idautils.XrefsFrom(self.blockInfo[blockID]['EndEA']): if (x.type == 21 or x.type == 19): children.add(x.to) else: func_x = idaapi.get_func(x.to) if (func_x and func_x.startEA == self.function): children.add(x.to) self.children[blockID] = children return self.children[blockID]
def find_tight_loops(fva): """ Code from Willi Ballenthin """ tight_loops = [] function = idaapi.get_func(fva) for bb in idaapi.FlowChart(function): # bb.endEA is the first addr not in the basic block bb_end = idc.PrevHead(bb.endEA) for x in idautils.XrefsFrom(bb_end): if x.to == bb.startEA and bb.startEA < bb_end: tight_loops.append((bb.startEA, bb_end)) if tight_loops: g_logger.debug("Tight loops in 0x%x: %s", fva, ["0x%x - 0x%x" % (s, e) for (s, e) in tight_loops]) return tight_loops
def argv(self, func): ''' Attempts to identify what types of arguments are passed to a given function. Currently unused. ''' args = [None for x in self.arch.argv] for xref in idautils.XrefsTo(func.startEA): if idaapi.is_call_insn(xref.frm): idaapi.decode_insn(xref.frm) ea = xref.frm + (self.arch.delay_slot * self.arch.insn_size) end_ea = (xref.frm - (self.arch.insn_size * 10)) while ea >= end_ea: # Stop searching if we've reached a conditional block or another call if idaapi.is_basic_block_end(ea) or ( ea != xref.frm and idaapi.is_call_insn(ea)): break idaapi.decode_insn(ea) features = idaapi.cmd.get_canon_feature() for n in range(0, len(self.CHANGE_OPND)): if idaapi.cmd.Operands[n].type in [ idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase ]: try: regname = self.arch.registers[ idaapi.cmd.Operands[n].reg] index = self.arch.argv.index(regname) except ValueError: continue if features & self.CHANGE_OPND[n]: for xref in idautils.XrefsFrom(ea): # TODO: Where is this xref type defined? if xref.type == 1: string = idc.GetString(xref.to) if string and len(string) > 4: args[index] = str break ea -= self.arch.insn_size yield args
def get_custom_viewer_hint(self, view, place): try: widget = ida_kernwin.get_current_widget() if ida_kernwin.get_widget_type(widget) != ida_kernwin.BWN_DISASM: return None curline = ida_kernwin.get_custom_viewer_curline(view, True) # sometimes get_custom_viewer_place() returns [x, y] and sometimes [place_t, x, y]. # we want the place_t. viewer_place = ida_kernwin.get_custom_viewer_place(view, True) if len(viewer_place) != 3: return None _, x, y = viewer_place ea = place.toea() # "color" is a bit of misnomer: its the type of the symbol currently hinted color = get_color_at_char(curline, x) if color != ida_lines.COLOR_ADDR: return None # grab the FAR references to code (not necessarilty a branch/call/jump by itself) far_code_references = [ xref.to for xref in idautils.XrefsFrom(ea, ida_xref.XREF_FAR) if ida_bytes.is_code(ida_bytes.get_flags(xref.to)) ] if len(far_code_references) != 1: return None fva = far_code_references[0] # ensure its actually a function if not idaapi.get_func(fva): return None # this magic constant is the number of "important lines" to display by default. # the remaining lines get shown if you scroll down while the hint is displayed, revealing more lines. return render_function_hint(fva), DEFAULT_IMPORTANT_LINES_NUM except Exception as e: logger.warning( 'unexpected exception: %s. Get in touch with @williballenthin.', e, exc_info=True) return None
def api_calls(self): """ Returns counter containing API calls and the number of times they were called. """ if self._api_calls: return self._api_calls api_calls = collections.Counter() for ea in self.heads(): if idc.print_insn_mnem(ea) == "call": for xref in idautils.XrefsFrom(ea, idaapi.XREF_FAR): if xref.to: func_name = ida_name.get_name(xref.to) if func_name: api_calls.update([func_name]) self._api_calls = api_calls return self._api_calls
def find_xrefs_from(self, func_ea): xrefs = [] for item in idautils.FuncItems(func_ea): ALL_XREFS = 0 for ref in idautils.XrefsFrom(item, ALL_XREFS): if ref.type not in XrefsFromFinder.XREF_TYPE2STR: continue if ref.to in idautils.FuncItems(func_ea): continue disas = idc.GetDisasm(item) curr_xref = XrefFrom(item, ref.to, ref.type, disas) xrefs.append(curr_xref) return xrefs
def analyzeFunction(self, funcea): # https://reverseengineering.stackexchange.com/questions/9352/finding-all-api-calls-in-a-function # Copy + Paste from Stack Overflow - Lika Boss n_flags = set() dism_addr = list(idautils.FuncItems(funcea)) for instr in dism_addr: tmp_api_address = "" if idaapi.is_call_insn(instr): for xref in idautils.XrefsFrom(instr, idaapi.XREF_FAR): if xref.to == None: continue tmp_api_address = xref.to break # get next instr since api address could not be found if tmp_api_address == "": continue api_flags = idc.GetFunctionFlags(tmp_api_address) # check for lib code (api) if (api_flags & idaapi.FUNC_LIB and api_flags & idaapi.FUNC_STATICDEF): tmp_api_name = idc.NameEx(0, tmp_api_address) if tmp_api_name: t_flags = self.processFunction( funcea, tmp_api_name) n_flags = ( t_flags| n_flags ) # Rename function if flags populated # Skip of this isn't the first run sflags = "".join(set(n_flags)) if len(n_flags) > 0 and self.rename: fn = idc.GetFunctionName(funcea) if not fn.startswith(sflags): print "Renaming - ", fn, " with - ", sflags idc.MakeName(funcea, str(sflags + "_" + fn )) tbl = [ funcea, idc.GetFunctionName(funcea), sflags ] for f in definitions.PEAPIs.keys(): if definitions.PEAPIs[f]['flag'] in sflags: tbl.append('*') else: tbl.append('') data.append( tbl )
def get_func_code_refs_from(func_ea, iaddrs): """Returns a set with the code references from this function""" code_refs = set() for addr in iaddrs: ref = idaapi.BADADDR for r in idautils.XrefsFrom(addr, idaapi.XREF_FAR): if r.iscode: to_func = idaapi.get_func(r.to) if not to_func or to_func.startEA != func_ea: ref = r.to else: ref = r.to if (ref != idaapi.BADADDR or idaapi.is_call_insn(addr) or idaapi.is_indirect_jump_insn(addr)): #print hex(i.addr), i, hex(ref) code_refs.add(ref) return code_refs
def show_graph(): f = ida_funcs.get_func(ida_kernwin.get_screen_ea()) if not f: print("Must be in a function") return # Iterate through all function instructions and take only call instructions result = [] tmp = ida_ua.insn_t() for x in [ x for x in idautils.FuncItems(f.start_ea) if (ida_ua.decode_insn(tmp, x) and ida_idp.is_call_insn(tmp)) ]: for xref in idautils.XrefsFrom(x, ida_xref.XREF_FAR): if not xref.iscode: continue t = ida_funcs.get_func_name(xref.to) if not t: t = hex(xref.to) result.append(t) g = MyGraph(ida_funcs.get_func_name(f.start_ea), result) if g.Show(): return g else: return None