def load_kext(self): self.heap.clear() # Setup mac_policy_list kern_mac_policy_list = self.ql.loader.kernel_extrn_symbols_detail[ b"_mac_policy_list"]["n_value"] mac_policy_list_addr = self.heap.alloc(sizeof(mac_policy_list_t)) self.mac_policy_list = mac_policy_list_t(self, mac_policy_list_addr) self.ql.mem.write(kern_mac_policy_list, self.ql.pack64(mac_policy_list_addr)) # Add initial process to allproc in kernel allproc = self.ql.loader.kernel_extrn_symbols_detail[b"_allproc"][ "n_value"] self.ev_manager.set_allproc(allproc) self.ev_manager.add_process(0, "head") self.ev_manager.add_process(0x1337, "demigod") self.ev_manager.add_process(1, "tail") if self.ql.loader.IOKit is True: # Handle IOKit driver self.ql.stack_push(0) self.savedrip = 0xffffff8000a163bd self.ql.run(begin=self.ql.loader.kext_alloc) self.kext_object = self.ql.arch.regs.rax self.ql.log.debug("Created kext object at 0x%x" % self.kext_object) self.ql.arch.regs.rdi = self.kext_object self.ql.arch.regs.rsi = 0 # NULL option self.savedrip = 0xffffff8000a16020 self.ql.run(begin=self.ql.loader.kext_init) if self.ql.arch.regs.rax == 0: self.ql.log.debug("Failed to initialize kext object") return self.ql.log.debug("Initialized kext object") self.ql.arch.regs.rdi = self.kext_object # FIXME Determine provider for kext self.ql.arch.regs.rsi = 0 # ? self.savedrip = 0xffffff8000a16102 self.ql.run(begin=self.ql.loader.kext_attach) if self.ql.arch.regs.rax == 0: self.ql.log.debug("Failed to attach kext object") return self.ql.log.debug("Attached kext object 1st time") self.ql.arch.regs.rdi = self.kext_object self.ql.arch.regs.rdi = 0 # FIXME Determine provider for kext self.ql.arch.regs.rsi = 0 # ? tmp = self.heap.alloc(8) self.ql.arch.regs.rdx = tmp self.savedrip = 0xffffff8000a16184 self.ql.run(begin=self.ql.loader.kext_probe) self.heap.free(tmp) self.ql.log.debug("Probed kext object") self.ql.arch.regs.rdi = self.kext_object # FIXME Determine provider for kext self.ql.arch.regs.rsi = 0 # ? self.savedrip = 0xffffff8000a16198 self.ql.run(begin=self.ql.loader.kext_detach) self.ql.log.debug("Detached kext object") self.ql.arch.regs.rdi = self.kext_object # FIXME Determine provider for kext self.ql.arch.regs.rsi = 0 # ? self.savedrip = 0xffffff8000a168a3 self.ql.run(begin=self.ql.loader.kext_attach) if self.ql.arch.regs.rax == 0: self.ql.log.debug("Failed to attach kext object") return self.ql.log.debug("Attached kext object 2nd time") self.ql.arch.regs.rdi = self.kext_object # FIXME Determine provider for kext self.ql.arch.regs.rsi = 0 # ? self.savedrip = 0xffffff8000a168ed self.ql.run(begin=self.ql.loader.kext_start) else: kmod_info_addr = self.heap.alloc(sizeof(kmod_info_t)) self.ql.log.debug("Created fake kmod_info at 0x%x" % kmod_info_addr) kmod_info = kmod_info_t(self.ql, kmod_info_addr) # OSKext.cpp:562 kmod_info.next = POINTER64(0) kmod_info.info_version = 1 kmod_info.id = 1 kmod_info.name = self.ql.loader.plist["CFBundleIdentifier"].encode( ) kmod_info.version = self.ql.loader.plist["CFBundleVersion"].encode( ) kmod_info.reference_count = 0 kmod_info.reference_list = POINTER64(0) kmod_info.address = POINTER64(self.ql.loader.slide) kmod_info.size = self.ql.loader.kext_size kmod_info.hdr_size = self.ql.loader.macho_file.header.header_size kmod_info.start = POINTER64(self.ql.loader.kext_start) kmod_info.stop = POINTER64(self.ql.loader.kext_stop) kmod_info.updateToMem() self.ql.log.debug("Initialized kmod_info") self.ql.arch.regs.rdi = kmod_info_addr self.ql.arch.regs.rsi = 0 self.savedrip = 0xffffff80009c2c16 self.ql.run(begin=self.ql.loader.kext_start)
def IOConnectCallMethod(ql, selector, input_array, input_cnt, input_struct, input_struct_size, output_array, output_cnt, output_struct, output_struct_size): if ql.os.IOKit is not True: ql.nprint("[!] Must have a IOKit driver") return output_array, output_struct args_addr = ql.os.heap.alloc(ctypes.sizeof(IOExternalMethodArguments)) ql.dprint(D_INFO, "[+] Created IOExternalMethodArguments object at 0x%x" % args_addr) args_obj = IOExternalMethodArguments(ql, args_addr) if input_array is not None and input_cnt != 0: input_array_addr = ql.os.heap.alloc(input_cnt) ql.mem.write(input_array_addr, b''.join(struct.pack("<Q", x) for x in input_array)) ql.dprint(D_INFO, "[+] Created input array at 0x%x" % input_array_addr) else: input_array_addr = 0 if input_struct is not None and input_struct_size != 0: input_struct_addr = ql.os.heap.alloc(input_struct_size) ql.mem.write(input_struct_addr, bytes(input_struct)) ql.dprint(D_INFO, "[+] Created input struct at 0x%x" % input_struct_addr) else: input_struct_addr = 0 if output_array is not None and output_cnt != 0: output_array_addr = ql.os.heap.alloc(output_cnt) ql.mem.write(output_array_addr, b''.join(struct.pack("<Q", x) for x in output_array)) ql.dprint(D_INFO, "[+] Created output array at 0x%x" % output_array_addr) else: output_array_addr = 0 if output_struct is not None and output_struct_size != 0: output_struct_addr = ql.os.heap.alloc(output_struct_size) ql.mem.write(output_struct_addr, bytes(output_struct)) ql.dprint(D_INFO, "[+] Created output struct at 0x%x" % output_struct_size) else: output_struct_addr = 0 dispatch_addr = ql.os.heap.alloc(ctypes.sizeof(IOExternalMethodDispatch)) ql.dprint(D_INFO, "[+] Created IOExternalMethodDispatch object at 0x%x" % dispatch_addr) dispatch_obj = IOExternalMethodDispatch(ql, dispatch_addr) args_obj.___reservedA = 0 args_obj._version = 2 args_obj._selector = selector args_obj._asyncWakePort = 0 args_obj._asyncReference = POINTER64(0) args_obj._asyncReferenceCount = 0 args_obj._structureVariableOutputData = POINTER64(0) args_obj._scalarInput = POINTER64(input_array_addr) args_obj._scalarInputCount = input_cnt args_obj._structureInput = POINTER64(input_struct_addr) args_obj._structureInputSize = input_struct_size # https://stackoverflow.com/questions/45432476/sending-iokit-command-with-dynamic-length args_obj._structureInputDescriptor = POINTER64(0) args_obj._structureOutputDescriptor = POINTER64(0) args_obj._structureOutputDescriptorSize = 0 args_obj._scalarOutput = POINTER64(output_array_addr) args_obj._scalarOutputCount = output_cnt args_obj._structureOutput = POINTER64(output_struct_addr) args_obj._structureOutputSize = output_struct_size args_obj.updateToMem() ql.dprint(D_INFO, "[+] Initialized IOExternalMethodArguments object") ql.os.savedrip=0xffffff8000a106ba ql.run(begin=ql.loader.user_alloc) ql.os.user_object = ql.reg.rax ql.dprint(D_INFO, "[+] Created user object at 0x%x" % ql.os.user_object) ql.reg.rdi = ql.os.user_object ql.reg.rsi = 0x1337 # owningTask ql.reg.rdx = 0 # securityID ql.reg.rcx = 0 # type ql.reg.r8 = 0 # properties ql.stack_push(0) ql.os.savedrip=0xffffff8000a10728 ql.run(begin=ql.loader.user_initWithTask) ql.dprint(D_INFO, "[+] Initialized user object") # TODO: Add some extra methods with correct order ql.reg.rdi = ql.os.user_object ql.reg.rsi = selector ql.reg.rdx = args_addr ql.reg.rcx = dispatch_addr ql.reg.r8 = ql.os.kext_object ql.reg.r9 = 0 ql.os.savedrip=0xffffff8000a6e9c7 ql.run(begin=ql.loader.user_externalMethod) args_obj.loadFromMem() output_array = args_obj.scalarOutput ql.dprint(D_INFO, "[+] Finish IOConnectCallMethod") return args_obj.scalarOutput, type(output_struct).from_buffer(args_obj.structureOutput)