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 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 kernelcache_populate_struct(struct=None, address=None, register=None, delta=None): import idc import idautils import idaapi import ida_kernelcache as kc import ida_kernelcache.ida_utilities as idau # Define the form to ask for the arguments. class MyForm(idaapi.Form): def __init__(self): swidth = 40 idaapi.Form.__init__( self, r"""STARTITEM 0 Automatically populate struct fields <#The name of the structure#Structure:{structure}> <#The address of the instruction at which the register points to the structure#Address :{address}> <#The register containing the pointer to the structure#Register :{register}> <#The offset of the pointer from the start of the structure#Delta :{delta}>""", { 'structure': idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT, swidth=swidth), 'address': idaapi.Form.NumericInput( tp=idaapi.Form.FT_ADDR, swidth=swidth, width=1000), 'register': idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT, swidth=swidth), 'delta': idaapi.Form.NumericInput(tp=idaapi.Form.FT_INT64, swidth=swidth), }) def OnFormChange(self, fid): return 1 # If any argument is unspecified, get it using the form. if any(arg is None for arg in (struct, address, register, delta)): f = MyForm() f.Compile() f.structure.value = struct or '' f.address.value = address or idc.get_screen_ea() f.register.value = register or 'X0' f.delta.value = delta or 0 ok = f.Execute() if ok != 1: print 'Cancelled' return False struct = f.structure.value address = f.address.value register = f.register.value delta = f.delta.value f.Free() # Check whether this struct is a class. kc.collect_class_info() is_class = struct in kc.class_info # Open the structure. sid = idau.struct_open(struct, create=True) if sid is None: print 'Could not open struct {}'.format(struct) return False # Check that the address is in a function. if not idaapi.get_func(address): print 'Address {:#x} is not a function'.format(address) return False # Get the register id. register_id = None if type(register) is str: register_id = idaapi.str2reg(register) elif type(register) is int: register_id = register register = idaapi.get_reg_name(register_id, 8) if register_id is None or register_id < 0: print 'Invalid register {}'.format(register) return False # Validate delta. if delta < 0 or delta > 0x1000000: print 'Invalid delta {}'.format(delta) return False elif is_class and delta != 0: print 'Nonzero delta not yet supported' return False type_name = 'class' if is_class else 'struct' print '{} = {}, address = {:#x}, register = {}, delta = {:#x}'.format( type_name, struct, address, register, delta) if is_class: # Run the analysis. kc.class_struct.process_functions([(address, struct, register_id)]) else: # Run the data flow to collect the accesses and then add those fields to the struct. accesses = kc.data_flow.pointer_accesses( function=address, initialization={address: { register_id: delta }}) kc.build_struct.create_struct_fields(sid, accesses=accesses) # Set the offsets to stroff. for addresses_and_deltas in accesses.values(): for ea, delta in addresses_and_deltas: insn = idautils.DecodeInstruction(ea) if insn: for op in insn.Operands: if op.type == idaapi.o_displ: idau.insn_op_stroff(insn, op.n, sid, delta) # All done! :) print 'Done' return True