def generate_write_at(addr): res = x86.MultipleInstr() res += x86.Mov(x86.deref(addr), "EAX") res += x86.Ret() return res.get_code()
print("Allocating memory in our calc") addr = calc.virtual_alloc(0x1000) print("Allocated memory is at <{0}>".format(hex(addr))) print("Writing 'SOME STUFF' in allocated memory") calc.write_memory(addr, "SOME STUFF") print("Reading allocated memory : <{0}>".format(repr(calc.read_memory(addr, 20)))) # Remote Execution print("Execution some native code in our calc (write 0x424242 at allocated address + return 0x1337)") if calc.bitness == 32: # Let's generate some native code code = x86.MultipleInstr() code += x86.Mov(x86.deref(addr), 0x42424242) code += x86.Mov("EAX", 0x1337) code += x86.Ret() else: code = x64.MultipleInstr() code += x64.Mov('RAX', addr) code += x64.Mov(x64.mem("[RAX]"), 0x42424242) code += x64.Mov("RAX", 0x1337) code += x64.Ret() print("Executing native code !") t = calc.execute(code.get_code()) t.wait() print("Return code = {0}".format(hex(t.exit_code))) print("Reading allocated memory : <{0}>".format(repr(calc.read_memory(addr, 20))))
def generate_read_at(addr): res = x86.MultipleInstr() res += x86.Mov("EAX", x86.deref(addr)) res += x86.Ret() return res.get_code()
def trigger(self, dbg, exc): fault_addr = exc.ExceptionRecord.ExceptionInformation[1] eip = dbg.current_thread.context.pc print("Instruction at <{0:#x}> wrote at <{1:#x}>".format( eip, fault_addr)) dbg.single_step_counter = 4 return dbg.single_step() calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS) d = MyDebugger(calc) code = calc.virtual_alloc(0x1000) data = calc.virtual_alloc(0x1000) injected = x86.MultipleInstr() injected += x86.Mov("EAX", 0) injected += x86.Mov(x86.deref(data), "EAX") injected += x86.Add("EAX", 4) injected += x86.Mov(x86.deref(data + 4), "EAX") injected += x86.Add("EAX", 8) injected += x86.Mov(x86.deref(data + 8), "EAX") injected += x86.Nop() injected += x86.Nop() injected += x86.Ret() calc.write_memory(code, injected.get_code()) d.add_bp(SingleStepOnWrite(data, size=8, events="W")) calc.create_thread(code, 0) d.loop()
def trigger(self, dbg, exc): fault_addr = exc.ExceptionRecord.ExceptionInformation[1] eip = dbg.current_thread.context.pc print("Instruction at <{0:#x}> wrote at <{1:#x}>".format(eip, fault_addr)) dbg.single_step_counter = 4 return dbg.single_step() calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS) d = MyDebugger(calc) code = calc.virtual_alloc(0x1000) data = calc.virtual_alloc(0x1000) injected = x86.MultipleInstr() injected += x86.Mov("EAX", 0) injected += x86.Mov(x86.deref(data), "EAX") injected += x86.Add("EAX", 4) injected += x86.Mov(x86.deref(data + 4), "EAX") injected += x86.Add("EAX", 8) injected += x86.Mov(x86.deref(data + 8), "EAX") injected += x86.Nop() injected += x86.Nop() injected += x86.Ret() calc.write_memory(code, injected.get_code()) d.add_bp(SingleStepOnWrite(data, size=8, events="W")) calc.create_thread(code, 0) d.loop()
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
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
print("Allocating memory in our notepad") addr = notepad.virtual_alloc(0x1000) print("Allocated memory is at <{0}>".format(hex(addr))) print("Writing 'SOME STUFF' in allocated memory") notepad.write_memory(addr, "SOME STUFF") print("Reading allocated memory : <{0}>".format(repr(notepad.read_memory(addr, 20)))) # Remote Execution print("Execution some native code in our notepad (write 0x424242 at allocated address + return 0x1337)") if notepad.bitness == 32: # Let's generate some native code code = x86.MultipleInstr() code += x86.Mov(x86.deref(addr), 0x42424242) code += x86.Mov("EAX", 0x1337) code += x86.Ret() else: code = x64.MultipleInstr() code += x64.Mov('RAX', addr) code += x64.Mov(x64.mem("[RAX]"), 0x42424242) code += x64.Mov("RAX", 0x1337) code += x64.Ret() print("Executing native code !") t = notepad.execute(code.get_code()) t.wait() print("Return code = {0}".format(hex(t.exit_code))) print("Reading allocated memory : <{0}>".format(repr(notepad.read_memory(addr, 20))))