Example #1
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())
Example #2
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())
Example #3
0
    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())
Example #4
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())
Example #5
0
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
Example #6
0
 def get_peb_addr(self):
     dest = self.virtual_alloc(0x1000)
     if self.bitness == 32:
         store_peb = x86.MultipleInstr()
         store_peb += x86.Mov('EAX', x86.mem('fs:[0x30]'))
         store_peb += x86.Mov(x86.create_displacement(disp=dest), 'EAX')
         store_peb += x86.Ret()
         get_peb_code = store_peb.get_code()
         self.write_memory(dest, "\x00" * 4)
         self.write_memory(dest + 4, get_peb_code)
         self.create_thread(dest + 4, 0)
         time.sleep(0.01)
         peb_addr = struct.unpack("<I", self.read_memory(dest, 4))[0]
         return peb_addr
     else:
         store_peb = x64.MultipleInstr()
         store_peb += x64.Mov('RAX', x64.mem('gs:[0x60]'))
         store_peb += x64.Mov(x64.create_displacement(disp=dest), 'RAX')
         store_peb += x64.Ret()
         get_peb_code = store_peb.get_code()
         self.write_memory(dest, "\x00" * 8)
         self.write_memory(dest + 8, get_peb_code)
         self.create_thread(dest + 8, 0)
         time.sleep(0.01)
         peb_addr = struct.unpack("<Q", self.read_memory(dest, 8))[0]
         return peb_addr
Example #7
0
 def get_peb_addr(self):
     dest = self.virtual_alloc(0x1000)
     if self.bitness == 32:
         store_peb = x86.MultipleInstr()
         store_peb += x86.Mov('EAX', x86.mem('fs:[0x30]'))
         store_peb += x86.Mov(x86.create_displacement(disp=dest), 'EAX')
         store_peb += x86.Ret()
         get_peb_code = store_peb.get_code()
         self.write_memory(dest, "\x00" * 4)
         self.write_memory(dest + 4, get_peb_code)
         self.create_thread(dest + 4, 0)
         time.sleep(0.01)
         peb_addr = struct.unpack("<I", self.read_memory(dest, 4))[0]
         return peb_addr
     else:
         store_peb = x64.MultipleInstr()
         store_peb += x64.Mov('RAX', x64.mem('gs:[0x60]'))
         store_peb += x64.Mov(x64.create_displacement(disp=dest), 'RAX')
         store_peb += x64.Ret()
         get_peb_code = store_peb.get_code()
         self.write_memory(dest, "\x00" * 8)
         self.write_memory(dest + 8, get_peb_code)
         self.create_thread(dest + 8, 0)
         time.sleep(0.01)
         peb_addr = struct.unpack("<Q", self.read_memory(dest, 8))[0]
         return peb_addr
Example #8
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from lief import PE
import windows.native_exec.simple_x86 as x86
from windows.generated_def import STD_OUTPUT_HANDLE, STD_INPUT_HANDLE

tobytes = lambda x: list(map(ord, x))
fmt_call = lambda addr: "[0x{:X}]".format(addr)
call_import = lambda addr: x86.mem(fmt_call(addr))

welcome = "Welcome to the pwn challenge!\r\n\tLIEF is awesome\r\n"
test = "cmd.exe\0"

imports = {
    "kernel32.dll": {
        "GetStdHandle": 0,
        "WriteFile": 0,
        "ReadFile": 0,
        "WinExec": 0,
    },
}

data = {
    welcome: 0,
    test: 0,
}

binary32 = PE.Binary("pwn.exe", PE.PE_TYPE.PE32)

