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 = x86.mem('[ECX]') INPUT_BUFFER_ALLOC_SIZE = x86.mem('[ECX + 4]') INPUT_BUFFER_ALLOC_TAG = x86.mem('[ECX + 8]') Alloc_IOCTL = x86.MultipleInstr() Alloc_IOCTL += x86.Cmp(self.IO_STACK_INPUT_BUFFER_LEN, 0xc) Alloc_IOCTL += x86.Jnz(':FAIL') Alloc_IOCTL += x86.Mov('ECX', self.IO_STACK_INPUT_BUFFER) Alloc_IOCTL += x86.Mov('EBX', INPUT_BUFFER_ALLOC_TAG) Alloc_IOCTL += x86.Push('EBX') Alloc_IOCTL += x86.Mov('EBX', INPUT_BUFFER_ALLOC_SIZE) Alloc_IOCTL += x86.Push('EBX') Alloc_IOCTL += x86.Mov('EBX', INPUT_BUFFER_ALLOC_TYPE) Alloc_IOCTL += x86.Push('EBX') Alloc_IOCTL += x86.Mov('EAX', ExAllocatePoolWithTag) Alloc_IOCTL += x86.Call('EAX') Alloc_IOCTL += x86.Mov('EDX', self.IRP_OUTPUT_BUFFER) Alloc_IOCTL += x86.Mov(x86.mem('[EDX]'), 'EAX') Alloc_IOCTL += x86.Xor('EAX', 'EAX') Alloc_IOCTL += x86.Ret() Alloc_IOCTL += x86.Label(":FAIL") Alloc_IOCTL += x86.Mov('EAX', 0x0C000000D) Alloc_IOCTL += x86.Ret() self.upgrade_driver_add_new_ioctl_handler(DU_MEMALLOC_IOCTL, Alloc_IOCTL.get_code())
def perform_manual_getproc_loadlib_32_for_dbg(target, dll_name): dll = "KERNEL32.DLL\x00".encode("utf-16-le") api = "LoadLibraryA\x00" dll_to_load = dll_name + "\x00" RemoteManualLoadLibray = x86.MultipleInstr() code = RemoteManualLoadLibray code += x86.Mov("ECX", x86.mem("[ESP + 4]")) code += x86.Push(x86.mem("[ECX + 4]")) code += x86.Push(x86.mem("[ECX]")) code += x86.Call(":FUNC_GETPROCADDRESS32") code += x86.Push(x86.mem("[ECX + 8]")) code += x86.Call("EAX") # LoadLibrary code += x86.Pop("ECX") code += x86.Pop("ECX") code += x86.Ret() RemoteManualLoadLibray += nativeutils.GetProcAddress32 addr = target.virtual_alloc(0x1000) addr2 = addr + len(dll) addr3 = addr2 + len(api) addr4 = addr3 + len(dll_to_load) target.write_memory(addr, dll) target.write_memory(addr2, api) target.write_memory(addr3, dll_to_load) target.write_qword(addr4, addr) target.write_qword(addr4 + 4, addr2) target.write_qword(addr4 + 0x8, addr3) t = target.execute(RemoteManualLoadLibray.get_code(), addr4) return t
def register_kernel_call(self): # expect in buffer: the address to call and all dword to push on the stack CCall_IOCTL = x86.MultipleInstr() CCall_IOCTL += x86.Mov('EAX', self.IO_STACK_INPUT_BUFFER_LEN) CCall_IOCTL += x86.Cmp('EAX', 0) CCall_IOCTL += x86.Jz(":FAIL") # Need at least the function to call CCall_IOCTL += x86.Mov('ECX', self.IO_STACK_INPUT_BUFFER) CCall_IOCTL += x86.Label(':PUSH_NEXT_ARG') CCall_IOCTL += x86.Cmp('EAX', 4) CCall_IOCTL += x86.Jz(":DO_CALL") CCall_IOCTL += x86.Sub('EAX', 4) INPUT_BUFFER_NEXT_ARG = x86.create_displacement(base='ECX', index='EAX') CCall_IOCTL += x86.Mov('EBX', INPUT_BUFFER_NEXT_ARG) CCall_IOCTL += x86.Push('EBX') CCall_IOCTL += x86.Jmp(':PUSH_NEXT_ARG') CCall_IOCTL += x86.Label(":DO_CALL") CCall_IOCTL += x86.Mov('EAX', x86.mem('[ECX]')) CCall_IOCTL += x86.Call('EAX') CCall_IOCTL += x86.Mov('EDX', self.IRP_OUTPUT_BUFFER) CCall_IOCTL += x86.Mov(x86.mem('[EDX]'), 'EAX') CCall_IOCTL += x86.Xor('EAX', 'EAX') CCall_IOCTL += x86.Ret() CCall_IOCTL += x86.Label(":FAIL") CCall_IOCTL += x86.Mov('EAX', 0x0C000000D) CCall_IOCTL += x86.Ret() self.upgrade_driver_add_new_ioctl_handler(DU_KCALL_IOCTL, CCall_IOCTL.get_code())
for library in imports.keys(): lib = binary32.add_library(library) for function in imports[library].keys(): lib.add_entry(function) for library in imports.keys(): for function in imports[library].keys(): imports[library][function] = binary32.predict_function_rva( library, function) + binary32.optional_header.imagebase code = x86.MultipleInstr() code += x86.Mov("EBP", "ESP") code += x86.Sub("ESP", 0x100) # GetStdHandle(STD_OUTPUT_HANDLE) code += x86.Push(STD_OUTPUT_HANDLE) code += x86.Call(call_import(imports["kernel32.dll"]["GetStdHandle"])) # WriteFile(eax, welcome, len_welcome, &esp+8, 0) code += x86.Lea("EDI", x86.mem("[ESP + 0x8]")) code += x86.Push(0) code += x86.Push("EDI") code += x86.Push(len(welcome)) code += x86.Push(data[welcome]) code += x86.Push("EAX") # hConsoleOutput code += x86.Call(call_import(imports["kernel32.dll"]["WriteFile"])) # GetStdHandle(STD_INPUT_HANDLE) code += x86.Push(STD_INPUT_HANDLE) code += x86.Call(call_import(imports["kernel32.dll"]["GetStdHandle"])) # ReadFile(eax, &esp+80, 0x50, &esp+8, 0) code += x86.Lea("EBX", x86.mem("[ESP + 0x80]")) code += x86.Push(0)
def hook_ntcreatefile(kdbg, ignore_jump_space_check=False): """Hook NtCreateFile, the hook write the filename to a shared memory page""" nt_create_file = kdbg.resolve_symbol("nt!NtCreateFile") if not ignore_jump_space_check: # Check that function begin with mov edi, edi for the hook short jump if kdbg.read_word(nt_create_file) != 0xff8b: # mov edi, edi print(hex(kdbg.read_word(nt_create_file))) raise ValueError( "Cannot hook fonction that doest not begin with <mov edi,edi> (/f to force if hook already in place)" ) # Check there is 5 bytes free before for the hook long jump if kdbg.read_virtual_memory(nt_create_file - 5, 5) not in ["\x90" * 5, "\xCC" * 5 ]: #NOP * 5 ; INT 3 * 5 print(kdbg.read_virtual_memory(nt_create_file - 5, 5)) raise ValueError( "Cannot hook fonction that is not prefixed with 5 nop/int 3") # Allocate memory for the shared buffer kernel<->user # the format is: # [addr] -> size of size already taken # then: # DWORD string_size # char[string_size] filename data_kernel_addr = kdbg.alloc_memory(0x1000) kdbg.write_pfv_memory(data_kernel_addr, "\x00" * 0x1000) # Map the shared buffer to userland data_user_addr = kdbg.map_page_to_userland(data_kernel_addr, 0x1000) # Allocate memory for the hook shellcode_addr = kdbg.alloc_memory(0x1000) # shellcode shellcode = x86.MultipleInstr() # Save register shellcode += x86.Push('EAX') shellcode += x86.Push('ECX') shellcode += x86.Push('EDI') shellcode += x86.Push('ESI') # Check that there is space remaining, else don't write it shellcode += x86.Cmp(x86.deref(data_kernel_addr), 0x900) shellcode += x86.Jnb(":END") # Get 3rd arg (POBJECT_ATTRIBUTES ObjectAttributes) shellcode += x86.Mov('EAX', x86.mem('[ESP + 0x1c]')) # 0xc + 0x10 for push # Get POBJECT_ATTRIBUTES.ObjectName (PUNICODE_STRING) shellcode += x86.Mov('EAX', x86.mem('[EAX + 0x8]')) shellcode += x86.Xor('ECX', 'ECX') # Get PUNICODE_STRING.Length shellcode += x86.Mov('CX', x86.mem('[EAX + 0]')) # Get PUNICODE_STRING.Buffer shellcode += x86.Mov('ESI', x86.mem('[EAX + 4]')) # Get the next free bytes in shared buffer shellcode += x86.Mov('EDI', data_kernel_addr + 4) shellcode += x86.Add('EDI', x86.deref(data_kernel_addr)) # Write (DWORD string_size) in our 'struct' shellcode += x86.Mov(x86.mem('[EDI]'), 'ECX') # update size taken in shared buffer shellcode += x86.Add(x86.deref(data_kernel_addr), 'ECX') shellcode += x86.Add(x86.deref(data_kernel_addr), 4) # Write (char[string_size] filename) in our 'struct' shellcode += x86.Add('EDI', 4) shellcode += x86.Rep + x86.Movsb() shellcode += x86.Label(":END") # Restore buffer shellcode += x86.Pop('ESI') shellcode += x86.Pop('EDI') shellcode += x86.Pop('ECX') shellcode += x86.Pop('EAX') # Jump to NtCreateFile shellcode += x86.JmpAt(nt_create_file + 2) # Write shellcode kdbg.write_pfv_memory(shellcode_addr, shellcode.get_code()) long_jump = x86.Jmp(shellcode_addr - (nt_create_file - 5)) # Write longjump to shellcode kdbg.write_pfv_memory(nt_create_file - 5, long_jump.get_code()) # Write shortjump NtCreateFile -> longjump short_jmp = x86.Jmp(-5) kdbg.write_pfv_memory(nt_create_file, short_jmp.get_code()) # Return address of shared buffer in userland return data_user_addr
GetProcAddress64 += x64.Label(":DLL_NOT_FOUND") GetProcAddress64 += x64.Mov("RAX", 0xfffffffffffffffe) GetProcAddress64 += x64.Jmp(":RETURN") GetProcAddress64 += x64.Label(":API_NOT_FOUND") GetProcAddress64 += x64.Pop("RAX") GetProcAddress64 += x64.Mov("RAX", 0xffffffffffffffff) GetProcAddress64 += x64.Jmp(":RETURN") # Ajout des dependances GetProcAddress64 += StrlenW64 GetProcAddress64 += StrlenA64 ###### 32 bits ####### StrlenW32 = x86.MultipleInstr() StrlenW32 += x86.Label(":FUNC_STRLENW32") StrlenW32 += x86.Push("EDI") StrlenW32 += x86.Mov("EDI", x86.mem("[ESP + 8]")) StrlenW32 += x86.Push("ECX") StrlenW32 += x86.Xor("EAX", "EAX") StrlenW32 += x86.Xor("ECX", "ECX") StrlenW32 += x86.Dec("ECX") StrlenW32 += x86.Repne + x86.ScasW() StrlenW32 += x86.Not("ECX") StrlenW32 += x86.Dec("ECX") StrlenW32 += x86.Mov("EAX", "ECX") StrlenW32 += x86.Pop("ECX") StrlenW32 += x86.Pop("EDI") StrlenW32 += x86.Ret() StrlenA32 = x86.MultipleInstr() StrlenA32 += x86.Label(":FUNC_STRLENA32")