KMDF Software-only keyboard device

Hello, folks -

I’m starting a new project, which will attempt to inject keystrokes (originating from user-mode code) via a device driver.

My first thought was to actually create a keyboard device driver, bypassing the class driver due to KMDF’s general lack of support for minidrivers. However, I couldn’t get the minimal driver to install (DiFx/devcon hangs after “DiFx Info: ENTER UpdateDriverForPlugAndPlayDevices…”; the driver is started and a device added but nothing after that; the device is of type FILE_DEVICE_KEYBOARD and exposes GUID_DEVINTERFACE_KEYBOARD - not sure what else I’m expected to do…).

So I decided to take a step back; writing a keyboard driver (as opposed to a minidriver) may be possible but it’s certainly not common. I can think of two other ways to do this:

  1. Take the hidusbfx2 route (I just downloaded the 6001 R0 WDK just for this sample): make a minimal WDM minidriver with a KMDF filter on it.
  2. Take the kbfiltr route: just a KMDF filter without a seperate software-only keyboard device. This should be sufficient to inject keystrokes, but I am not sure if the sample provided can be made to work for *any* type of system. (I have a computer at home that only has a USB keyboard, no PS2).

Plus, for either of these solutions, I believe I’d need an additional control device as well, for user-mode communication, correct?

I’d love to hear recommendations on which approach I should use. FYI, I have some KMDF experience but no WDM; PnP for WDM scares me…

-Steve

Hello, Steve.

I’ve already written a virtual keyboard driver (WDM, non-KMDF).
It was actually much easier than I originally thought, because most power & PnP management is already done by the bus driver (root enumerator).

Here’s how I did it:

Create a function driver for an root-enumerated keyboard device. Depending on your requirements, you don’t need a bus- or minidriver.

  • Handle IRP_MJ_POWER & IRP_MJ_PNP. For the most part, you just have to pass them down untouched.
  • Handle IRP_MJ_CREATE & IRP_MJ_CLOSE. Just succeed them for Win32k’s Raw Input Thread to access your device. Kbdclass already does the privilege validation.
  • Handle IRP_MJ_INTERNAL_DEVICE_CONTROL to act like a real keyboard (IOCTL_INTERNAL_KEYBOARD_CONNECT, IOCTL_KEYBOARD_QUERY_ATTRIBUTES, IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION, IOCTL_KEYBOARD_QUERY_INDICATORS, IOCTL_KEYBOARD_QUERY_TYPEMATIC, IOCTL_KEYBOARD_SET_INDICATORS, IOCTL_KEYBOARD_SET_TYPEMATIC).
  • Write an INF file, create a root-enumerated device node (e.g., using devcon), and install your driver.

I suggest to look at WDK’s pnpi8042 as it does everything you need (and beyond).
You can mimic its default keyboard properties and optionally implement WMI support, but that is no requirement.

Yes, you will need a control device object for user-mode applications to access the driver.

The easiest solution is to edit kbfiltr, but you won’t have your dedicated keyboard device then.
Kbfiltr doesn’t necessarily care about the keyboard type it is filtering; it just has to receive IOCTL_INTERNAL_KEYBOARD_CONNECT originating from kbdclass.

Sorry:

“Hello, Stephen.”

Steve, I would like to clear up a couple of terms that are particular to the keyboard stack. A keyboard port driver is not a true port+miniport driver like NDIS or scsiport, rather it is a driver which controls a port on which a keyboard is attached (just like the serial driver controls a serial port). The keyboard port driver is a full fledged driver with the keyboard class driver layered on top of it, e.g.

Kbdclass
|

|
PDO

This means that you can easily use KMDF to write a keyboard port driver, someone else has already responded on which IOCTLs you need to support, it is not that large of a problem space. You still have the issue of communication with your application. A control device or a raw PDO is required. You have a few other options though

o kbdfiltr: this is not tied to a particular data format (HID, i8042prt) or bus (i8042prt, usb, Bluetooth). There are ps2 specific parts, but you can remove those. You still need a control device/raw PDO to communicate with the app. You do depend on at least one keyboard being present.

o a HID mini driver: in this case you are lower in the stack, the 6001 has a sample that uses KMDF for the HID minidriver. In this case you need to create an extra top level collection that will be exposed as a PDO by HIDClass