# Start with 0x100 bytes of \cc
Example #9
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
Example #10
0
class DriverUpgrader32(DriverUpgrader):
    """Upgrader for windbg_driver_x86.sys (sha-1 D766D6393C3BEC3D4AB1568D373B565BB85EB665)

    Explanation:

        the function `upgrade_driver` will add some code to the DeviceIoControl handler
        The added code will replace the code of the driver initialisation

        The new code search the IoControlCode in an array of IOCODE/Handler and call
        the corresponding handler with the following parameters:

            ESI -> IO_STACK_LOCATION that contains:
                : The input buffer size
                : The input buffer
                : The output buffer size

            EDI -> IRP that contains:
                : The output buffer

            The handler must:
                - Verify the size of input / output buffer
                - Do whatever it wants
                - Write the returned values in the output buffer
                - Return 0 if everything went well
                - Return an error code otherwise

        Adding a new handler is simple, we just need to add the IOCODE/HANDLER to the handler array.
        It can be done by calling:

            self.upgrade_driver_add_new_ioctl_handler(IOCODE, HANDLER_CODE)
    """
    PTR_SIZE = 4
    # Offset of the function we will rewrite in the driver
    init_function_offset = 0xD10
    # Offset of the jump in the iohandle that we will hijack
    hijack_offset = 0xb1f
    # Offset to the `fail` function end
    failed_offset = 0xC2B
    # Offset to `success` function end
    normal_end = 0xC32
    # Address of the pointer to the IOCODE/HANDLER array
    HANDLE_ARRAY_ADDR = 0xCBA
    FIRST_ARRAY_ADDR = HANDLE_ARRAY_ADDR + 4

    # Memory access often used in new handler: based on the parameters expected
    IO_STACK_OUPUT_BUFFER_LEN = x86.mem('[ESI + 4]')
    IO_STACK_INPUT_BUFFER_LEN = x86.mem('[ESI + 8]')
    IO_STACK_INPUT_BUFFER =     x86.mem('[ESI + 0x10]')
    IRP_OUTPUT_BUFFER =         x86.mem('[EDI + 0x3c]')

    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())

    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)

    def full_driver_upgrade(self):
        """Upgrade the driver, bootstrap it and add new features

            We don't want to write all the handler in the driver init code.
            We bootstrap by only adding the `mem_alloc` feature and use it to:
                - Alloc a new page for the IOCODE/HANDLER array
                - Alloc a new page for the handlers code
            We move the IOCODE/HANDLER array
            Finally we add the other features
        """
        self._upgrade_driver_inject_base_upgrade()
        self.register_alloc_memory()
        new_ioctl_array_page = self.kdbg.alloc_memory(0x1000)

        alloc_ioctl, alloc_code_addr = self.registered_ioctl[0]
        # Write first array dest
        self.write_pfv_ptr(self.ioctl_array_ptr, new_ioctl_array_page)
        self.write_pfv_ptr(new_ioctl_array_page, alloc_ioctl)
        self.write_pfv_ptr(new_ioctl_array_page + 4, alloc_code_addr)
        self.write_pfv_ptr(new_ioctl_array_page + 8, 0)
        self.write_pfv_ptr(new_ioctl_array_page + 0xc, 0)

        self.ioctl_array = new_ioctl_array_page
        new_code_page = self.kdbg.alloc_memory(0x1000)
        self.next_code_addr = new_code_page
        # Register other ioctl
        self.register_kernel_call()
        self.register_io_in()
        self.register_io_out()

    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 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())

    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())

    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())
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")
StrlenA32 += x86.Push("EDI")
Example #12
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
Example #13
0
class CurrentProcess(Process):
    """The current process"""
    get_peb = None

    get_peb_32_code = x86.MultipleInstr()
    get_peb_32_code += x86.Mov('EAX', x86.mem('fs:[0x30]'))
    get_peb_32_code += x86.Ret()
    get_peb_32_code = get_peb_32_code.get_code()

    get_peb_64_code = x64.MultipleInstr()
    get_peb_64_code += x64.Mov('RAX', x64.mem('gs:[0x60]'))
    get_peb_64_code += x64.Ret()
    get_peb_64_code = get_peb_64_code.get_code()

    allocator = native_exec.native_function.allocator

    # Use RtlGetCurrentPeb ?
    def get_peb_builtin(self):
        if self.get_peb is not None:
            return self.get_peb
        if self.bitness == 32:
            get_peb = native_exec.create_function(self.get_peb_32_code, [PVOID])
        else:
            get_peb = native_exec.create_function(self.get_peb_64_code, [PVOID])
        self.get_peb = get_peb
        return get_peb

    def _get_handle(self):
        return winproxy.GetCurrentProcess()

    def __del__(self):
        pass

    @property
    def pid(self):
        """Process ID

        :type: :class:`int`
		"""
        return os.getpid()

    # Is there a better way ?
    @utils.fixedpropety
    def ppid(self):
        """Parent Process ID

        :type: :class:`int`
		"""
        return [p for p in windows.system.processes if p.pid == self.pid][0].ppid

    @utils.fixedpropety
    def peb(self):
        """The Process Environment Block of the current process

        :type: :class:`PEB`
		"""
        return PEB.from_address(self.get_peb_builtin()())

    @utils.fixedpropety
    def bitness(self):
        """The bitness of the process

        :type: :class:`int` -- 32 or 64
		"""
        import platform
        bits = platform.architecture()[0]
        return int(bits[:2])

    def virtual_alloc(self, size, prot=PAGE_EXECUTE_READWRITE):
        """Allocate memory in the process

        :return: The address of the allocated memory
        :rtype: :class:`int`
		"""
        return winproxy.VirtualAlloc(dwSize=size, flProtect=prot)

    def virtual_free(self, addr):
        """Free memory in the process by virtual_alloc"""
        return winproxy.VirtualFree(addr)

    def write_memory(self, addr, data):
        """Write data at addr"""
        buffertype = (c_char * len(data)).from_address(addr)
        buffertype[:len(data)] = data
        return True

    def read_memory(self, addr, size):
        """Read ``size`` from ``addr``

        :return: The data read
        :rtype: :class:`str`
		"""
        dbgprint('Read CurrentProcess Memory', 'READMEM')
        buffer = (c_char * size).from_address(addr)
        return buffer[:]

    def create_thread(self, lpStartAddress, lpParameter, dwCreationFlags=0):
        """Create a new thread

        :rtype: :class:`WinThread` or :class:`DeadThread`
		"""
        handle = winproxy.CreateThread(lpStartAddress=lpStartAddress, lpParameter=lpParameter, dwCreationFlags=dwCreationFlags)
        return WinThread._from_handle(handle)

    def execute(self, code, parameter=0):
        """Execute native code ``code`` in the current thread.

        :rtype: :class:`int` the return value of the native code"""
        f = windows.native_exec.create_function(code, [PVOID, PVOID])
        return f(parameter)

    def exit(self, code=0):
        """Exit the process"""
        return winproxy.ExitProcess(code)

    def wait(self, timeout=INFINITE):
        """Raise :class:`ValueError` to prevent deadlock :D"""
        raise ValueError("wait() on current thread")

    @utils.fixedpropety
    def peb_syswow(self):
        """The 64bits PEB of a SysWow64 process

            :type: :class:`PEB`
		"""
        if not self.is_wow_64:
            raise ValueError("Not a syswow process")
        return windows.syswow64.get_current_process_syswow_peb()
