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
相关产品推荐
相关产品推荐

