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

时间:2017-03-03 11:11:37

标签: c++ c windows kernel driver

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

当我使用结构作为媒介通过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 个答案:

答案 0 :(得分:0)

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

也许这可能是其中一个原因。 我看到的其他问题只是通过&amp;,你应该传递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;
}

答案 1 :(得分:-1)

问题:

显然,IOCTL通过使用两者的堆栈来工作 司机&amp;用户程序。我理解堆栈了 函数调用DeviceIoControl()被复制到内核空间 然后使用DeviceIoControl()的参数进行剖析 知道我们正在使用哪些堆栈变量&amp;缓冲区是 最后设置为Irp-&gt; 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);