Ejemplo n.º 1
0
def hook_IoCreateDriver(ql: Qiling, address: int, params):
    init_func = params["InitializationFunction"]

    ret_addr = ql.stack_read(0)
    # print("\n\n>>> IoCreateDriver at %x, going to execute function at %x, RET = %x\n" %(address, init_func, ret_addr))

    # save SP & init_sp
    sp = ql.reg.sp
    init_sp = ql.os.init_sp

    ql.os.fcall = ql.os.fcall_select(STDCALL)
    ql.os.fcall.writeParams((
        (POINTER, ql.loader.driver_object_address),
        (POINTER, ql.loader.regitry_path_address)))

    ql.until_addr = ret_addr

    # now lest emualate InitializationFunction
    try:
        ql.run(begin=init_func)
    except UcError as err:
        verify_ret(ql, err)

    # reset SP since emulated function does not cleanup
    ql.reg.sp = sp
    ql.os.init_sp = init_sp

    # ret_addr = ql.stack_read(0)
    # print("\n\nPC = %x, ret = %x\n" %(ql.pc, ret_addr))

    return 0
Ejemplo n.º 2
0
    def ioctl(self, params):
        def ioctl_code(DeviceType, Function, Method, Access):
            return (DeviceType << 16) | (Access << 14) | (
                Function << 2) | Method

        alloc_addr = []

        def build_mdl(buffer_size, data=None):
            if self.ql.archtype == QL_ARCH.X8664:
                mdl = MDL64()
            else:
                mdl = MDL32()

            mapped_address = self.heap.alloc(buffer_size)
            alloc_addr.append(mapped_address)
            mdl.MappedSystemVa.value = mapped_address
            mdl.StartVa.value = mapped_address
            mdl.ByteOffset = 0
            mdl.ByteCount = buffer_size
            if data:
                written = data if len(
                    data) <= buffer_size else data[:buffer_size]
                self.ql.mem.write(mapped_address, written)

            return mdl

        # quick simple way to manage all alloc memory
        if self.ql.ostype == QL_OS.WINDOWS:
            # print("DeviceControl callback is at 0x%x" %self.loader.driver_object.MajorFunction[IRP_MJ_DEVICE_CONTROL])
            if self.ql.loader.driver_object.MajorFunction[
                    IRP_MJ_DEVICE_CONTROL] == 0:
                # raise error?
                return (None, None, None)

            # create new memory region to store input data
            _ioctl_code, output_buffer_size, in_buffer = params
            # extract data transfer method
            devicetype, function, ctl_method, access = _ioctl_code

            input_buffer_size = len(in_buffer)
            input_buffer_addr = self.heap.alloc(input_buffer_size)
            alloc_addr.append(input_buffer_addr)
            self.ql.mem.write(input_buffer_addr, bytes(in_buffer))

            # create new memory region to store out data
            output_buffer_addr = self.heap.alloc(output_buffer_size)
            alloc_addr.append(output_buffer_addr)

            # allocate memory regions for IRP and IO_STACK_LOCATION
            if self.ql.archtype == QL_ARCH.X8664:
                irp_addr = self.heap.alloc(ctypes.sizeof(IRP64))
                alloc_addr.append(irp_addr)
                irpstack_addr = self.heap.alloc(
                    ctypes.sizeof(IO_STACK_LOCATION64))
                alloc_addr.append(irpstack_addr)
                # setup irp stack parameters
                irpstack = IO_STACK_LOCATION64()
                # setup IRP structure
                irp = IRP64()
                irp.irpstack = ctypes.cast(irpstack_addr,
                                           ctypes.POINTER(IO_STACK_LOCATION64))
            else:
                irp_addr = self.heap.alloc(ctypes.sizeof(IRP32))
                alloc_addr.append(irp_addr)
                irpstack_addr = self.heap.alloc(
                    ctypes.sizeof(IO_STACK_LOCATION32))
                alloc_addr.append(irpstack_addr)
                # setup irp stack parameters
                irpstack = IO_STACK_LOCATION32()
                # setup IRP structure
                irp = IRP32()
                irp.irpstack = ctypes.cast(irpstack_addr,
                                           ctypes.POINTER(IO_STACK_LOCATION32))

                #print("32 stack location size = 0x%x" %ctypes.sizeof(IO_STACK_LOCATION32))
                #print("32 status block size = 0x%x" %ctypes.sizeof(IO_STATUS_BLOCK32))
                #print("32 irp size = 0x%x" %ctypes.sizeof(IRP32))
                #print("32 IoStatus offset = 0x%x" %IRP32.IoStatus.offset)
                #print("32 UserIosb offset = 0x%x" %IRP32.UserIosb.offset)
                #print("32 UserEvent offset = 0x%x" %IRP32.UserEvent.offset)
                #print("32 UserBuffer offset = 0x%x" %IRP32.UserBuffer.offset)
                #print("32 irpstack offset = 0x%x" %IRP32.irpstack.offset)
                #print("irp at %x, irpstack at %x" %(irp_addr, irpstack_addr))

            logging.info("IRP is at 0x%x, IO_STACK_LOCATION is at 0x%x" %
                         (irp_addr, irpstack_addr))

            irpstack.Parameters.DeviceIoControl.IoControlCode = ioctl_code(
                devicetype, function, ctl_method, access)
            irpstack.Parameters.DeviceIoControl.OutputBufferLength = output_buffer_size
            irpstack.Parameters.DeviceIoControl.InputBufferLength = input_buffer_size
            irpstack.Parameters.DeviceIoControl.Type3InputBuffer.value = input_buffer_addr  # used by IOCTL_METHOD_NEITHER
            self.ql.mem.write(irpstack_addr, bytes(irpstack))

            if ctl_method == METHOD_NEITHER:
                irp.UserBuffer.value = output_buffer_addr  # used by IOCTL_METHOD_NEITHER

            # allocate memory for AssociatedIrp.SystemBuffer
            # used by IOCTL_METHOD_IN_DIRECT, IOCTL_METHOD_OUT_DIRECT and IOCTL_METHOD_BUFFERED
            system_buffer_size = max(input_buffer_size, output_buffer_size)
            system_buffer_addr = self.heap.alloc(system_buffer_size)
            alloc_addr.append(system_buffer_addr)

            # init data from input buffer
            self.ql.mem.write(system_buffer_addr, bytes(in_buffer))
            irp.AssociatedIrp.SystemBuffer.value = system_buffer_addr

            if ctl_method in (METHOD_IN_DIRECT, METHOD_OUT_DIRECT):
                # Create MDL structure for output data
                # used by both IOCTL_METHOD_IN_DIRECT and IOCTL_METHOD_OUT_DIRECT
                mdl = build_mdl(output_buffer_size)
                if self.ql.archtype == QL_ARCH.X8664:
                    mdl_addr = self.heap.alloc(ctypes.sizeof(MDL64))
                else:
                    mdl_addr = self.heap.alloc(ctypes.sizeof(MDL32))

                alloc_addr.append(mdl_addr)

                self.ql.mem.write(mdl_addr, bytes(mdl))
                irp.MdlAddress.value = mdl_addr

            # everything is done! Write IRP to memory
            self.ql.mem.write(irp_addr, bytes(irp))

            # set function args
            logging.info(
                "Executing IOCTL with DeviceObject = 0x%x, IRP = 0x%x" %
                (self.ql.loader.driver_object.DeviceObject, irp_addr))
            self.set_function_args(
                (self.ql.loader.driver_object.DeviceObject, irp_addr))

            try:
                # now emulate IOCTL's DeviceControl
                self.ql.run(self.ql.loader.driver_object.
                            MajorFunction[IRP_MJ_DEVICE_CONTROL])
            except UcError as err:
                verify_ret(self.ql, err)

            # read current IRP state
            if self.ql.archtype == QL_ARCH.X8664:
                irp_buffer = self.ql.mem.read(irp_addr, ctypes.sizeof(IRP64))
                irp = IRP64.from_buffer(irp_buffer)
            else:
                irp_buffer = self.ql.mem.read(irp_addr, ctypes.sizeof(IRP32))
                irp = IRP32.from_buffer(irp_buffer)

            io_status = irp.IoStatus

            # read output data
            output_data = b''
            if io_status.Status.Status >= 0:
                if ctl_method == METHOD_BUFFERED:
                    output_data = self.ql.mem.read(system_buffer_addr,
                                                   io_status.Information.value)
                if ctl_method in (METHOD_IN_DIRECT, METHOD_OUT_DIRECT):
                    output_data = self.ql.mem.read(mdl.MappedSystemVa.value,
                                                   io_status.Information.value)
                if ctl_method == METHOD_NEITHER:
                    output_data = self.ql.mem.read(output_buffer_addr,
                                                   io_status.Information.value)

            # now free all alloc memory
            for addr in alloc_addr:
                # print("freeing heap memory at 0x%x" %addr) # FIXME: the output is not deterministic??
                self.heap.free(addr)
            #print("\n")

            return io_status.Status.Status, io_status.Information.value, output_data
        else:  # TODO: IOCTL for non-Windows.
            pass