I personally would choose a filter, it is less confusing to the user and if there are no keyboards, what kind of client scenario is it :wink: ?

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Sunday, November 04, 2007 1:29 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] KMDF Software-only keyboard device

Hello, folks -

I’m starting a new project, which will attempt to inject keystrokes (originating from user-mode code) via a device driver.

My first thought was to actually create a keyboard device driver, bypassing the class driver due to KMDF’s general lack of support for minidrivers. However, I couldn’t get the minimal driver to install (DiFx/devcon hangs after “DiFx Info: ENTER UpdateDriverForPlugAndPlayDevices…”; the driver is started and a device added but nothing after that; the device is of type FILE_DEVICE_KEYBOARD and exposes GUID_DEVINTERFACE_KEYBOARD - not sure what else I’m expected to do…).

So I decided to take a step back; writing a keyboard driver (as opposed to a minidriver) may be possible but it’s certainly not common. I can think of two other ways to do this:
1) Take the hidusbfx2 route (I just downloaded the 6001 R0 WDK just for this sample): make a minimal WDM minidriver with a KMDF filter on it.
2) Take the kbfiltr route: just a KMDF filter without a seperate software-only keyboard device. This should be sufficient to inject keystrokes, but I am not sure if the sample provided can be made to work for any type of system. (I have a computer at home that only has a USB keyboard, no PS2).

Plus, for either of these solutions, I believe I’d need an additional control device as well, for user-mode communication, correct?

I’d love to hear recommendations on which approach I should use. FYI, I have some KMDF experience but no WDM; PnP for WDM scares me…

-Steve


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Pnp and power management is not done by the root enumerator. Quite the opposite. Since it is a fake device, the PDO does nothing other then complete these irps as is. In the keyboard stack, kdclass is the power policy owner who maps System to Device power states for the stack, otherwise in another stack your WDM should be doing this.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hushmail.com
Sent: Sunday, November 04, 2007 3:41 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] KMDF Software-only keyboard device

Hello, Steve.

I’ve already written a virtual keyboard driver (WDM, non-KMDF).
It was actually much easier than I originally thought, because most power & PnP management is already done by the bus driver (root enumerator).

Here’s how I did it:

Create a function driver for an root-enumerated keyboard device. Depending on your requirements, you don’t need a bus- or minidriver.

  • Handle IRP_MJ_POWER & IRP_MJ_PNP. For the most part, you just have to pass them down untouched.
  • Handle IRP_MJ_CREATE & IRP_MJ_CLOSE. Just succeed them for Win32k’s Raw Input Thread to access your device. Kbdclass already does the privilege validation.
  • Handle IRP_MJ_INTERNAL_DEVICE_CONTROL to act like a real keyboard (IOCTL_INTERNAL_KEYBOARD_CONNECT, IOCTL_KEYBOARD_QUERY_ATTRIBUTES, IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION, IOCTL_KEYBOARD_QUERY_INDICATORS, IOCTL_KEYBOARD_QUERY_TYPEMATIC, IOCTL_KEYBOARD_SET_INDICATORS, IOCTL_KEYBOARD_SET_TYPEMATIC).
  • Write an INF file, create a root-enumerated device node (e.g., using devcon), and install your driver.

I suggest to look at WDK’s pnpi8042 as it does everything you need (and beyond).
You can mimic its default keyboard properties and optionally implement WMI support, but that is no requirement.

Yes, you will need a control device object for user-mode applications to access the driver.

The easiest solution is to edit kbfiltr, but you won’t have your dedicated keyboard device then.
Kbfiltr doesn’t necessarily care about the keyboard type it is filtering; it just has to receive IOCTL_INTERNAL_KEYBOARD_CONNECT originating from kbdclass.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Doron Holan wrote:

Pnp and power management is not done by the root enumerator. Quite the
opposite. Since it is a fake device, the PDO does nothing other then complete
these irps as is.

Thank you.
I was wondering how the root enumerator (which technically is a bus driver, right?) handles power and PnP management.
So the answer is “complete as is” for all of them?

One other thing I’d like to mention to people that are considering
writing a driver like this: consider security.

