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

Windows 10键盘过滤驱动:IRP按键信息的位置与访问方法

Windows 10键盘过滤驱动:读取IRP中的按键信息
  • 免责声明:我刚接触内核与驱动编程,若术语使用不当还请见谅。
  • 我正尝试编写Windows 10键盘过滤驱动,用于记录并保存用户按键。核心需求是读取包含按键信息的IRP,计划通过为IRP_MJ_READ设置自定义派遣例程来实现,但不清楚按键信息在IRP中的具体位置及访问方式。

以下是_IRP结构体定义:

typedef struct _IRP {
    CSHORT Type;
    USHORT Size;
    PMDL MdlAddress;
    ULONG Flags;
    union {
        struct _IRP *MasterIrp;
        LONG IrpCount;
        PVOID SystemBuffer;
    } AssociatedIrp;
    LIST_ENTRY ThreadListEntry;
    IO_STATUS_BLOCK IoStatus;
    KPROCESSOR_MODE RequestorMode;
    BOOLEAN PendingReturned;
    CHAR StackCount;
    CHAR CurrentLocation;
    BOOLEAN Cancel;
    KIRQL CancelIrql;
    CCHAR ApcEnvironment;
    UCHAR AllocationFlags;
    PIO_STATUS_BLOCK UserIosb;
    PKEVENT UserEvent;
    union {
        struct {
            PIO_APC_ROUTINE UserApcRoutine;
            PVOID UserApcContext;
        } AsynchronousParameters;
        LARGE_INTEGER AllocationSize;
    } Overlay;
    PDRIVER_CANCEL CancelRoutine;
    PVOID UserBuffer;
    union {
        struct {
            union {
                KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
                struct {
                    PVOID DriverContext[4];
                };
            };
            PETHREAD Thread;
            PCHAR AuxiliaryBuffer;
            struct {
                LIST_ENTRY ListEntry;
                union {
                    struct _IO_STACK_LOCATION *CurrentStackLocation;
                    ULONG PacketType;
                };
            };
            PFILE_OBJECT OriginalFileObject;
        };
    } Tail;
} IRP, *PIRP;

参考此前鼠标过滤驱动的相关思路,我猜测按键信息可能在Irp->AssociatedIrp.SystemBuffer中,但不确定该假设是否正确,也不清楚如何读取该位置的信息。


解答

你的猜测完全正确,键盘输入的IRP_MJ_READ请求中,按键数据确实存储在Irp->AssociatedIrp.SystemBuffer中。不过要注意,这个缓冲区里的数据是KEYBOARD_INPUT_DATA结构体数组,而非单个按键值。

具体访问步骤:

  1. 验证IRP与缓冲区有效性
    在IRP_MJ_READ派遣例程中,先获取当前IRP栈位置,检查缓冲区长度是否足够容纳至少一个KEYBOARD_INPUT_DATA结构体:

    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    if (stack->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA)) {
        Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_INVALID_BUFFER_SIZE;
    }
    
  2. 转换缓冲区指针类型
    将SystemBuffer强制转换为PKEYBOARD_INPUT_DATA类型,即可直接访问按键数据:

    PKEYBOARD_INPUT_DATA keyData = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
    
  3. 读取按键核心信息
    KEYBOARD_INPUT_DATA结构体包含了按键的关键状态:

    • MakeCode:硬件扫描码(对应具体按键)
    • Flags:按键动作标识(KEY_MAKE表示按下,KEY_BREAK表示释放)
    • ExtraInformation:额外输入数据(如USB键盘的扩展信息)
      示例读取逻辑:
    ULONG dataCount = stack->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA);
    for (ULONG i = 0; i < dataCount; i++) {
        USHORT scanCode = keyData[i].MakeCode;
        BOOLEAN isKeyPressed = !(keyData[i].Flags & KEY_BREAK);
        // 在此处将扫描码与按键状态写入日志或存储介质
    }
    
  4. 关键注意事项

    • 内核模式下要确保内存访问安全:若Irp->RequestorMode为UserMode,需通过MmGetSystemAddressForMdlSafe验证MdlAddress(不过IRP_MJ_READ的SystemBuffer通常是IO管理器锁定的系统空间,可直接访问)。
    • 读取完成后,必须调用IoSkipCurrentIrpStackLocation(Irp)或IoCopyCurrentIrpStackLocationToNext(Irp),再将IRP向下传递给下层驱动,保证键盘设备正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:56:06