You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows内核驱动如何完整返回PVOID内存地址至用户态?

解决Windows内核驱动中完整返回PVOID地址给用户态的问题

问题核心是:64位系统下PVOID为8字节(64位),但Irp->IoStatus.Information是32位ULONG类型,直接强转赋值会丢失高位地址。必须通过输出缓冲区传递完整的64位地址,以下是具体实现方案:

方案思路

放弃通过IoStatus.Information传递地址,改用IOCTL的输出缓冲区承载64位地址数据。确保IOCTL定义使用支持输出缓冲区的传输方法(如METHOD_BUFFERED,你已尝试过该方法,只需调整代码逻辑)。

驱动端代码修改

调整IOCTL处理逻辑,将生成的PVOID地址写入输出缓冲区,并设置Information为实际写入的字节数:

NTSTATUS status = STATUS_SUCCESS;
ULONG bytesIO = 0;
auto stack = IoGetCurrentIrpStackLocation(Irp);

switch (stack->Parameters.DeviceIoControl.IoControlCode)
{
    case IOCTL_SHELL:
    {
        auto len = stack->Parameters.DeviceIoControl.InputBufferLength;
        if (len < sizeof(Data))
        {
            DbgPrint("[-] Received too small buffer\n");
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        auto data = (Data*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
        if (data == nullptr)
        {
            DbgPrint("[-] Received empty buffer\n");
            status = STATUS_INVALID_PARAMETER;
            break;
        }

        PVOID buf = SetMemoryAddress(data);

        // --- 修改部分开始 ---
        // 获取输出缓冲区指针
        PVOID outputBuffer = Irp->AssociatedIrp.SystemBuffer;
        // 检查输出缓冲区是否足够容纳PVOID
        if (stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PVOID))
        {
            DbgPrint("[-] Output buffer too small\n");
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        // 将完整地址写入输出缓冲区
        *(PVOID*)outputBuffer = buf;
        bytesIO = sizeof(PVOID); // 设置实际写入字节数
        // --- 修改部分结束 ---

        DbgBreakPoint();

        break;
    }
}

Irp->IoStatus.Status = status;
Irp->IoStatus.Information = bytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

用户态客户端代码修改

调整DeviceIoControl调用,提供足够大的输出缓冲区接收地址,并正确打印64位地址:

HANDLE hDevice;
BOOL success;

hDevice = CreateFile(L"\\\\.\\Driver", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
    return FALSE;

Data data;
// Fill data structure here

// --- 修改部分开始 ---
PVOID retn = nullptr;
DWORD bytesReturned = 0;
// 传入输出缓冲区,大小适配PVOID
success = DeviceIoControl(hDevice, IOCTL_SHELL, &data, sizeof(data), &retn, sizeof(retn), &bytesReturned, NULL);
// 用%p打印64位地址(64位系统下自动输出8字节格式)
printf("0x%p\n", retn);
// --- 修改部分结束 ---

return success;

关键注意事项

  • 确保IOCTL定义的传输方法为METHOD_BUFFERED、METHOD_IN_DIRECT或METHOD_OUT_DIRECT,这些方法会自动处理内核与用户态的缓冲区同步。
  • 64位环境下,避免用ULONG存储地址,建议用ULONG_PTR/LONG_PTR适配32/64位系统。
  • 驱动端必须检查输出缓冲区大小,防止溢出导致系统崩溃或安全风险。

内容的提问来源于stack exchange,提问作者AnonUser1191

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 00:01:06