Ejemplo n.º 3
0
    def io_Write(self, in_buffer):
        if self.ql.ostype == QL_OS.WINDOWS:

            if self.ql.loader.driver_object.MajorFunction[IRP_MJ_WRITE] == 0:
                # raise error?
                return (False, None)

        if self.ql.archbit == 32:
            buf = self.ql.mem.read(self.ql.loader.driver_object.DeviceObject,
                                   ctypes.sizeof(DEVICE_OBJECT32))
            device_object = DEVICE_OBJECT32.from_buffer(buf)
        else:
            buf = self.ql.mem.read(self.ql.loader.driver_object.DeviceObject,
                                   ctypes.sizeof(DEVICE_OBJECT64))
            device_object = DEVICE_OBJECT64.from_buffer(buf)

        alloc_addr = []

        def build_mdl(buffer_size, data=None):
            if self.ql.archtype == QL_ARCH.X8664:
                mdl = MDL64()
            else:
                mdl = MDL32()

            mapped_address = self.heap.alloc(buffer_size)
            alloc_addr.append(mapped_address)
            mdl.MappedSystemVa.value = mapped_address
            mdl.StartVa.value = mapped_address
            mdl.ByteOffset = 0
            mdl.ByteCount = buffer_size
            if data:
                written = data if len(
                    data) <= buffer_size else data[:buffer_size]
                self.ql.mem.write(mapped_address, written)

            return mdl

        # allocate memory regions for IRP and IO_STACK_LOCATION
        if self.ql.archtype == QL_ARCH.X8664:
            irp_addr = self.heap.alloc(ctypes.sizeof(IRP64))
            alloc_addr.append(irp_addr)
            irpstack_addr = self.heap.alloc(ctypes.sizeof(IO_STACK_LOCATION64))
            alloc_addr.append(irpstack_addr)
            # setup irp stack parameters
            irpstack = IO_STACK_LOCATION64()
            # setup IRP structure
            irp = IRP64()
            irp.irpstack = ctypes.cast(irpstack_addr,
                                       ctypes.POINTER(IO_STACK_LOCATION64))
        else:
            irp_addr = self.heap.alloc(ctypes.sizeof(IRP32))
            alloc_addr.append(irp_addr)
            irpstack_addr = self.heap.alloc(ctypes.sizeof(IO_STACK_LOCATION32))
            alloc_addr.append(irpstack_addr)
            # setup irp stack parameters
            irpstack = IO_STACK_LOCATION32()
            # setup IRP structure
            irp = IRP32()
            irp.irpstack = ctypes.cast(irpstack_addr,
                                       ctypes.POINTER(IO_STACK_LOCATION32))

        irpstack.MajorFunction = IRP_MJ_WRITE
        irpstack.Parameters.Write.Length = len(in_buffer)
        self.ql.mem.write(irpstack_addr, bytes(irpstack))

        if device_object.Flags & DO_BUFFERED_IO:
            # BUFFERED_IO
            system_buffer_addr = self.heap.alloc(len(in_buffer))
            alloc_addr.append(system_buffer_addr)
            self.ql.mem.write(system_buffer_addr, bytes(in_buffer))
            irp.AssociatedIrp.SystemBuffer.value = system_buffer_addr
        elif device_object.Flags & DO_DIRECT_IO:
            # DIRECT_IO
            mdl = build_mdl(len(in_buffer))
            if self.ql.archtype == QL_ARCH.X8664:
                mdl_addr = self.heap.alloc(ctypes.sizeof(MDL64))
            else:
                mdl_addr = self.heap.alloc(ctypes.sizeof(MDL32))

            alloc_addr.append(mdl_addr)

            self.ql.mem.write(mdl_addr, bytes(mdl))
            irp.MdlAddress.value = mdl_addr
        else:
            # NEITHER_IO
            input_buffer_size = len(in_buffer)
            input_buffer_addr = self.heap.alloc(input_buffer_size)
            alloc_addr.append(input_buffer_addr)
            self.ql.mem.write(input_buffer_addr, bytes(in_buffer))
            irp.UserBuffer.value = input_buffer_addr

        # everything is done! Write IRP to memory
        self.ql.mem.write(irp_addr, bytes(irp))

        # set function args
        self.set_function_args(
            (self.ql.loader.driver_object.DeviceObject, irp_addr))

        try:
            # now emulate
            self.ql.run(
                self.ql.loader.driver_object.MajorFunction[IRP_MJ_WRITE])
        except UcError as err:
            verify_ret(self.ql, err)

        # read current IRP state
        if self.ql.archtype == QL_ARCH.X8664:
            irp_buffer = self.ql.mem.read(irp_addr, ctypes.sizeof(IRP64))
            irp = IRP64.from_buffer(irp_buffer)
        else:
            irp_buffer = self.ql.mem.read(irp_addr, ctypes.sizeof(IRP32))
            irp = IRP32.from_buffer(irp_buffer)

        io_status = irp.IoStatus
        # now free all alloc memory
        for addr in alloc_addr:
            # print("freeing heap memory at 0x%x" %addr) # FIXME: the output is not deterministic??
            self.heap.free(addr)
        return True, io_status.Information.value
