def register_io_in(self): in_ioctl = x64.MultipleInstr() INPUT_BUFFER_SIZE = x64.mem('[RCX]') INPUT_BUFFER_PORT = x64.mem('[RCX + 8]') in_ioctl += x64.Cmp(self.IO_STACK_INPUT_BUFFER_LEN, 0x10) # size indicator / port in_ioctl += x64.Jnz(":FAIL") in_ioctl += x64.Mov('RCX', self.IO_STACK_INPUT_BUFFER) in_ioctl += x64.Mov('RDX', INPUT_BUFFER_PORT) in_ioctl += x64.Mov('RCX', INPUT_BUFFER_SIZE) in_ioctl += x64.Cmp('RCX', 0x1) in_ioctl += x64.Jnz(":OUT_2_OR_4") in_ioctl += x64.In('AL', 'DX') in_ioctl += x64.Jmp(':SUCCESS') in_ioctl += x64.Label(":OUT_2_OR_4") in_ioctl += x64.Cmp('RCX', 0x2) in_ioctl += x64.Jnz(":OUT_4") in_ioctl += x64.In('AX', 'DX') in_ioctl += x64.Jmp(':SUCCESS') in_ioctl += x64.Label(":OUT_4") in_ioctl += x64.In('EAX', 'DX') in_ioctl += x64.Label(":SUCCESS") in_ioctl += x64.Mov('RDX', self.IRP_OUTPUT_BUFFER) in_ioctl += x64.Mov(x64.mem('[RDX]'), 'RAX') in_ioctl += x64.Xor('RAX', 'RAX') in_ioctl += x64.Ret() in_ioctl += x64.Label(":FAIL") in_ioctl += x64.Mov('RAX', 0x0C000000D) in_ioctl += x64.Ret() self.upgrade_driver_add_new_ioctl_handler(DU_IN_IOCTL, in_ioctl.get_code())
def register_io_out(self): out_ioctl = x64.MultipleInstr() INPUT_BUFFER_SIZE = x64.mem('[RCX]') INPUT_BUFFER_PORT = x64.mem('[RCX + 8]') INPUT_BUFFER_VALUE = x64.mem('[RCX + 0x10]') out_ioctl += x64.Cmp(self.IO_STACK_INPUT_BUFFER_LEN, 0x18) # size indicator / port / value out_ioctl += x64.Jnz(":FAIL") out_ioctl += x64.Mov('RCX', self.IO_STACK_INPUT_BUFFER) out_ioctl += x64.Mov('RDX', INPUT_BUFFER_PORT) out_ioctl += x64.Mov('RAX', INPUT_BUFFER_VALUE) out_ioctl += x64.Mov('RCX', INPUT_BUFFER_SIZE) out_ioctl += x64.Cmp('RCX', 0x1) out_ioctl += x64.Jnz(":OUT_2_OR_4") out_ioctl += x64.Out('DX', 'AL') out_ioctl += x64.Jmp(':SUCCESS') out_ioctl += x64.Label(":OUT_2_OR_4") out_ioctl += x64.Cmp('RCX', 0x2) out_ioctl += x64.Jnz(":OUT_4") out_ioctl += x64.Out('DX', 'AX') out_ioctl += x64.Jmp(':SUCCESS') out_ioctl += x64.Label(":OUT_4") out_ioctl += x64.Out('DX', 'EAX') out_ioctl += x64.Label(":SUCCESS") out_ioctl += x64.Xor('RAX', 'RAX') out_ioctl += x64.Ret() out_ioctl += x64.Label(":FAIL") out_ioctl += x64.Mov('RAX', 0x0C000000D) out_ioctl += x64.Ret() self.upgrade_driver_add_new_ioctl_handler(DU_OUT_IOCTL, out_ioctl.get_code())
def register_alloc_memory(self): ExAllocatePoolWithTag = self.kdbg.get_symbol_offset("nt!ExAllocatePoolWithTag") if ExAllocatePoolWithTag is None: raise ValueError("Could not resolve <ExAllocatePoolWithTag>") INPUT_BUFFER_ALLOC_TYPE = x64.mem('[RCX]') INPUT_BUFFER_ALLOC_SIZE = x64.mem('[RCX + 0x8]') INPUT_BUFFER_ALLOC_TAG = x64.mem('[RCX + 0x10]') Alloc_IOCTL = x64.MultipleInstr() Alloc_IOCTL += x64.Cmp(self.IO_STACK_INPUT_BUFFER_LEN, 0x18) Alloc_IOCTL += x64.Jnz(':FAIL') Alloc_IOCTL += x64.Mov('RCX', self.IO_STACK_INPUT_BUFFER) Alloc_IOCTL += x64.Mov('R8', INPUT_BUFFER_ALLOC_TAG) Alloc_IOCTL += x64.Mov('RDX', INPUT_BUFFER_ALLOC_SIZE) Alloc_IOCTL += x64.Mov('RCX', INPUT_BUFFER_ALLOC_TYPE) Alloc_IOCTL += x64.Mov('RAX', ExAllocatePoolWithTag) Alloc_IOCTL += x64.Call('RAX') Alloc_IOCTL += x64.Mov('RBX', self.IRP_OUTPUT_BUFFER) Alloc_IOCTL += x64.Mov(x64.mem('[RBX]'), 'RAX') Alloc_IOCTL += x64.Xor('RAX', 'RAX') Alloc_IOCTL += x64.Ret() Alloc_IOCTL += x64.Label(":FAIL") Alloc_IOCTL += x64.Mov('RAX', 0x0C000000D) Alloc_IOCTL += x64.Ret() self.upgrade_driver_add_new_ioctl_handler(DU_MEMALLOC_IOCTL, Alloc_IOCTL.get_code())
def _upgrade_driver_inject_base_upgrade(self): kldbgdrv = self.kldbgdrv upgrade = x64.MultipleInstr() # R14 : IOCODE # RSI -> IO_STACK_LOCATION # RDI -> IRP upgrade = x64.MultipleInstr() upgrade += x64.Cmp('R14', self.NORMAL_IO_CODE) upgrade += x64.Jz(self.normal_io_offset - (self.init_driver_offset + len(upgrade.get_code()))) upgrade += x64.Mov('Rax', x64.create_displacement(disp=kldbgdrv + self.HANDLE_ARRAY_ADDR)) upgrade += x64.Label(":LOOP") upgrade += x64.Mov('RCX', x64.create_displacement('RAX')) upgrade += x64.Cmp('R14', 'RCX') upgrade += x64.Jnz(':END') upgrade += x64.Mov('RAX', x64.create_displacement('RAX', disp=8)) upgrade += x64.Call('RAX') upgrade += x64.Mov('RBX', 'RAX') upgrade += x64.JmpAt(kldbgdrv + self.normal_end_offset) upgrade += x64.Label(":END") upgrade += x64.Cmp('RCX', 0) upgrade += x64.Jnz(':NEXT') upgrade += x64.JmpAt(kldbgdrv + self.fail_offset) upgrade += x64.Label(":NEXT") upgrade += x64.Add('RAX', 0x10) upgrade += x64.Jmp(':LOOP') self.kdbg.write_pfv_memory(kldbgdrv + self.init_driver_offset, str(upgrade.get_code())) # Write first array dest self.write_pfv_ptr(kldbgdrv + self.HANDLE_ARRAY_ADDR, kldbgdrv + self.FIRST_ARRAY_ADDR) self.write_pfv_ptr(kldbgdrv + self.FIRST_ARRAY_ADDR, 0) self.write_pfv_ptr(kldbgdrv + self.FIRST_ARRAY_ADDR + 8, 0) # Jump hijack jump_init_function = x64.Jmp(self.init_driver_offset - (self.hijack_offset)) self.kdbg.write_pfv_memory(kldbgdrv + self.hijack_offset, str(jump_init_function.get_code())) self.ioctl_array = kldbgdrv + self.FIRST_ARRAY_ADDR self.ioctl_array_ptr = kldbgdrv + self.HANDLE_ARRAY_ADDR self.next_code_addr = kldbgdrv + self.init_driver_offset + len(upgrade.get_code()) self.is_upgraded = True
def register_kernel_call(self): # expect in buffer: the address to call and all dword to push on the stack CCall_IOCTL = x64.MultipleInstr() CCall_IOCTL += x64.Mov('RAX', self.IO_STACK_INPUT_BUFFER_LEN) CCall_IOCTL += x64.Cmp('RAX', 0) CCall_IOCTL += x64.Jz(":FAIL") # Need at least the function to call CCall_IOCTL += x64.Mov('R15', 4 * 8) # Size to pop on the stack at the end (4 * push RDI) CCall_IOCTL += x64.Mov('R10', self.IO_STACK_INPUT_BUFFER) CCall_IOCTL += x64.Label(':PUSH_NEXT_ARG') CCall_IOCTL += x64.Cmp('RAX', (8 * 5)) CCall_IOCTL += x64.Jbe(":SETUP_REG_ARGS") CCall_IOCTL += x64.Sub('RAX', 8) INPUT_BUFFER_NEXT_ARG = x64.create_displacement(base='R10', index='RAX') CCall_IOCTL += x64.Mov('RBX', INPUT_BUFFER_NEXT_ARG) CCall_IOCTL += x64.Push('RBX') CCall_IOCTL += x64.Add('R15', 8) # Add at Size to pop on the stack at the end CCall_IOCTL += x64.Jmp(':PUSH_NEXT_ARG') CCall_IOCTL += x64.Label(":SETUP_REG_ARGS") # Could be done in a loop # But do I really want to generate x86 in a loop.. CCall_IOCTL += x64.Cmp('RAX', (8 * 5)) CCall_IOCTL += x64.Jz(":SETUP_4_ARGS") CCall_IOCTL += x64.Cmp('RAX', (8 * 4)) CCall_IOCTL += x64.Jz(":SETUP_3_ARGS") CCall_IOCTL += x64.Cmp('RAX', (8 * 3)) CCall_IOCTL += x64.Jz(":SETUP_2_ARGS") CCall_IOCTL += x64.Cmp('RAX', (8 * 2)) CCall_IOCTL += x64.Jz(":SETUP_1_ARGS") CCall_IOCTL += x64.Jmp(":SETUP_0_ARGS") CCall_IOCTL += x64.Label(":SETUP_4_ARGS") CCall_IOCTL += x64.Mov('R9', x64.mem('[R10 + 0x20]')) CCall_IOCTL += x64.Label(":SETUP_3_ARGS") CCall_IOCTL += x64.Mov('R8', x64.mem('[R10 + 0x18]')) CCall_IOCTL += x64.Label(":SETUP_2_ARGS") CCall_IOCTL += x64.Mov('RDX', x64.mem('[R10 + 0x10]')) CCall_IOCTL += x64.Label(":SETUP_1_ARGS") CCall_IOCTL += x64.Mov('RCX', x64.mem('[R10 + 8]')) CCall_IOCTL += x64.Label(":SETUP_0_ARGS") CCall_IOCTL += x64.Mov('RAX', x64.mem('[R10]')) # Fix Reserve space (calling convention) CCall_IOCTL += x64.Push('RDI') CCall_IOCTL += x64.Push('RDI') CCall_IOCTL += x64.Push('RDI') CCall_IOCTL += x64.Push('RDI') CCall_IOCTL += x64.Call('RAX') CCall_IOCTL += x64.Mov('RDX', self.IRP_OUTPUT_BUFFER) CCall_IOCTL += x64.Mov(x64.mem('[RDX]'), 'RAX') CCall_IOCTL += x64.Xor('RAX', 'RAX') CCall_IOCTL += x64.Add('RSP', 'R15') CCall_IOCTL += x64.Ret() CCall_IOCTL += x64.Label(":FAIL") CCall_IOCTL += x64.Mov('RAX', 0x0C000000D) CCall_IOCTL += x64.Ret() self.upgrade_driver_add_new_ioctl_handler(DU_KCALL_IOCTL, CCall_IOCTL.get_code())
GetProcAddress64 += x64.Mov("R11", "RCX") GetProcAddress64 += x64.Mov("R12", "RDX") GetProcAddress64 += x64.Mov("RAX", x64.mem("GS:[0x60]")) #PEB ! GetProcAddress64 += x64.Mov( "RAX", x64.mem("[RAX + 24] ")) # ; RAX = ldr (+ 6 for 64 cause of 2 ptr) GetProcAddress64 += x64.Mov( "RAX", x64.mem("[RAX + 32]")) # ; RAX on the first elt of the list (first module) GetProcAddress64 += x64.Mov("RDX", "RAX") GetProcAddress64 += x64.Label(":a_dest") GetProcAddress64 += x64.Mov("RAX", "RDX") GetProcAddress64 += x64.Mov( "RBX", x64.mem("[RAX + 32]")) # RBX : first base ! (base of current module) #GetProcAddress64 += x64.Mov("RBX ", x64.mem("[RAX + 32]")) # RBX : first base ! (base of current module) GetProcAddress64 += x64.Cmp("RBX", 0) GetProcAddress64 += x64.Jz(":DLL_NOT_FOUND") GetProcAddress64 += x64.Mov( "RCX", x64.mem("[RAX + 80]")) # RCX = NAME (UNICODE_STRING.Buffer) GetProcAddress64 += x64.Call(":FUNC_STRLENW64") GetProcAddress64 += x64.Mov("RDI", "RCX") GetProcAddress64 += x64.Mov("RCX", "RAX") GetProcAddress64 += x64.Mov("RSI", "R11") GetProcAddress64 += x64.Rep + x64.CmpsW( ) #;cmp with current dll name (unicode) GetProcAddress64 += x64.Test("RCX", "RCX") GetProcAddress64 += x64.Jz(":DLL_FOUND") GetProcAddress64 += x64.Mov("RDX", x64.mem("[RDX]")) GetProcAddress64 += x64.Jmp(":a_dest") GetProcAddress64 += x64.Label(":DLL_FOUND") # here rbx = base GetProcAddress64 += x64.Mov("EAX", x64.mem("[RBX + 60]")) # rax = PEBASE RVA