原始 PDO 将 IOCTL 发送到上层过滤器驱动程序 (kbfiltr/moufiltr) 以启用/禁用设备
我对驱动程序开发非常陌生,并尝试编写一个简单的过滤驱动程序来启用或禁用键盘或鼠标设备。如果我能让它工作,我想在插入鼠标时使用它来禁用笔记本电脑上的触摸板。我意识到可能已经有软件可以做到这一点,但我对设备驱动程序非常感兴趣并且想要自己学习如何做到这一点。
我使用 WDK 附带的 kbfiltr 和 moufiltr 示例,作为上层过滤器驱动程序安装。 kbfiltr 示例创建一个可由用户模式程序枚举和连接的 pdo。这允许我将 IOCTL 发送到由 KbFilter_EvtIoDeviceControlForRawPdo 处理的 PDO。然而,当我尝试做任何与过滤器驱动程序相关的事情时,比如调用KbFilter_EvtIoInternalDeviceControl,这样我就可以做一些类似
VOID
KbFilter_EvtIoInternalDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
...
hDevice = WdfIoQueueGetDevice(Queue);
devExt = FilterGetData(hDevice);
switch (IoControlCode) {
...
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
//
// Clear the connection parameters in the device extension.
//
devExt->UpperConnectData.ClassService = NULL;
break;
...
}
蓝屏死机的事情。这不是上面的代码,在普通示例中,设置为 null 被注释掉,仅调用 Kbfilter 就会导致 BSOD。我尝试直接在 PDO 中设置设备扩展,但这也会导致 BSOD,大概是因为它是 PDO devExt,而不是 kbfiltr 的?
(相关:从 BSOD 获取堆栈跟踪的好方法是什么?我使用 Virtual PC 作为测试环境和未经检查的 XPSP3 版本)
我无法将 IOCTL_INTERNAL_KEYBOARD_DISCONNECT 直接发送到驱动程序堆栈(我理解该输入设备一次只接受一个连接?)因此需要原始 PDO。我实际上只需要发送两个 IOCTL(以启用和禁用),并且我想我只需使用键盘断开连接和连接,因为这些已经定义了。
如果我对这些假设有任何错误,请告诉我,我知道我在这方面确实是菜鸟,但我还没有找到很多关于通过 PDO 进行这种通信的文档。
I am quite new to driver development and trying to write a simple filter driver that will enable or disable a keyboard or mouse device. If I can make it work, I want to use it to disable the touchpad on my laptop when a mouse is plugged in. I realize there is probably software out there that does this already, but I am really interested in device drivers and want to learn how to do this myself.
I am using the kbfiltr and moufiltr examples that ship with the WDK, installed as upper filter drivers. The kbfiltr example creates a pdo which can be enumerated and connected to by a usermode program. This allows me to send IOCTLs to the PDO that are handled by KbFilter_EvtIoDeviceControlForRawPdo. However, when I try and do anything at all related to the filter driver, like call into KbFilter_EvtIoInternalDeviceControl so I can do something like
VOID
KbFilter_EvtIoInternalDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
...
hDevice = WdfIoQueueGetDevice(Queue);
devExt = FilterGetData(hDevice);
switch (IoControlCode) {
...
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
//
// Clear the connection parameters in the device extension.
//
devExt->UpperConnectData.ClassService = NULL;
break;
...
}
I get a BSOD. It is not the above code, in the vanilla example the set to null is commented out, just calling into Kbfilter causes the BSOD. I have tried to set the device extension directly in the PDO but this also causes a BSOD, presumably because it is the PDO devExt, not kbfiltr's?
(related: what is a good way of getting the stack trace from a BSOD? I am using Virtual PC as my test environment and an unchecked build of XPSP3)
I can't send an IOCTL_INTERNAL_KEYBOARD_DISCONNECT directly to the driver stack (I understand that input devices accept only one connection at a time?) hence the need for the raw PDO. I really only need to send two IOCTLs (to enable and disable) and I figured I would just use the keyboard disconnect and connect since these were already defined.
If I am wrong about any of these assumptions, please let me know, I know I really am a noob at this but I haven't found a lot of documentation about this kind of communication via a PDO.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,我终于解决了这个问题,我的驱动程序正在工作。
KMDF 过滤器驱动程序的实现:
感谢 Sergius 提出了 COM 端口方法,因为这帮助我设置了 WinDbg。 这篇很棒的博客文章解释了如何快速设置它,基本上你让 VPC 设置一个 com 端口作为命名Pipe,在虚拟化操作系统上启用内核调试模式,并在启动时连接到它。然后,您可以在驱动程序加载时获取所有 DbgPrint 消息并执行更多操作,但启动过程中的跟踪消息对我来说是一个巨大的帮助。
我认为我的主要问题是尝试在 KbFiltr 中重用内部 IOCTL。这对我来说只是一个糟糕的设计理念,因为我不理解内部 IOCTL 和其他 IOCTL 之间的区别 - 内部 IOCTLS(例如 IOCTL_INTERNAL_KEYBOARD_DISCONNECT)具有受限的访问条件,只能由其他驱动程序或内核发送。另外此知识库文章“如何将 IOCTL 发送到筛选器驱动程序” 是使用相同控件的示例设备结构,不过是WDM。
无论如何,在整个周末与 KbFiltr 示例进行斗争之后,我终于放弃并开始使用 WDF 烤面包机/过滤器示例。这是一个更准系统的 KMDF 过滤器驱动程序,我必须使用 KbFiltr 和 MouFiltr 来填补很多空白。 Toaster 过滤器驱动程序操作与 KbFiltr 类似,但它创建一个控制设备而不是 PDO。它还为控制设备设置一个 dos 设备名称,以便您可以从用户模式与其通信,而无需 Pinvoke 执行该步骤。控制设备允许您通过迭代集合来控制加载了过滤器驱动程序的所有设备。等待锁用于同步对集合的访问。
我还能够只修改 INF 文件(使用 Mouse 类而不是 Toaster 类)并将其直接开箱即用地应用到我的测试机器上,而无需修改驱动程序代码!从有效的事情开始要容易得多。 此页面提供了您应该更改的内容的完整列表调整样本。
Ok, I have finally solved this and my driver is working.
Implementation of a KMDF filter driver:
Thanks to Sergius who suggested the COM-port approach because this helped me set up WinDbg. This awesome blog post explains how to get it set up quickly, basically you let VPC set up a com port as a named pipe, enable kernel debug mode on the virtualized OS, and connect to it while it is booting. Then you can get all the DbgPrint messages when the driver is loading and do a lot more, but just the trace messages during the startup process were a huge help for me.
I think my main problem was trying to reuse an internal IOCTL in KbFiltr. This was just a bad design idea on my part because I didn't understand the difference between internal IOCTL and other IOCTLs - Internal IOCTLS such as IOCTL_INTERNAL_KEYBOARD_DISCONNECT have restricted access conditions and should only be sent by other drivers or the kernel. Also this KB article "How to send IOCTL to filter driver" is an example using the same control device structure, but it is WDM.
Anyway, after fighting with the KbFiltr example all weekend, I finally gave up and started over using the WDF Toaster/filtr example. This is a more barebones KMDF filter driver and I had to fill in a lot of blanks using KbFiltr and MouFiltr. The Toaster filter driver operation is similar to KbFiltr but it creates a control device instead of a PDO. It also sets a dos device name for the control device so you can communicate with it from usermode without having to Pinvoke to do that step. The control device allows you to control all devices which have your filter driver loaded just by iterating over the collection. A waitlock is used to synchronize access to the collection.
I also was able to just modify the INF file (to use Mouse class instead of Toaster class) and apply it straight out of the box on my test machine with no modification to the driver code! It is so much easier to start with something that is working. This page gives a comprehensive list of things you should change to adapt the samples.
首先:您可以在用户模式下做您想做的事情(当插入鼠标时禁用我的笔记本电脑上的触摸板)。它将变得更加简单和安全。请参阅使用设备安装功能和WM_DEVICECHANGE
要调试代码中的问题:从 BSOD 或安装程序获取内存转储内核调试器连接(使用虚拟 PC 上的 COM 端口重定向到管道)。请参阅Windows 调试工具
玩得开心!
First of all: You can do what you want to do (disable the touchpad on my laptop when a mouse is plugged in) in the user-mode. It will be much simpler and safer. Look at Using Device Installation Functions and WM_DEVICECHANGE
To debug problems in your code: Get a memory dump from BSOD or setup a kernel debugger connection (using a COM-port on your virtual PC redirected to a pipe). See Debugging Tools for Windows
Have fun!