def find_WdfControlDeviceInitAllocate(): function_offset = OFFSET_WdfControlDeviceInitAllocate call_pfn = None try: for xref in idautils.XrefsTo(g_vars["_WDFFUNCTIONS"] + function_offset): call_pfn = xref.frm except StopIteration: # this is case 2 or 3 pass if call_pfn is None: call_pfn = find_wdf_callback_through_immediate("call", 0, function_offset) if call_pfn: idc.OpStroffEx(call_pfn, 0, (idaapi.get_struc_id("_WDFFUNCTIONS")), 0) if call_pfn is None: call_pfn = find_wdf_callback_through_immediate("mov", 1, function_offset) if call_pfn: idc.OpStroffEx(call_pfn, 1, (idaapi.get_struc_id("_WDFFUNCTIONS")), 0) lea_sddl = find_function_arg(call_pfn, "lea", "r8", 0) unicode_sddl = idc.get_operand_value(lea_sddl, 1) idc.set_name(unicode_sddl, 'control_device_sddl') assign_struct_to_address(unicode_sddl, "_UNICODE_STRING") print("Control Device SDDL at: ", hex(unicode_sddl))
def find_WdfDeviceCreateDeviceInterface(): function_offset = OFFSET_WdfDeviceCreateDeviceInterface calls_to_pfn_list = [] try: for xref in idautils.XrefsTo(g_vars["_WDFFUNCTIONS"]+function_offset): call_pfnWdfDeviceCreateDeviceInterface = xref.frm calls_to_pfn_list.append(call_pfnWdfDeviceCreateDeviceInterface) except StopIteration: # this is case 2 or 3 pass if len(calls_to_pfn_list) == 0: call_pfnWdfDeviceCreateDeviceInterface = find_wdf_callback_through_immediate("call", 0, function_offset) if call_pfnWdfDeviceCreateDeviceInterface: calls_to_pfn_list.append(call_pfnWdfDeviceCreateDeviceInterface) idc.OpStroffEx(call_pfnWdfDeviceCreateDeviceInterface,0,(idaapi.get_struc_id("_WDFFUNCTIONS")),0) if len(calls_to_pfn_list) == 0: call_pfnWdfDeviceCreateDeviceInterface = find_wdf_callback_through_immediate("mov", 1,function_offset) if call_pfnWdfDeviceCreateDeviceInterface: calls_to_pfn_list.append(call_pfnWdfDeviceCreateDeviceInterface) idc.OpStroffEx(call_pfnWdfDeviceCreateDeviceInterface,1,(idaapi.get_struc_id("_WDFFUNCTIONS")),0) for k, pfn_call in enumerate(calls_to_pfn_list): lea_guid = find_function_arg(pfn_call, "lea", "r8", 0) interface_guid = idc.GetOperandValue(lea_guid, 1) idc.MakeName(interface_guid, '_InterfaceGUID' + str(k)) assign_struct_to_address(interface_guid, "GUID") g_vars["_InterfaceGUID" + str(k)] = interface_guid print("_InterfaceGUID: ", hex(interface_guid)) guid_bytes = idc.GetManyBytes(interface_guid, 0x10) print_guid(guid_bytes)
def find_WdfDriverCreate(): function_offset = OFFSET_WdfDriverCreate # If the XREF to wdfFunctions + function_offset exists.. then we're in case 1! try: call_pfnWdfDriverCreate = idautils.XrefsTo(g_vars["_WDFFUNCTIONS"]+function_offset).next().frm except StopIteration: # this is case 2! call_pfnWdfDriverCreate = find_wdf_callback_through_immediate("mov", 1,function_offset) if call_pfnWdfDriverCreate != None: idc.OpStroffEx(call_pfnWdfDriverCreate,1,(idaapi.get_struc_id("_WDFFUNCTIONS")),0) else: call_pfnWdfDriverCreate = find_wdf_callback_through_immediate("call", 0, function_offset) idc.OpStroffEx(call_pfnWdfDriverCreate,0,(idaapi.get_struc_id("_WDFFUNCTIONS")),0) if call_pfnWdfDriverCreate != None: # First identify the RealDriverEntry :) current_func = idaapi.get_func(call_pfnWdfDriverCreate) idc.MakeName(current_func.startEA, "_DriverEntry_") argument_DriverConfig_addr = find_function_arg_with_operand_value(call_pfnWdfDriverCreate, "mov", "rsp", 0x20, 0) register_DriverConfig = idc.GetOpnd(argument_DriverConfig_addr, 1) lea_DriverConfig_addr = find_function_arg(argument_DriverConfig_addr, "lea", register_DriverConfig, 0) # Get stack and the stack operand offset current_func = idaapi.get_func(lea_DriverConfig_addr) stack_id = idc.GetFrame(current_func) opnd = idc.GetOpnd(lea_DriverConfig_addr, 1) if "rsp" in opnd: stack_member_offset = idc.GetOperandValue(lea_DriverConfig_addr, 1) elif "rbp" in opnd: var_x = opnd.split("+")[-1][:-1] # [rbp+57h+var_80] -> var_80 members, _ = retrieve_stack_members(current_func) inverted_members = {v:k for k, v in members.items()} try: stack_member_offset = inverted_members[var_x] except KeyError as msg: print msg return else: print("+] WdfDriverCreate() Unidentified register stack layout") return #idc.SetMemberName(stack_id, stack_member_offset, "_DriverConfig") struct_id = idaapi.get_struc_id("_WDF_DRIVER_CONFIG") struct_size = idc.GetStrucSize(struct_id) # First check if we have already touch this function stack before #if function_stack_erased(current_func): # need to take care of the already defined structs # pass #else: delete_all_function_stack_members(current_func, force=True) idc.AddStrucMember(stack_id, "driver_config", stack_member_offset, idc.FF_BYTE|idc.FF_DATA, -1, struct_size) idc.SetMemberType(stack_id, stack_member_offset, idc.FF_STRU|idc.FF_DATA, struct_id, 1)
def find_WdfIoQueueCreate(): function_offset = OFFSET_WdfIoQueueCreate calls_to_pfn_list = [] try: for xref in idautils.XrefsTo(g_vars["_WDFFUNCTIONS"] + function_offset): call_pfnWdfIoQueueCreate = xref.frm calls_to_pfn_list.append(call_pfnWdfIoQueueCreate) except StopIteration: # this is case 2 or 3 pass if len(calls_to_pfn_list) == 0: call_pfnWdfIoQueueCreate = find_wdf_callback_through_immediate( "call", 0, function_offset) if call_pfnWdfIoQueueCreate: calls_to_pfn_list.append(call_pfnWdfIoQueueCreate) idc.OpStroffEx(call_pfnWdfIoQueueCreate, 0, (idaapi.get_struc_id("_WDFFUNCTIONS")), 0) if len(calls_to_pfn_list) == 0: call_pfnWdfIoQueueCreate = find_wdf_callback_through_immediate( "mov", 1, function_offset) if call_pfnWdfIoQueueCreate: calls_to_pfn_list.append(call_pfnWdfIoQueueCreate) idc.OpStroffEx(call_pfnWdfIoQueueCreate, 1, (idaapi.get_struc_id("_WDFFUNCTIONS")), 0) for pfn_call in calls_to_pfn_list: lea_argument_addr = find_function_arg(pfn_call, "lea", "r8", 0) # Get stack and the stack operand offset current_func = idaapi.get_func(lea_argument_addr) stack_id = idc.GetFrame(current_func) stack_member_offset = idc.get_operand_value(lea_argument_addr, 1) struct_id = idaapi.get_struc_id("_WDF_IO_QUEUE_CONFIG") struct_size = idc.GetStrucSize(struct_id) # First check if we have already touch this function stack before if function_stack_erased(current_func): # need to take care of the already defined structs # If the arguments collide then this will fail pass else: delete_all_function_stack_members(current_func) print("Erased the stack members") idc.AddStrucMember(stack_id, "queue_config", stack_member_offset, idc.FF_BYTE | idc.FF_DATA, -1, struct_size) idc.SetMemberType(stack_id, stack_member_offset, idc.FF_STRU | idc.FF_DATA, struct_id, 1) print("IOQueue Creation at: " + hex(pfn_call))
def _convert_operands_to_struct_offsets(access_addresses): """Convert the operands that generated struct accesses into struct offsets.""" for classname, addresses_and_deltas in access_addresses.items(): sid = idau.struct_open(classname) if sid is not None: for ea, delta in addresses_and_deltas: insn = idautils.DecodeInstruction(ea) if insn: for op in insn.Operands: if op.type == idaapi.o_displ: if not idc.OpStroffEx(ea, op.n, sid, delta): _log(1, 'Could not convert {:#x} to struct offset for class {} ' 'delta {}', ea, classname, delta)
def find_WdfDeviceInitSetIoInCallerContextCallback(): function_offset = OFFSET_WdfDeviceInitSetIoIncallerContextCallback try: call_pfn = idautils.XrefsTo(g_vars["_WDFFUNCTIONS"]+function_offset).next().frm except StopIteration: # this is case 2! call_pfn = find_wdf_callback_through_immediate("mov", 1,function_offset) if call_pfn is None: call_pfn = find_wdf_callback_through_immediate("call", 0, function_offset) if call_pfn != None: idc.OpStroffEx(call_pfn,0,(idaapi.get_struc_id("_WDFFUNCTIONS")),0) lea_addr = find_function_arg(call_pfn, "lea", "r8", 0) EvtWdfIoInCallerContext = idc.GetOperandValue(lea_addr, 1) idc.MakeName(EvtWdfIoInCallerContext, 'EvtWdfIoInCallerContext')
def yatest_apply_struct(self): addrs = [] # -1: struct, n: union for k in range(-1, 4): # find an integer operand in any function addr = self.find_operand_addr() addrs.append(addr) # create struct sid = idc.AddStrucEx(-1, 'apply_struct_%x' % (k + 1), 0) self.assertNotEqual(sid, -1) ftype = idaapi.FF_BYTE | idaapi.FF_DATA # apply struct only if k == -1: # add struct fields for x in xrange(0, 0x60): self.assertEqual( idc.AddStrucMember(sid, 'field_%x' % x, -1, ftype, -1, 1), 0) # apply struct self.assertNotEqual(idc.OpStroffEx(addr, 1, sid, 0), idaapi.BADADDR) continue # create union uid = idc.AddStrucEx(-1, 'apply_union_%x' % (k + 1), 1) self.assertNotEqual(uid, -1) for x in xrange(1, 0x10): self.assertEqual( idc.AddStrucMember(uid, 'union_%x' % x, -1, ftype, -1, 1), 0) # add struct fields for x in xrange(0, 0x60): self.assertEqual( idc.AddStrucMember(sid, 'field_%x' % x, -1, idaapi.struflag(), uid, 1), 0) # apply selected union field fid = idc.GetMemberId(uid, k) self.assertNotEqual(fid, -1) path = idaapi.tid_array(2) path[0] = sid path[1] = fid self.assertNotEqual(idaapi.op_stroff(addr, 1, path.cast(), 2, 0), idaapi.BADADDR) yaunit.save('apply_struct', addrs)
def _insn_op_stroff_695(insn, n, sid, delta): """A wrapper of idc.OpStroffEx for IDA 6.95.""" return idc.OpStroffEx(insn.ea, n, sid, delta)
def _insn_op_stroff_700(insn, n, sid, delta): """A wrapper of idc.OpStroffEx for IDA 7.""" return idc.OpStroffEx(insn, n, sid, delta)
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.ScreenEA() 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: idc.OpStroffEx(ea, op.n, sid, delta) # All done! :) print 'Done' return True