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结构体数组,而非单个按键值。
具体访问步骤:
验证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; }转换缓冲区指针类型
将SystemBuffer强制转换为PKEYBOARD_INPUT_DATA类型,即可直接访问按键数据:PKEYBOARD_INPUT_DATA keyData = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;读取按键核心信息
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); // 在此处将扫描码与按键状态写入日志或存储介质 }关键注意事项
- 内核模式下要确保内存访问安全:若
Irp->RequestorMode为UserMode,需通过MmGetSystemAddressForMdlSafe验证MdlAddress(不过IRP_MJ_READ的SystemBuffer通常是IO管理器锁定的系统空间,可直接访问)。 - 读取完成后,必须调用
IoSkipCurrentIrpStackLocation(Irp)或IoCopyCurrentIrpStackLocationToNext(Irp),再将IRP向下传递给下层驱动,保证键盘设备正常工作。
- 内核模式下要确保内存访问安全:若
内容的提问来源于stack exchange,提问作者ImSuffering
相关产品推荐
相关产品推荐