Ejemplo n.º 4
0
def io_Write(ql: Qiling, in_buffer: bytes):
    heap = ql.os.heap

    if ql.loader.driver_object.MajorFunction[IRP_MJ_WRITE] == 0:
        # raise error?
        return (False, None)

    driver_object_cls = ql.loader.driver_object.__class__
    buf = ql.mem.read(ql.loader.driver_object.DeviceObject,
                      ctypes.sizeof(driver_object_cls))
    device_object = driver_object_cls.from_buffer(buf)

    alloc_addr = []

    def build_mdl(buffer_size: int, data=None):
        mdl = make_mdl(ql.arch.bits)

        mapped_address = heap.alloc(buffer_size)
        alloc_addr.append(mapped_address)
        mdl.MappedSystemVa.value = mapped_address
        mdl.StartVa.value = mapped_address
        mdl.ByteOffset = 0
        mdl.ByteCount = buffer_size
        if data:
            written = data if len(data) <= buffer_size else data[:buffer_size]
            ql.mem.write(mapped_address, written)

        return mdl

    # allocate memory regions for IRP and IO_STACK_LOCATION
    irp = make_irp(ql.arch.bits)
    irpstack_class = irp.irpstack._type_

    irp_addr = heap.alloc(ctypes.sizeof(irp))
    alloc_addr.append(irp_addr)

    irpstack_addr = heap.alloc(ctypes.sizeof(irpstack_class))
    alloc_addr.append(irpstack_addr)

    # setup irp stack parameters
    irpstack = irpstack_class()
    # setup IRP structure
    irp.irpstack = ctypes.cast(irpstack_addr, ctypes.POINTER(irpstack_class))

    irpstack.MajorFunction = IRP_MJ_WRITE
    irpstack.Parameters.Write.Length = len(in_buffer)
    ql.mem.write(irpstack_addr, bytes(irpstack))

    if device_object.Flags & DO_BUFFERED_IO:
        # BUFFERED_IO
        system_buffer_addr = heap.alloc(len(in_buffer))
        alloc_addr.append(system_buffer_addr)
        ql.mem.write(system_buffer_addr, bytes(in_buffer))
        irp.AssociatedIrp.SystemBuffer.value = system_buffer_addr
    elif device_object.Flags & DO_DIRECT_IO:
        # DIRECT_IO
        mdl = build_mdl(len(in_buffer))
        mdl_addr = heap.alloc(ctypes.sizeof(mdl))
        alloc_addr.append(mdl_addr)

        ql.mem.write(mdl_addr, bytes(mdl))
        irp.MdlAddress.value = mdl_addr
    else:
        # NEITHER_IO
        input_buffer_size = len(in_buffer)
        input_buffer_addr = heap.alloc(input_buffer_size)
        alloc_addr.append(input_buffer_addr)
        ql.mem.write(input_buffer_addr, bytes(in_buffer))
        irp.UserBuffer.value = input_buffer_addr

    # everything is done! Write IRP to memory
    ql.mem.write(irp_addr, bytes(irp))

    # set function args
    # TODO: make sure this is indeed STDCALL
    ql.os.fcall = ql.os.fcall_select(STDCALL)
    ql.os.fcall.writeParams(
        ((POINTER, ql.loader.driver_object.DeviceObject), (POINTER, irp_addr)))

    try:
        # now emulate
        ql.run(ql.loader.driver_object.MajorFunction[IRP_MJ_WRITE])
    except UcError as err:
        verify_ret(ql, err)

    # read current IRP state
    irp_buffer = ql.mem.read(irp_addr, ctypes.sizeof(irp))
    irp = irp.from_buffer(irp_buffer)

    io_status = irp.IoStatus
    # now free all alloc memory
    for addr in alloc_addr:
        # print("freeing heap memory at 0x%x" %addr) # FIXME: the output is not deterministic??
        heap.free(addr)

    return True, io_status.Information.value
