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

内核模式驱动调用ACPI控制方法失败(STATUS_INVALID_PARAMETER)

问题分析与解决方案

错误原因

返回STATUS_INVALID_PARAMETER(-1073741811)的核心问题有两个:

  • 目标设备对象错误:你直接获取的是ACPI设备的物理设备对象(PDO),但IOCTL_ACPI_EVAL_METHOD需要发送给ACPI驱动为该设备创建的功能设备对象(FDO)——PDO仅负责设备枚举,不处理ACPI方法调用请求。
  • PDO名称不可靠:\Device\00000071这类PDO名称是系统动态分配的,重启或设备枚举变更后会失效,硬编码会导致后续设备获取失败。

解决步骤

1. 正确获取ACPI设备的FDO

通过设备的硬件ID(TEST2412)枚举ACPI接口,匹配目标设备并获取FDO,避免依赖动态变化的PDO名称:

NTSTATUS GetAcpiFdo(PDEVICE_OBJECT* pAcpiFdo, PFILE_OBJECT* pFileObject) {
    GUID acpiGuid = GUID_DEVINTERFACE_ACPI;
    UNICODE_STRING targetHid;
    RtlInitUnicodeString(&targetHid, L"TEST2412");
    
    // 获取所有ACPI设备接口列表
    PZZWSTR interfaceList = NULL;
    ULONG listSize = 0;
    NTSTATUS status = IoGetDeviceInterfaces(&acpiGuid, NULL, 0, &interfaceList, &listSize);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    // 遍历接口匹配目标HID
    PUNICODE_STRING currentInterface = (PUNICODE_STRING)interfaceList;
    while (currentInterface->Length > 0) {
        // 尝试打开当前接口
        status = IoOpenDeviceInterface(currentInterface, FILE_READ_DATA | FILE_WRITE_DATA, NULL, pFileObject, pAcpiFdo);
        if (NT_SUCCESS(status)) {
            // 获取设备HID属性验证是否为目标设备
            WCHAR hidBuffer[256];
            UNICODE_STRING deviceHid;
            RtlInitUnicodeString(&deviceHid, hidBuffer);
            status = IoGetDeviceProperty(*pAcpiFdo, DevicePropertyHardwareId, sizeof(hidBuffer), hidBuffer, &listSize);
            if (NT_SUCCESS(status) && RtlCompareUnicodeString(&deviceHid, &targetHid, TRUE) == 0) {
                // 找到目标设备,释放列表后返回
                ExFreePool(interfaceList);
                return STATUS_SUCCESS;
            }
            // 非目标设备,释放已打开的对象
            ObDereferenceObject(*pFileObject);
            ObDereferenceObject(*pAcpiFdo);
        }
        // 移动到下一个接口
        currentInterface = (PUNICODE_STRING)((PUCHAR)currentInterface + currentInterface->MaximumLength);
    }

    ExFreePool(interfaceList);
    return STATUS_NOT_FOUND;
}

2. 修正ACPI方法调用逻辑

虽然你对MethodNameAsUlong的字节序处理正确(x86小端系统下'ERIF'对应ACPI方法名FIRE),但优化缓冲区初始化和IRP构建细节:

NTSTATUS CallAcpiMethod(PDEVICE_OBJECT pAcpiFdo) {
    KdPrint(("CallAcpiMethod enter\n"));
    ACPI_EVAL_INPUT_BUFFER inputBuffer = {0};
    ACPI_EVAL_OUTPUT_BUFFER outputBuffer = {0};
    IO_STATUS_BLOCK ioStatus;
    KEVENT event;
    PIRP irp;

    // 初始化输入缓冲区:签名+方法名
    inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
    inputBuffer.MethodNameAsUlong = 'ERIF'; // 对应ACPI方法名"FIRE"

    // 初始化IRP完成事件
    KeInitializeEvent(&event, NotificationEvent, FALSE);

    // 构建ACPI方法调用IRP
    irp = IoBuildDeviceIoControlRequest(
        IOCTL_ACPI_EVAL_METHOD,
        pAcpiFdo,
        &inputBuffer, sizeof(inputBuffer),
        &outputBuffer, sizeof(outputBuffer),
        FALSE, &event, &ioStatus);
    if (!irp) {
        KdPrint(("failed to create IRP\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // 发送IRP并等待完成
    NTSTATUS status = IoCallDriver(pAcpiFdo, irp);
    if (status == STATUS_PENDING) {
        KdPrint(("IoCallDriver pending status=%ld\n", status));
        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        status = ioStatus.Status;
    }

    KdPrint(("CallAcpiMethod exit status=%ld\n", status));
    return status;
}

3. 权限验证

确保你的内核驱动已正确签名,且拥有访问ACPI设备的权限——未签名驱动在开启安全启动的系统中会被拦截,间接导致参数错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:02:07