Exemplo n.º 1
0
    def register_io_in(self):
        in_ioctl = x86.MultipleInstr()

        INPUT_BUFFER_PORT =  x86.mem('[ECX + 4]')
        INPUT_BUFFER_SIZE =  x86.mem('[ECX]')

        in_ioctl += x86.Cmp(self.IO_STACK_INPUT_BUFFER_LEN, 8)  # size indicator / port
        in_ioctl += x86.Jnz(":FAIL")
        in_ioctl += x86.Cmp(self.IO_STACK_OUPUT_BUFFER_LEN, 0x4)
        in_ioctl += x86.Jnz(":FAIL")
        in_ioctl += x86.Mov('ECX', self.IO_STACK_INPUT_BUFFER)
        in_ioctl += x86.Mov('EDX', INPUT_BUFFER_PORT)
        in_ioctl += x86.Mov('ECX', INPUT_BUFFER_SIZE)
        in_ioctl += x86.Xor('EAX', 'EAX')
        in_ioctl += x86.Cmp('ECX', 0x1)
        in_ioctl += x86.Jnz(":IN_2_OR_4")
        in_ioctl += x86.In('AL', 'DX')
        in_ioctl += x86.Jmp(':SUCCESS')
        in_ioctl += x86.Label(":IN_2_OR_4")
        in_ioctl += x86.Cmp('ECX', 0x2)
        in_ioctl += x86.Jnz(":IN_4")
        in_ioctl += x86.In('AX', 'DX')
        in_ioctl += x86.Jmp(':SUCCESS')
        in_ioctl += x86.Label(":IN_4")
        in_ioctl += x86.In('EAX', 'DX')
        in_ioctl += x86.Label(":SUCCESS")
        in_ioctl += x86.Mov('EDX', self.IRP_OUTPUT_BUFFER)
        in_ioctl += x86.Mov(x86.mem('[EDX]'), 'EAX')
        in_ioctl += x86.Xor('EAX', 'EAX')
        in_ioctl += x86.Ret()
        in_ioctl += x86.Label(":FAIL")
        in_ioctl += x86.Mov('EAX', 0x0C000000D)
        in_ioctl += x86.Ret()

        self.upgrade_driver_add_new_ioctl_handler(DU_IN_IOCTL, in_ioctl.get_code())
Exemplo n.º 2
0
    def register_io_out(self):
        out_ioctl = x86.MultipleInstr()

        INPUT_BUFFER_SIZE =  x86.mem('[ECX]')
        INPUT_BUFFER_PORT =  x86.mem('[ECX + 4]')
        INPUT_BUFFER_VALUE = x86.mem('[ECX + 8]')

        out_ioctl += x86.Cmp(self.IO_STACK_INPUT_BUFFER_LEN, 0xc)  # size indicator / port / value
        out_ioctl += x86.Jnz(":FAIL")
        out_ioctl +=    x86.Mov('ECX', self.IO_STACK_INPUT_BUFFER)
        out_ioctl +=    x86.Mov('EDX', INPUT_BUFFER_PORT)
        out_ioctl +=    x86.Mov('EAX', INPUT_BUFFER_VALUE)
        out_ioctl +=    x86.Mov('ECX', INPUT_BUFFER_SIZE)
        out_ioctl +=    x86.Cmp('ECX', 0x1)
        out_ioctl +=    x86.Jnz(":OUT_2_OR_4")
        out_ioctl +=    x86.Out('DX', 'AL')
        out_ioctl +=    x86.Jmp(':SUCCESS')
        out_ioctl +=    x86.Label(":OUT_2_OR_4")
        out_ioctl +=    x86.Cmp('ECX', 0x2)
        out_ioctl +=    x86.Jnz(":OUT_4")
        out_ioctl +=    x86.Out('DX', 'AX')
        out_ioctl +=    x86.Jmp(':SUCCESS')
        out_ioctl +=    x86.Label(":OUT_4")
        out_ioctl +=    x86.Out('DX', 'EAX')
        out_ioctl +=    x86.Label(":SUCCESS")
        out_ioctl +=    x86.Xor('EAX', 'EAX')
        out_ioctl +=    x86.Ret()
        out_ioctl += x86.Label(":FAIL")
        out_ioctl += x86.Mov('EAX', 0x0C000000D)
        out_ioctl += x86.Ret()

        self.upgrade_driver_add_new_ioctl_handler(DU_OUT_IOCTL, out_ioctl.get_code())
Exemplo n.º 3
0
    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())
Exemplo n.º 4
0
 def test_get_context_address_32(self, proc32):
     code = x86.MultipleInstr()
     code += x86.Mov("EAX", 0x42424242)
     code += x86.Label(":LOOP")
     code += x86.Jmp(":LOOP")
     t = proc32.execute(code.get_code())
     time.sleep(0.5)
     cont = t.context
     assert cont.Eax == 0x42424242