Example #14
0
class CurrentProcess(Process):
    """The current process"""
    get_peb = None

    get_peb_32_code = x86.MultipleInstr()
    get_peb_32_code += x86.Mov('EAX', x86.mem('fs:[0x30]'))
    get_peb_32_code += x86.Ret()
    get_peb_32_code = get_peb_32_code.get_code()

    get_peb_64_code = x64.MultipleInstr()
    get_peb_64_code += x64.Mov('RAX', x64.mem('gs:[0x60]'))
    get_peb_64_code += x64.Ret()
    get_peb_64_code = get_peb_64_code.get_code()

    allocator = native_exec.native_function.allocator

    def get_peb_builtin(self):
        if self.get_peb is not None:
            return self.get_peb
        if self.bitness == 32:
            get_peb = native_exec.create_function(self.get_peb_32_code,
                                                  [PVOID])
        else:
            get_peb = native_exec.create_function(self.get_peb_64_code,
                                                  [PVOID])
        self.get_peb = get_peb
        return get_peb

    def _get_handle(self):
        return winproxy.GetCurrentProcess()

    def __del__(self):
        pass

    @property
    def pid(self):
        """Process ID

        :type: int
        """
        return os.getpid()

    # Is there a better way ?
    @utils.fixedpropety
    def ppid(self):
        """Parent Process ID

        :type: int
        """
        return [p for p in windows.system.processes
                if p.pid == self.pid][0].ppid

    @utils.fixedpropety
    def peb(self):
        """The Process Environment Block of the current process

        :type: :class:`PEB`
        """
        return PEB.from_address(self.get_peb_builtin()())

    @utils.fixedpropety
    def bitness(self):
        """The bitness of the process

        :returns: int -- 32 or 64"""
        import platform
        bits = platform.architecture()[0]
        return int(bits[:2])

    def virtual_alloc(self, size):
        """Allocate memory in the current process

        :returns: int
        """
        return winproxy.VirtualAlloc(dwSize=size)

    def write_memory(self, addr, data):
        """Write data at addr"""
        buffertype = (c_char * len(data)).from_address(addr)
        buffertype[:len(data)] = data
        return True

    def read_memory(self, addr, size):
        """Read size from adddr"""
        dbgprint('Read CurrentProcess Memory', 'READMEM')
        buffer = (c_char * size).from_address(addr)
        return buffer[:]

    def create_thread(self, lpStartAddress, lpParameter, dwCreationFlags=0):
        """Create a new thread

        .. note::
            CreateThread https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx
        """
        handle = winproxy.CreateThread(lpStartAddress=lpStartAddress,
                                       lpParameter=lpParameter,
                                       dwCreationFlags=dwCreationFlags)
        return WinThread._from_handle(handle)

    def exit(self, code=0):
        """Exit the process"""
        return winproxy.ExitProcess(code)
Example #15
0
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")