Драйвер 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);