def kernelcache_find_virtual_method_overrides(classname=None, method=None): import idc import idaapi import ida_kernelcache as kc # Define the form to ask for the arguments. class MyForm(idaapi.Form): def __init__(self): swidth = 40 idaapi.Form.__init__( self, r"""STARTITEM 0 Find virtual method overrides <#The class#Class :{classname}> <#The virtual method#Method:{method}>""", { 'classname': idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT, swidth=swidth), 'method': idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT, swidth=swidth), }) def OnFormChange(self, fid): return 1 kc.collect_class_info() if any(arg is None for arg in (classname, method)): f = MyForm() f.Compile() f.classname.value = classname or '' f.method.value = method or '' ok = f.Execute() if ok != 1: print 'Cancelled' return False classname = f.classname.value method = f.method.value f.Free() if classname not in kc.class_info: print 'Not a valid class: {}'.format(classname) return False print 'Subclasses of {} that override {}:'.format(classname, method) baseinfo = kc.class_info[classname] found = False for classinfo in baseinfo.descendants(): for _, override, _ in kc.vtable.class_vtable_overrides( classinfo, superinfo=baseinfo, methods=True): name = idc.NameEx(idc.BADADDR, override) demangled = idc.Demangle(name, idc.GetLongPrm(idc.INF_SHORT_DN)) name = demangled if demangled else name if method in name: print '{:#x} {}'.format(override, classinfo.classname) found = True if not found: print 'No subclass of {} overrides {}'.format(classname, method) return found
def get_ea_name(ea, fromaddr=idc.BADADDR, true=False, user=False): """Get the name of an address. This function returns the name associated with the byte at the specified address. Arguments: ea: The linear address whose name to find. Options: fromaddr: The referring address. Default is BADADDR. Some addresses have a location-specific name (for example, labels within a function). If fromaddr is not BADADDR, then this function will try to retrieve the name of ea from fromaddr's perspective. The global name will be returned if no location-specific name is found. true: Retrieve the true name rather than the display name. Default is False. user: Return "" if the name is not a user name. Returns: The name of the address or "". """ if user and not idc.hasUserName(idc.GetFlags(ea)): return "" if true: return idc.GetTrueNameEx(fromaddr, ea) else: return idc.NameEx(fromaddr, ea)
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 kernelcache_find_virtual_method_overrides(classname=None, method=None): import idc import ida_kernelcache as kc kc.collect_class_info() if not classname: classname = idc.AskStr('IOUserClient', 'Enter class name') if classname not in kc.class_info: print 'Not a valid class: {}'.format(classname) return False if not method: method = idc.AskStr('externalMethod', 'Enter method name') print 'Subclasses of {} that override {}:'.format(classname, method) baseinfo = kc.class_info[classname] found = False for classinfo in baseinfo.descendants(): for _, override, _ in kc.vtable.class_vtable_overrides( classinfo, superinfo=baseinfo, methods=True): name = idc.NameEx(idc.BADADDR, override) demangled = idc.Demangle(name, idc.GetLongPrm(idc.INF_SHORT_DN)) name = demangled if demangled else name if method in name: print '{:#x} {}'.format(override, classinfo.classname) found = True if not found: print 'No subclass of {} overrides {}'.format(classname, method) return found
def _collect_data(self, collect_args): func_item = collect_args["func_item"] code_refs_from_list = list(idautils.CodeRefsFrom(func_item, False)) for code_ref in code_refs_from_list: is_loaded_dynamically = False is_library_function = False function_name = "" if (idc.GetFunctionFlags(code_ref) == -1): # Find code_ref in functions that are imported dynamically for imported_module in self._imported_modules: if code_ref in imported_module.get_addresses(): is_loaded_dynamically = True break else: if ((idc.GetFunctionFlags(code_ref) & idaapi.FUNC_LIB) != 0 and idaapi.get_func(code_ref) != idaapi.get_func(func_item)): # code_ref is imported statically is_library_function = True if (is_library_function or is_loaded_dynamically): # get name function_name = idc.NameEx(func_item, code_ref) # include in attribute if not (function_name in self._lib_calls_counters): self._lib_calls_counters[function_name] = 0 self._lib_calls_counters[function_name] += 1
def _collect_data(self, collect_args): func_item = collect_args["func_item"] code_refs_from_list = \ list(idautils.CodeRefsFrom(func_item, False)) for code_ref in code_refs_from_list: is_loaded_dynamically = False is_library_function = False called_function_name = "" if (idc.GetFunctionFlags(code_ref) == -1): # Find code_ref in functions that are imported dynamically for imported_module in self._imported_modules: if code_ref in imported_module.get_addresses(): is_loaded_dynamically = True break else: # get_func(code_ref) != get_func(func_item) -> # do not include coderefs to self. if ((idc.GetFunctionFlags(code_ref) & idaapi.FUNC_LIB) != 0 and idaapi.get_func(code_ref) != idaapi.get_func(func_item)): # code_ref is imported statically is_library_function = True # Data is gathered only for library functions or Imports. if (is_library_function or is_loaded_dynamically): # get name called_function_name = idc.NameEx(func_item, code_ref) # include in attribute self._lib_calls_list.append(called_function_name)
def getText(self, addy): #print "Fetching text for %08x" % addy color = idaapi.SCOLOR_STRING if addy == function.top(addy): name = idc.NameEx(addy, addy) try: name = idc.Demangle(name, idc.GetLongPrm(idc.INF_SHORT_DN)) except: pass else: name = idc.NameEx(addy, addy) if name: return idaapi.COLSTR(" %s " % name, color) else: return idaapi.COLSTR(" 0x%08x " % addy, color)
def generate_data_from_offset( offset): # credits to ferhat, or whoever wrote this found_values = {} chunks = idautils.Chunks(offset) for begin, end in chunks: name = "" offset = -1 ea = begin while ea != end: mnem = idc.GetMnem(ea) opnd = idc.GetOpnd(ea, 0) stack_value = idc.GetOperandValue(ea, 0) if mnem == "jz" or mnem == "jl": name = "" offset = -1 if offset == -1 and (mnem == "add" or mnem == "lea" or mnem == "sub"): offset = idc.GetOperandValue(ea, 1) if mnem == "sub": offset = 0x100000000 - offset if mnem == "push" and "offset" in opnd and "pNodeName" not in opnd: name = idc.GetString(stack_value, -1, idc.ASCSTR_C) if is_user_name(stack_value): # this should crash? wtf name = idc.NameEx(idc.BADADDR, stack_value) if mnem == "call" or mnem == "jmp": #print("{} at {}").format(name, dec_to_hex(offset)) if name: found_values[offset] = name name = "" offset = -1 ea = idc.NextNotTail(ea) return found_values
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 db_read(cls, address, key=None, repeatable=0): result = comment.toDict( idc.GetCommentEx(address, repeatable) ) name = idc.NameEx(address, address) if name: result['__name__'] = name # defaults if '__color__' not in result: c = cls.color(address) if c is not None: result['__color__'] = c if '__address__' not in result: result['__address__'] = address if '__context__' not in result: result['__context__'] = idc.GetFunctionAttr(address, idc.FUNCATTR_START) if '__sp__' not in result: result['__sp__'] = idc.GetSpd(address) if key is not None: return result[key] return result
break def is_user_name(ea): f = idc.GetFlags(ea) return idc.hasUserName(f) for (startea, endea) in Chunks(myfunc): for head in Heads(startea, endea): switch_info = idaapi.get_switch_info_ex(head) if switch_info != None: num_cases = switch_info.get_jtable_size() # print(num_cases) # print 'good jump table found' results = idaapi.calc_switch_cases(head, switch_info) for idx in xrange(results.cases.size()): cur_case = results.cases[idx] ret = is_user_name(results.targets[idx]) if ret: name = idc.NameEx(BADADDR, results.targets[idx]) if "TARGET_" in name or "PRED_" in name: for cidx in xrange(len(cur_case)): number = int(cur_case[cidx]) name = name.replace("TARGET_", "").replace("PRED_", "") if name not in jump_table: jump_table[name] = number print(jump_table)
def yacheck_function_name(self): addr = yaunit.load('function_name') self.assertEqual('some_new_function_name', idc.NameEx(idaapi.BADADDR, addr))