无法从C++内核驱动向Rust输出缓冲区接收数据
内核驱动输出缓冲区数据无法被Rust用户态接收问题
我在实现C++内核驱动与Rust用户态程序的DeviceIoControl通信时遇到问题:内核端已确认输出缓冲区被正确写入值123,但Rust用户态接收到的始终是0。
内核端C++代码
PVOID outputBuffer = Irp->UserBuffer; LONG outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; LONG tempVmFullAccessCount = g_VmFullAccessCount; KdPrint(("Long size: %d\n", sizeof(LONG))); LONG constValue = 123; RtlCopyMemory(outputBuffer, &constValue, sizeof(LONG)); information = sizeof(LONG); KdPrint(("Output buffer value: %d\n", *((PLONG)outputBuffer)));
Rust用户态第一种尝试代码
let mut bytes_returned: DWORD = 0; let mut buffer: [u8; 4] = [0; 4]; let output_buffer = buffer.as_mut_ptr() as PVOID; let result: BOOL = unsafe { DeviceIoControl( h_device, IOCTL_NOTIFY_USERMODE_APP, null_mut(), 0, output_buffer, size_of::<i32>() as u32, &mut bytes_returned as *mut DWORD, null_mut(), ) }; if result != FALSE { println!("Bytes returned: {}", bytes_returned); println!("VM Full Access Counter: {}", vm_full_access_counter); println!("Size of i32: {}", size_of::<i32>()); vm_full_access_counter = i32::from_ne_bytes(buffer); println!("VM Full Access Counter: {}", vm_full_access_counter); } else { eprintln!("DeviceIoControl failed. Error: {}", unsafe { winapi::um::errhandlingapi::GetLastError() }); }
运行后output_buffer始终为[0,0,0,0],于是尝试直接传递变量而非u8缓冲区:
Rust用户态第二种尝试代码
let mut vm_full_access_counter: i32 = 100; let mut bytes_returned: DWORD = 0; let result: BOOL = unsafe { DeviceIoControl( h_device, IOCTL_NOTIFY_USERMODE_APP, null_mut(), 0, &mut vm_full_access_counter as *mut i32 as PVOID, size_of::<i32>() as u32, &mut bytes_returned as *mut DWORD, null_mut(), ) }; if result != FALSE { println!("Bytes returned: {}", bytes_returned); println!("VM Full Access Counter: {}", vm_full_access_counter); println!("Size of i32: {}", size_of::<i32>()); let raw_ptr = &mut vm_full_access_counter as *mut i32; let value = unsafe { *raw_ptr }; println!("VM Full Access Counter: {}", value); } else { eprintln!("DeviceIoControl failed. Error: {}", unsafe { winapi::um::errhandlingapi::GetLastError() }); }
结果:变量vm_full_access_counter调用后从初始值100变为0,依然无法正确获取内核写入的123。
已知关键信息
- LONG和i32的大小均为4字节
- 内核端打印确认
outputBuffer已写入123 - Rust端
bytes_returned返回值为4 - 已通过定时器+Arc&Mutex验证,排除延迟更新问题
排查方向与解决方法
检查IRP完成状态设置
内核端必须正确设置IRP的完成状态和返回信息长度,否则用户态无法正确接收数据:Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = information; // 此处为sizeof(LONG) IoCompleteRequest(Irp, IO_NO_INCREMENT);验证IOCTL缓冲区类型匹配
IOCTL定义的缓冲区类型需与内核代码使用的缓冲区对应:METHOD_BUFFERED:内核应使用Irp->AssociatedIrp.SystemBuffer而非UserBufferMETHOD_IN_DIRECT/METHOD_OUT_DIRECT:需处理MDL- 仅
METHOD_NEITHER可直接使用UserBuffer
确认用户态权限与IOCTL定义一致性
- 确保设备句柄
h_device有效,打开设备时请求了GENERIC_READ | GENERIC_WRITE权限 - 验证
IOCTL_NOTIFY_USERMODE_APP的控制码定义(设备类型、功能码、传输类型)与内核端完全一致
- 确保设备句柄
显式字节序转换验证
x86/x64平台为小端序,可尝试在Rust端用i32::from_le_bytes(buffer)替代from_ne_bytes,确认是否因隐式字节序问题导致数据错误。内核端内存访问合法性检查
内核端添加内存访问探测,避免非法内存写入导致数据未正确提交:__try { ProbeForWrite(outputBuffer, sizeof(LONG), sizeof(CHAR)); RtlCopyMemory(outputBuffer, &constValue, sizeof(LONG)); } __except(EXCEPTION_EXECUTE_HANDLER) { Irp->IoStatus.Status = GetExceptionCode(); return Irp->IoStatus.Status; }
内容的提问来源于stack exchange,提问作者urth
相关产品推荐
相关产品推荐