Exemplo n.º 5
0
    def _upgrade_driver_inject_base_upgrade(self):
        kldbgdrv = self.kldbgdrv
        upgrade = x86.MultipleInstr()
        IoControlCode_on_stack = x86.create_displacement(base='EBP', disp=-0x30)
        IO_STACK_LOCATION_on_stack = x86.create_displacement(base='EBP', disp=-0x34)
        IoStatus_on_stack = x86.create_displacement(base='EBP', disp=-0x3c)
        IRP_on_stack = x86.create_displacement(base='EBP', disp=+0x0c)

        upgrade += x86.Mov('EBX', IoControlCode_on_stack)
        upgrade += x86.Mov('EAX', x86.create_displacement(disp=kldbgdrv + self.HANDLE_ARRAY_ADDR))
        upgrade += x86.Label(":LOOP")
        upgrade +=      x86.Mov('ECX', x86.create_displacement('EAX'))
        upgrade +=      x86.Cmp('EBX', 'ECX')
        upgrade +=      x86.Jnz(':END')
        upgrade +=          x86.Mov('EAX', x86.create_displacement('EAX', disp=4))
        # ESI -> IO_STACK_LOCATION
        # EDI -> IRP
        upgrade +=          x86.Mov('ESI', IO_STACK_LOCATION_on_stack)
        upgrade +=          x86.Mov('EDI', IRP_on_stack)
        upgrade +=          x86.Call('EAX')
        upgrade +=          x86.Mov(IoStatus_on_stack, 'EAX')
        upgrade +=          x86.JmpAt(kldbgdrv + self.normal_end)
        upgrade +=      x86.Label(":END")
        upgrade +=      x86.Cmp('ECX', 0)
        upgrade +=      x86.Jnz(':NEXT')
        upgrade +=          x86.JmpAt(kldbgdrv + self.failed_offset)
        upgrade +=      x86.Label(":NEXT")
        upgrade +=      x86.Add('EAX', 8)
        upgrade += x86.Jmp(':LOOP')

        # Write new driver code
        self.kdbg.write_pfv_memory(kldbgdrv + self.init_function_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 + 4, 0)
        # Jump hijack
        jump_init_function = x86.Jmp(self.init_function_offset - (self.hijack_offset))
        self.kdbg.write_pfv_memory(kldbgdrv + self.hijack_offset, str(jump_init_function.get_code()))

        self.is_upgraded = True
        self.ioctl_array = kldbgdrv + self.FIRST_ARRAY_ADDR
        self.ioctl_array_ptr = kldbgdrv + self.HANDLE_ARRAY_ADDR
        self.next_code_addr = kldbgdrv + self.init_function_offset + len(upgrade.get_code())
Exemplo n.º 6
0
 def test_get_context_address_32(self):
     with Calc32() as calc:
         code = x86.MultipleInstr()
         code += x86.Mov("EAX", 0x42424242)
         code += x86.Label(":LOOP")
         code += x86.Jmp(":LOOP")
         t = calc.execute(code.get_code())
         time.sleep(0.5)
         cont = t.context
         self.assertEqual(cont.Eax, 0x42424242)
Exemplo n.º 7
0
    def test_set_thread_context_32(self, proc32):
        code =  x86.MultipleInstr()
        code += x86.Label(":LOOP")
        code += x86.Jmp(":LOOP")
        data_len = len(code.get_code())
        code += x86.Ret()

        t = proc32.execute(code.get_code())
        time.sleep(0.1)
        assert proc32.is_exit == False
        t.suspend()
        ctx = t.context
        ctx.Eip += data_len
        ctx.Eax = 0x11223344
        t.set_context(ctx)
        t.resume()
        time.sleep(0.1)
        assert t.exit_code == 0x11223344
Exemplo n.º 8
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
Exemplo n.º 9
0
 def is_driver_already_upgraded(self):
     """Check if the driver have already been upgraded by checking if the jump hijack is in place"""
     jump_hijack = x86.Jmp(self.init_function_offset - (self.hijack_offset)).get_code()
     mem = self.kdbg.read_virtual_memory(self.kldbgdrv + self.hijack_offset, len(jump_hijack))
     return mem == str(jump_hijack)
Exemplo n.º 10
0
    "EBX",
    x86.mem("[EAX + 0x18]"))  # EBX : first base ! (base of current module)
GetProcAddress32 += x86.Cmp("EBX", 0)
GetProcAddress32 += x86.Jz(":DLL_NOT_FOUND")
GetProcAddress32 += x86.Mov(
    "ECX", x86.mem("[EAX + 0x30]"))  # RCX = NAME (UNICODE_STRING.Buffer)
GetProcAddress32 += x86.Push("ECX")
GetProcAddress32 += x86.Call(":FUNC_STRLENW32")
GetProcAddress32 += x86.Pop("EDI")  # Current name
GetProcAddress32 += x86.Mov("ECX", "EAX")
GetProcAddress32 += x86.Mov("ESI", x86.mem("[ESP + 0x18]"))
GetProcAddress32 += x86.Rep + x86.CmpsW()
GetProcAddress32 += x86.Test("ECX", "ECX")
GetProcAddress32 += x86.Jz(":DLL_FOUND")
GetProcAddress32 += x86.Mov("EDX", x86.mem("[EDX]"))
GetProcAddress32 += x86.Jmp(":a_dest")
GetProcAddress32 += x86.Label(":DLL_FOUND")
GetProcAddress32 += x86.Mov("EAX", x86.mem("[EBX + 0x3c]"))  # rax = PEBASE RVA
GetProcAddress32 += x86.Add("EAX", "EBX")  # RAX = PEBASE
GetProcAddress32 += x86.Add("EAX", 0x18)  # ;OPTIONAL HEADER
GetProcAddress32 += x86.Mov("ECX",
                            x86.mem("[EAX + 0x60]"))  # ;ecx = RVA export dir
GetProcAddress32 += x86.Add("ECX", "EBX")  # ;ecx = export_dir
GetProcAddress32 += x86.Mov("EAX", "ECX")
GetProcAddress32 += x86.Push("EAX")  # Save it
# ; EBX = BASE | EAX = EXPORT DIR
GetProcAddress32 += x86.Mov("ECX", x86.mem("[EAX  + 24] "))
GetProcAddress32 += x86.Mov("EBP", "ECX")  # ;EBP = NB names
GetProcAddress32 += x86.Mov("EDX",
                            x86.mem("[EAX  + 32] "))  # EDX = names array RVA
GetProcAddress32 += x86.Add("EDX", "EBX")  #  RDX = names array