DeviceIoControl调用返回错误码87(无效参数)问题排查
错误码87(ERROR_INVALID_PARAMETER)表示DeviceIoControl的参数不符合驱动要求,结合你的代码,重点排查以下几个方向:
1. 结构体指针在METHOD_BUFFERED模式下无效
你使用了METHOD_BUFFERED控制码,这种模式下内核会完整复制用户态输入缓冲区到内核空间。但你的t_image结构体中address是ULONGLONG*类型(用户态指针),这个指针在内核空间完全无效——内核无法直接访问用户态地址,驱动尝试解引用时会触发错误,最终返回无效参数。
修复方案:
修改t_image结构体,将指针替换为实际的ULONGLONG变量,让内核直接写入值到结构体中:
typedef struct t_image { INT32 security_code; INT32 process_id; ULONGLONG address; // 替换指针为实际变量 } e_image, * s_image;
用户态代码调整为:
uintptr_t driver::find_image() { t_image arguments = {0}; arguments.security_code = code_security; arguments.process_id = ProcId; arguments.address = 0; // 初始化默认值 DWORD bytes_returned = 0; if (!DeviceIoControl(driver_handle, code_image, &arguments, sizeof(arguments), &arguments, sizeof(arguments), &bytes_returned, NULL)) { DWORD error_code = GetLastError(); LPSTR error_message = nullptr; FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&error_message, 0, nullptr ); std::cout << "DeviceIoControl failed with error " << error_code << ": " << error_message << std::endl; LocalFree(error_message); return 0; } return static_cast<uintptr_t>(arguments.address); }
2. 输入输出缓冲区参数不匹配
你当前调用DeviceIoControl时,lpOutBuffer传nullptr、nOutBufferSize为NULL,但如果驱动期望通过输出缓冲区返回镜像地址,这两个参数完全不符合要求——驱动无法写入结果,因此返回无效参数。
修复方案:
如上述代码所示,将lpOutBuffer设为结构体指针&arguments,nOutBufferSize设为sizeof(arguments),同时传递有效的lpBytesReturned变量(不能为NULL,除非使用异步OVERLAPPED操作)。
3. 用户态与内核态结构体大小/对齐不一致
如果驱动端的t_image结构体定义和用户态不一致(比如编译器对齐选项不同,内核用#pragma pack(4)而用户态用默认对齐),会导致sizeof(arguments)在用户态和内核态不相等,驱动校验输入缓冲区大小时会判定参数无效。
修复方案:
在用户态和驱动端的结构体定义前统一添加对齐指令,确保大小一致:
#pragma pack(push, 4) typedef struct t_image { INT32 security_code; INT32 process_id; ULONGLONG address; } e_image, * s_image; #pragma pack(pop)
4. 进程ID或安全码无效
- 检查
ProcId是否为有效的进程ID(不能是0、不存在的进程ID),驱动可能会校验进程ID有效性,无效则返回错误87。 - 检查
code_security的值是否与驱动端期望的安全码完全一致,驱动端如果对该字段有校验,不匹配会直接返回无效参数。
5. 控制码定义不匹配
确认驱动端处理code_image控制码时,使用的缓冲区模式与用户态定义的METHOD_BUFFERED一致。如果驱动端误写为METHOD_IN_DIRECT或其他模式,也会导致参数不匹配。
内容的提问来源于stack exchange,提问作者Time Clox

