【问题标题】:Windows Driver IOCTL Code Bluescreens / Crashes The ComputerWindows 驱动程序 IOCTL 代码蓝屏/计算机崩溃
【发布时间】:2017-07-23 11:21:18
【问题描述】:

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

当我使用结构作为媒介通过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 使我的驱动程序和整个计算机崩溃,如何解决?我在这里做错了什么?

【问题讨论】:

  • 据我了解,从驱动程序到用户模式的通信是通过将堆栈(?)或堆栈的某些项目复制到用户空间然后处理来实现的。全局变量保存该值,而我只是在创建一个指向该值的指针并使用它的事实导致了这种情况,因为全局变量不在堆栈上?
  • 1) 你没有从IrpSp-&gt;Parameters.DeviceIoControl 检查InputBufferLength 和OutputBufferLength 2) 你没有检查PsLookupProcessByProcessId 的结果 3) 你没有打电话给ObfDereferenceObject(Process) 4) ULONG Address 必须是@ 987654334@ 或 ULONG_PTR,你检查 Address 吗? 5) 您必须分析memory.dmp(或pagefile.sys)以查看崩溃的确切位置
  • @RbMm 这是一个愚蠢的错误,已经找到了修复它。请检查我的答案
  • 你做什么 - 不修复
  • 您没有发布足够多的代码。例如,您设置了一个名为 OutPut 的变量,但我们永远看不到它的用途。

标签: c++ c windows kernel driver


【解决方案1】:

检查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;
}

【讨论】:

  • “我看到的其他问题仅通过 &” 待定。那是怎么编译的?
  • 这个也不行,以前试过。我认为问题出在内核模块代码中。甚至不再导致蓝屏,只是将处理器设置为关闭状态(在虚拟和物理 CPU 上尝试)。
【解决方案2】:

问题:

显然 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);

【讨论】:

  • 必须是 bytesIO = sizeof(ULONG); 。你的代码是一场噩梦
  • 没有从内核模式堆栈中复制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
相关资源
最近更新 更多