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

DeviceIoControl调用返回错误码87(无效参数)问题排查

错误码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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:35:17