Драйвер Windows IOCTL Код Bluescreens / Сбой компьютера

У меня есть драйвер устройства, который я использую для чтения другой виртуальной памяти процесса из пространства ядра, поэтому мне не нужно использовать такие функции, как ReadProcessMemory или же WriteProcessMemory,

Это прекрасно работает, когда я использую структуру в качестве среды для передачи аргументов в ядро ​​через DeviceIoControl, но драйвер сбивает мой компьютер, когда я использую простые переменные, такие как unsigned long.

Вот пример отлично работающего кода

(Водитель):

#define IO_KERNEL_READ_REQUEST    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0701, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)

typedef struct _KERNEL_READ_REQUEST
{
    ULONG ProcessId;

    ULONG Address;
    ULONG Response;
    ULONG Size;

} KERNEL_READ_REQUEST, *PKERNEL_READ_REQUEST;

    if (ControlCode == IO_KERNEL_READ_REQUEST)
    {
        PKERNEL_READ_REQUEST ReadInput = (PKERNEL_READ_REQUEST)Irp->AssociatedIrp.SystemBuffer;
        PKERNEL_READ_REQUEST ReadOutput = (PKERNEL_READ_REQUEST)Irp->AssociatedIrp.SystemBuffer;

        PEPROCESS Process;
        PsLookupProcessByProcessId(ReadInput->ProcessId, &Process);
        KeReadVirtualMemory(Process, ReadInput->Address, &ReadOutput->Response, ReadInput->Size);

        DbgPrintEx(0, 0, "Read Params:  %lu, %#010x \n", ReadInput->ProcessId, ReadInput->Address);
        DbgPrintEx(0, 0, "Value: %lu \n", ReadOutput->Response);

        status = STATUS_SUCCESS;
        bytesIO = sizeof(KERNEL_READ_REQUEST);
    }

(Программа):

template <typename type>
type KernelRead(HANDLE hDriver, ULONG ProcessId, ULONG ReadAddress, SIZE_T ReadSize)
{
    if (hDriver == INVALID_HANDLE_VALUE)
        return (type)false;

    DWORD Return;
    DWORD Bytes;
    KERNEL_READ_REQUEST  ReadRequest;

    ReadRequest.ProcessId = ProcessId;
    ReadRequest.Address = ReadAddress;
    ReadRequest.Size = ReadSize;

    if (DeviceIoControl(hDriver, IO_KERNEL_READ_REQUEST, &ReadRequest, sizeof(ReadRequest),
        &ReadRequest, sizeof(ReadRequest), &Bytes, NULL)) {
        return (type)ReadRequest.Response;
    }
    else
        return (type)false;
}

Это то, что вызывает проблему

#define IO_KERNEL_GET_ID           CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0703, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
else if (ControlCode == IO_KERNEL_GET_ID)
{
    // ProcessId is an ULONG initialized at the driver entry
    PULONG OutPut = (PULONG)Irp->AssociatedIrp.SystemBuffer;
    OutPut = &ProcessId;

    DbgPrintEx(0, 0, "Kernel Get Id: %d \n", *OutPut);

    status = STATUS_SUCCESS;
    bytesIO = sizeof(OutPut);
}

DWORD KernelGetProcessId(HANDLE hDriver)
{
    if (hDriver == INVALID_HANDLE_VALUE)
        return false;
    ULONG Id;

    if (DeviceIoControl(hDriver, IO_KERNEL_GET_ID, &, sizeof(Id),
        &Id, sizeof(Id), 0, NULL))
        return Id;
    else
        return false;
}

призвание KernelGetProcessId вылетает мой драйвер и весь компьютер, как это можно исправить? Что я здесь не так делаю?

2 ответа

Проверьте DeviceIoControl. Если lpOverlapped имеет значение NULL, lpBytesReturned не может быть NULL. Даже когда операция не возвращает выходные данные и lpOutBuffer имеет значение NULL, DeviceIoControl использует lpBytesReturned. После такой операции значение lpBytesReturned не имеет смысла.

Может быть, это может быть одной из причин. Другая проблема, которую я вижу, касается только &, вы должны передать переменную ULONG в нем.

Проверьте что-то вроде этого

DWORD KernelGetProcessId(HANDLE hDriver)
{
    if (hDriver == INVALID_HANDLE_VALUE)
        return false;
    ULONG Id;
    DWORD Bytes;

    if (DeviceIoControl(hDriver, IO_KERNEL_GET_ID, &Id, sizeof(Id),
        &Id, sizeof(Id), &Bytes, NULL))
        return Id;
    else
        return false;
}

Проблема:

Очевидно, IOCTL работают с использованием стека как драйвера, так и пользовательской программы. Насколько я понимаю, стек функции, вызывающей DeviceIoControl(), копируется в пространство ядра, а затем разбирается с использованием аргументов DeviceIoControl(), чтобы узнать, с какими переменными стека мы работаем, и в буфере наконец устанавливается Irp->AssociatedIrp.SystemBuffer.

После завершения операции IOCTL на стороне ядра выполняется IoCompleteRequest(), который копирует стек модуля ядра в пространство пользователя, которое затем снова разбивается на форму, в которой мы хотим его получить.

(поправьте меня, если я ошибаюсь)

Решение:

Сбой вызван этим кодом в модуле ядра:

PULONG OutPut = (PULONG)Irp->AssociatedIrp.SystemBuffer;
  OutPut = &ProcessId;

в котором адрес глобальной переменной задается как значение выходных данных. Теперь, когда стек копируется, адрес явно никуда не указывает, поскольку переменная "ProcessId" находится в 64-битном пространстве ядра. Это мое понимание проблемы.

Это решает проблему:

PULONG OutPut = (PULONG)Irp->AssociatedIrp.SystemBuffer;
*OutPut = ProcessId;

DbgPrintEx(0, 0, "Kernel Get Id: %d \n", *OutPut);

status = STATUS_SUCCESS;
bytesIO = sizeof(OutPut);
Другие вопросы по тегам