视窗驱动程序IOCTL代码蓝屏/使计算机崩溃

Windows Driver IOCTL Code Bluescreens / Crashes The Computer

本文关键字:计算机 崩溃 驱动程序 IOCTL 代码      更新时间:2023-10-16

我有一个设备驱动程序,我用它来从内核空间读取其他进程虚拟内存,所以我不必使用ReadProcessMemoryWriteProcessMemory等函数。

当我使用结构作为媒介通过DeviceIoControl将参数传递给内核时,这工作正常,但是当我使用无符号长整型等普通变量时,驱动程序会使我的计算机崩溃。

这是一个完美工作代码的示例

(司机):

#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会使我的驱动程序和整个计算机崩溃,如何解决此问题?我在这里做错了什么?

检查 DeviceIoControl。如果 lpOverlapped 为 NULL,则 lpBytesReturn 不能为 NULL。即使操作不返回任何输出数据并且 lpOutBuffer 为 NULL,DeviceIoControl 也会使用 lpBytesReturn。经过这样的操作,lpBytesReturn的值是没有意义的。

也许这可能是原因之一。 我看到的其他问题是只传递 &,您应该在其中传递 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);