One of the security features of Vista is that it prevents user mode
applications from using SendInput to send an “Enter” key that dismisses
a UAC dialog. Only keystrokes from physical keyboards (i.e. drivers),
are sent to session 0 dialogs like this. AFAIK, there’s no mechanism in
place for the OS to prevent a kernel mode driver from injecting a
keystroke from what it thinks is a physical keyboard.

Any driver that allows an injection of a keystroke from usermode,
therefore, exposes the OS to certain types of malware that it would be
less vulnerable to if the driver was not present.

I’m not necessarily saying “don’t do it”, but be aware that there are
costs beyond what might be obvious.

The same is true for mouse drivers, of course.

To a lesser degree, the same is true of an app that runs with
uiAccess=TRUE in its manifest that forwards keystrokes or mouse
movements to elevated applications.

xxxxx@gmail.com wrote:

Hello, folks -

I’m starting a new project, which will attempt to inject keystrokes (originating from user-mode code) via a device driver.

My first thought was to actually create a keyboard device driver, bypassing the class driver due to KMDF’s general lack of support for minidrivers. However, I couldn’t get the minimal driver to install (DiFx/devcon hangs after “DiFx Info: ENTER UpdateDriverForPlugAndPlayDevices…”; the driver is started and a device added but nothing after that; the device is of type FILE_DEVICE_KEYBOARD and exposes GUID_DEVINTERFACE_KEYBOARD - not sure what else I’m expected to do…).

So I decided to take a step back; writing a keyboard driver (as opposed to a minidriver) may be possible but it’s certainly not common. I can think of two other ways to do this:

  1. Take the hidusbfx2 route (I just downloaded the 6001 R0 WDK just for this sample): make a minimal WDM minidriver with a KMDF filter on it.
  2. Take the kbfiltr route: just a KMDF filter without a seperate software-only keyboard device. This should be sufficient to inject keystrokes, but I am not sure if the sample provided can be made to work for *any* type of system. (I have a computer at home that only has a USB keyboard, no PS2).

Plus, for either of these solutions, I believe I’d need an additional control device as well, for user-mode communication, correct?

I’d love to hear recommendations on which approach I should use. FYI, I have some KMDF experience but no WDM; PnP for WDM scares me…

-Steve


Ray
(If you want to reply to me off list, please remove “spamblock.” from my
email address)

First of all, thanks to all the helpful replies. I have gotten it working just fine!

Installation took quite a while to figure out until I finally found this article:
http://www.osronline.com/article.cfm?id=446
which is really required reading for KMDF filter drivers.

And this brings me to my follow-up question: is the way I’m doing my installation really valid?
Here’s my steps:

  1. Call WdfPreDeviceInstall
  2. Call SetupInstallFilesFromInfSection to install the driver file
  3. Call SetupInstallServicesFromInfSection to register the driver
  4. Manually modify registry filter value so the filter driver will load
  5. Commit the file queue
  6. Call WdfPostDeviceInstall
    (then I restart the driver stack for all drivers in that class - which seems to always require a reboot for keyboard devices)

This is kind of a merge between the OSR article and the Microsoft filter driver installation instructions, because the OSR article uses SCM to register the driver (which Microsoft seems to be against, at least for PnP drivers), but the Microsoft instructions don’t support coinstallers. I also came across a quote while trying to figure this out: “There’re no concept of coinstallers for class filters…” (Scott Noone, OSR, 2006-Oct-10 on microsoft.public.development.device.drivers), and I don’t know why this concept wouldn’t exist…

BTW, I know I seem to be rather pedantic (some people are thinking “It works! Why ask if it’s right?”) - here’s my reason: I’m working as a contract programmer, and when I finish a job, I want it to be as forward-compatible as possible. Microsoft seems to frown on using CreateService to install a driver, so I don’t do it. My goal is just to do things as *right* as possible so that my clients have working software for the maximum future time. I know in my 23 years of programming, I’ve had to deal with a lot of code that was wrong but happened to work - and then when the library/compiler/OS/hardware was upgraded, it “suddenly” broke, and I don’t want my programs to have that reputation.

Thanks again for all the help, and especially for OSR’s KMDF filter driver installation article!
-Stephen Cleary