C++ Windows驱动程序IOCTL代码蓝屏/使计算机崩溃

C++ Windows驱动程序IOCTL代码蓝屏/使计算机崩溃,c++,c,windows,kernel,driver,C++,C,Windows,Kernel,Driver,我有一个设备驱动程序,可以用来从内核空间读取其他进程虚拟内存,因此我不必使用ReadProcessMemory或WriteProcessMemory之类的函数 当我使用结构作为媒介,通过DeviceIoControl将参数传递给内核时,这种方法可以很好地工作,但是当我使用无符号long之类的普通变量时,驱动程序会使我的计算机崩溃 下面是一个完美工作的代码示例 (驱动程序): #define IO_KERNEL_READ_REQUEST CTL_CODE(FILE_DEVICE_UNKNOW

我有一个设备驱动程序,可以用来从内核空间读取其他进程虚拟内存,因此我不必使用
ReadProcessMemory
WriteProcessMemory
之类的函数

当我使用结构作为媒介,通过
DeviceIoControl
将参数传递给内核时,这种方法可以很好地工作,但是当我使用无符号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_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;
}
调用
KernelGetProcessId
会使我的驱动程序和整个计算机崩溃,如何解决这个问题?我做错了什么?

检查。如果lpOverlapped为NULL,则lpBytesReturned不能为NULL。即使操作不返回任何输出数据且LPEXBUFFER为NULL,DeviceIoControl也会使用lpBytesReturned。在这样的操作之后,返回的lpbytes的值没有意义

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

据我所知,从驱动程序到用户模式的通信是通过将堆栈(?)或堆栈的某些项复制到用户空间,然后进行处理来实现的。一个全局变量持有该值,而我只是做了一个指向该值的指针&使用它会导致这种情况,因为全局变量不在堆栈上?1)您没有从
IrpSp->Parameters.DeviceIoControl
检查
InputBufferLength
OutputBufferLength
PsLookupProcessByProcessId
3)您没有调用
ObfDereferenceObject(Process)
4)
ULONG地址
必须是
PVOID
ULONG\u PTR
,是否检查
地址
?5) 您必须分析
memory.dmp
(或
pagefile.sys
)以查看确切位置crash@RbMm这是一个愚蠢的错误,已经找到了修复方法。请检查我的回答你做了什么-不确定你没有张贴足够的代码。例如,您设置了一个名为
OutPut
的变量,但我们从未看到它的用途。这是如何编译的?这也不起作用,以前试过。我认为问题在于内核模块代码。不再导致蓝屏,只需将处理器设置为关机状态(在虚拟和物理CPU上尝试)。必须是
bytesIO=sizeof(ULONG)。你的代码完全是噩梦——从内核模式堆栈复制的东西。