Ejemplo n.º 5
0
def ioctl(ql: Qiling, params: Tuple[Tuple, int, bytes]) -> Tuple:

    allocations = []

    def __heap_alloc(size: int) -> int:
        address = ql.os.heap.alloc(size)
        allocations.append(address)

        return address

    def __free_all(allocations: Iterable[int]) -> None:
        for address in allocations:
            ql.os.heap.free(address)

    def ioctl_code(DeviceType: int, Function: int, Method: int,
                   Access: int) -> int:
        return (DeviceType << 16) | (Access << 14) | (Function << 2) | Method

    def build_mdl(buffer_size, data=None):
        mdl = make_mdl(ql.arch.bits)

        mapped_address = __heap_alloc(buffer_size)
        mdl.MappedSystemVa.value = mapped_address
        mdl.StartVa.value = mapped_address
        mdl.ByteOffset = 0
        mdl.ByteCount = buffer_size

        if data:
            written = data if len(data) <= buffer_size else data[:buffer_size]
            ql.mem.write(mapped_address, written)

        return mdl

    if ql.loader.driver_object.MajorFunction[IRP_MJ_DEVICE_CONTROL] == 0:
        # raise error?
        return (None, None, None)

    # create new memory region to store input data
    _ioctl_code, output_buffer_size, in_buffer = params
    # extract data transfer method
    devicetype, function, ctl_method, access = _ioctl_code

    input_buffer_size = len(in_buffer)
    input_buffer_addr = __heap_alloc(input_buffer_size)
    ql.mem.write(input_buffer_addr, bytes(in_buffer))

    # create new memory region to store out data
    output_buffer_addr = __heap_alloc(output_buffer_size)

    # allocate memory regions for IRP and IO_STACK_LOCATION
    irp = make_irp(ql.arch.bits)
    irpstack_class = irp.irpstack._type_

    irp_addr = __heap_alloc(ctypes.sizeof(irp))
    irpstack_addr = __heap_alloc(ctypes.sizeof(irpstack_class))

    # setup irp stack parameters
    irpstack = irpstack_class()
    # setup IRP structure
    irp.irpstack = ctypes.cast(irpstack_addr, ctypes.POINTER(irpstack_class))

    ql.log.info("IRP is at 0x%x, IO_STACK_LOCATION is at 0x%x" %
                (irp_addr, irpstack_addr))

    irpstack.Parameters.DeviceIoControl.IoControlCode = ioctl_code(
        devicetype, function, ctl_method, access)
    irpstack.Parameters.DeviceIoControl.OutputBufferLength = output_buffer_size
    irpstack.Parameters.DeviceIoControl.InputBufferLength = input_buffer_size
    irpstack.Parameters.DeviceIoControl.Type3InputBuffer.value = input_buffer_addr  # used by IOCTL_METHOD_NEITHER
    ql.mem.write(irpstack_addr, bytes(irpstack))

    if ctl_method == METHOD_NEITHER:
        irp.UserBuffer.value = output_buffer_addr  # used by IOCTL_METHOD_NEITHER

    # allocate memory for AssociatedIrp.SystemBuffer
    # used by IOCTL_METHOD_IN_DIRECT, IOCTL_METHOD_OUT_DIRECT and IOCTL_METHOD_BUFFERED
    system_buffer_size = max(input_buffer_size, output_buffer_size)
    system_buffer_addr = __heap_alloc(system_buffer_size)

    # init data from input buffer
    ql.mem.write(system_buffer_addr, bytes(in_buffer))
    irp.AssociatedIrp.SystemBuffer.value = system_buffer_addr

    if ctl_method in (METHOD_IN_DIRECT, METHOD_OUT_DIRECT):
        # Create MDL structure for output data
        # used by both IOCTL_METHOD_IN_DIRECT and IOCTL_METHOD_OUT_DIRECT
        mdl = build_mdl(output_buffer_size)
        mdl_addr = __heap_alloc(ctypes.sizeof(mdl))

        ql.mem.write(mdl_addr, bytes(mdl))
        irp.MdlAddress.value = mdl_addr

    # everything is done! Write IRP to memory
    ql.mem.write(irp_addr, bytes(irp))

    # set function args
    ql.log.info("Executing IOCTL with DeviceObject = 0x%x, IRP = 0x%x" %
                (ql.loader.driver_object.DeviceObject, irp_addr))
    # TODO: make sure this is indeed STDCALL
    ql.os.fcall = ql.os.fcall_select(STDCALL)
    ql.os.fcall.writeParams(
        ((POINTER, ql.loader.driver_object.DeviceObject), (POINTER, irp_addr)))

    try:
        ql.log.info(
            f"Executing from: {ql.loader.driver_object.MajorFunction[IRP_MJ_DEVICE_CONTROL]:#x}"
        )
        # now emulate IOCTL's DeviceControl
        ql.run(ql.loader.driver_object.MajorFunction[IRP_MJ_DEVICE_CONTROL])
    except UcError as err:
        verify_ret(ql, err)

    # read current IRP state
    irp_buffer = ql.mem.read(irp_addr, ctypes.sizeof(irp))
    irp = irp.__class__.from_buffer(irp_buffer)

    io_status = irp.IoStatus

    # read output data
    output_data = b''
    if io_status.Status.Status >= 0:
        if ctl_method == METHOD_BUFFERED:
            output_data = ql.mem.read(system_buffer_addr,
                                      io_status.Information.value)
        if ctl_method in (METHOD_IN_DIRECT, METHOD_OUT_DIRECT):
            output_data = ql.mem.read(mdl.MappedSystemVa.value,
                                      io_status.Information.value)
        if ctl_method == METHOD_NEITHER:
            output_data = ql.mem.read(output_buffer_addr,
                                      io_status.Information.value)

    # now free all alloc memory
    __free_all(allocations)

    return io_status.Status.Status, io_status.Information.value, output_data