How to Write Keyboard Filter Aware of New Devices?

Hi OSR Community!

Before you help I want to warn you that this is not a commercial product but rather something
for my own purposes. So if you feel you need to explain too much to have me understand
writing a proper keyboard driver just tell me and I will stop asking.
But I intend not to attend to a OSR consulting or a seminary because I’m studying electrical engineering
and not driver writing. The following is just for hobby purposes and understanding Windows better:

I’m currently attempting to write a PROPER WDM model filter driver for the keyboard device type.
Hence, I’d like to not fall back to undocumented functions or fields such as
ObReferenceObjectByName and pDeviceObject->DeviceObjectExtension with its “Lower” or “Attached” device object fields.

My filter driver should be capable of detecting which device arrived
and should then automatically attach to any newly arrived device of the keyboard type.
In msdn I found a function IoRegisterPlugPlayNotification which seems to do exactly that.

The DEVICE_INTERFACE_CHANGE_NOTIFICATION contains a unicode string with the symbolic link name in it.
This symbolic link is then transformed into a usual device name by leveraging
ZwOpenSymbolicLinkObject and ZwQuerySymbolicLinkObject.
Now, I wanted to get an initial pointer to the corresponding device stack by
calling IoGetDeviceObjectPointer.

The problem is now, IoGetDeviceObjectPointer fails with NTSTATUS
STATUS_SHARING_VIOLATION if I specify ACCESS_MASK of both FILE_READ_DATA or even 0,
which is the lowest access I can imagine. A brief reversing showed that IoGetDeviceObjectPointer
calls the ZwOpenFile call in order to get a FILE_OBJECT pointer on which in turn IoGetRelatedDeviceObject is
called. However, I assume that the ZwOpenFile call fails because this call not just returns a handle to
a FILE_OBJECT (out of an imaginary FILE_OBJECT pool) but rather leads to an IRP_MJ_CREATE
being created which is then sent to the foreign device object to ask for consent! And likely,
the driver controlling the device object (in my case a HID USB device)
tells me something like “No! GTFO here, I already have a device, I will never let you obtain another pointer or handle!”
(exclusive access mode)

Hence, I am now stuck. How am I supposed to get a device object pointer
somewhere into the target device stack if I cannot open the device normally and if it cannot
use the ObReferenceObjectByHandle with a ObSymbolicLinkObjectType* type?

In order to make the attachment work I would need to convert the symbolic link or the derived
target name SOMEHOW into an arbitrary PDEVICE_OBJECT pointing somewhere into the current target
device stack, according to the current symbolic link target.

TL;DR
How do I correctly write a keyboard filter driver aware of devices arriving in the future if I cannot attach my device
using IoAttachDevice or IoGetDeviceObjectPointer & IoAttachDeviceByDeviceStackSafe, and if I cannot
obtain a pointer into the corresponding device stack to the supplied symbolic link?

The only chance I have is forcing the attach to work even if the keyboard filter denies,
in terms of temporarily patching its IRP_MJ_CREATE routine, so it
will no longer return STATUS_SHARING_VIOLATION, but since this is an extreme ugly hack I wished
there was a documented solution.

I wanted to peek into the “kbfiltr” example but couldn’t find the WDM version, but I am almost
certain that Microsoft spent a notification routine there…
Is there a documented way to get a DEVICE_OBJECT pointer without the corresponding driver’s consent?
Since I am in kernelland I should be able to do what I want and If I want to open any device object
for me there is no reason to block that :wink:

If you think that I’m too unexperienced or too stupid, read the intro sentence…
It is just for me, you’re not going to give your knowledge away for then being
screwed by my better product! So no concurrence threat here.

Best Regards

Microwave89

P.S. Maybe you can also point me to some in your opinion valuable sources…

The proper way is to install it as a class upper filter below kbdclass. This will invoke your AddDevice routine for each keyboard started by the system. And a proper wdm driver is years worth of work, a proper kmdf driver is proper from the start

Sent from Outlook Mailhttp: for Windows 10

From: xxxxx@gmail.com
Sent: Wednesday, July 29, 2015 10:07 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] How to Write Keyboard Filter Aware of New Devices?

Hi OSR Community!

Before you help I want to warn you that this is not a commercial product but rather something
for my own purposes. So if you feel you need to explain too much to have me understand
writing a proper keyboard driver just tell me and I will stop asking.
But I intend not to attend to a OSR consulting or a seminary because I’m studying electrical engineering
and not driver writing. The following is just for hobby purposes and understanding Windows better:

I’m currently attempting to write a PROPER WDM model filter driver for the keyboard device type.
Hence, I’d like to not fall back to undocumented functions or fields such as
ObReferenceObjectByName and pDeviceObject->DeviceObjectExtension with its “Lower” or “Attached” device object fields.

My filter driver should be capable of detecting which device arrived
and should then automatically attach to any newly arrived device of the keyboard type.
In msdn I found a function IoRegisterPlugPlayNotification which seems to do exactly that.

The DEVICE_INTERFACE_CHANGE_NOTIFICATION contains a unicode string with the symbolic link name in it.
This symbolic link is then transformed into a usual device name by leveraging
ZwOpenSymbolicLinkObject and ZwQuerySymbolicLinkObject.
Now, I wanted to get an initial pointer to the corresponding device stack by
calling IoGetDeviceObjectPointer.

The problem is now, IoGetDeviceObjectPointer fails with NTSTATUS
STATUS_SHARING_VIOLATION if I specify ACCESS_MASK of both FILE_READ_DATA or even 0,
which is the lowest access I can imagine. A brief reversing showed that IoGetDeviceObjectPointer
calls the ZwOpenFile call in order to get a FILE_OBJECT pointer on which in turn IoGetRelatedDeviceObject is
called. However, I assume that the ZwOpenFile call fails because this call not just returns a handle to
a FILE_OBJECT (out of an imaginary FILE_OBJECT pool) but rather leads to an IRP_MJ_CREATE
being created which is then sent to the foreign device object to ask for consent! And likely,
the driver controlling the device object (in my case a HID USB device)
tells me something like “No! GTFO here, I already have a device, I will never let you obtain another pointer or handle!”
(exclusive access mode)

Hence, I am now stuck. How am I supposed to get a device object pointer
somewhere into the target device stack if I cannot open the device normally and if it cannot
use the ObReferenceObjectByHandle with a ObSymbolicLinkObjectType* type?

In order to make the attachment work I would need to convert the symbolic link or the derived
target name SOMEHOW into an arbitrary PDEVICE_OBJECT pointing somewhere into the current target
device stack, according to the current symbolic link target.

TL;DR
How do I correctly write a keyboard filter driver aware of devices arriving in the future if I cannot attach my device
using IoAttachDevice or IoGetDeviceObjectPointer & IoAttachDeviceByDeviceStackSafe, and if I cannot
obtain a pointer into the corresponding device stack to the supplied symbolic link?

The only chance I have is forcing the attach to work even if the keyboard filter denies,
in terms of temporarily patching its IRP_MJ_CREATE routine, so it
will no longer return STATUS_SHARING_VIOLATION, but since this is an extreme ugly hack I wished
there was a documented solution.

I wanted to peek into the “kbfiltr” example but couldn’t find the WDM version, but I am almost
certain that Microsoft spent a notification routine there…
Is there a documented way to get a DEVICE_OBJECT pointer without the corresponding driver’s consent?
Since I am in kernelland I should be able to do what I want and If I want to open any device object
for me there is no reason to block that :wink:

If you think that I’m too unexperienced or too stupid, read the intro sentence…
It is just for me, you’re not going to give your knowledge away for then being
screwed by my better product! So no concurrence threat here.

Best Regards

Microwave89

P.S. Maybe you can also point me to some in your opinion valuable sources…


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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</http:>

you not need parse SymbolicLink - just use it name in
IoGetDeviceObjectPointer(Notification->SymbolicLinkName, SYNCHRONIZE, &FileObject, &DeviceObject)
or
HANDLE hFile;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, Notification->SymbolicLinkName, OBJ_CASE_INSENSITIVE };
IO_STATUS_BLOCK iosb;
IoCreateFile(&hFile, SYNCHRONIZE, &oa, &iosb, 0, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, 0, 0, 0, CreateFileTypeNone, 0, IO_ATTACH_DEVICE)
second variant more universal - let open some device, which can not be open without IO_ATTACH_DEVICE flag

or for WDM add self filter to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4D36E96B-E325-11CE-BFC1-08002BE10318}\UpperFilters
in AddDevice you already got DeviceObject for Attach, will be not need use IoRegisterPlugPlayNotification

Wow, thank you both so much!
This really will help me a lot!

“Let’s open a device with IO_ATTACH_DEVICE flag”
Wow. I completely forgot I am working in KM and that don’t need to call ZwOpenFile!
Again, can’t tell how glad I am about your fast help!

I will try both solutions!
By means of installing, you mean something more sophisticated than basically ntdll!NtLoadDriver with nothing but the DriverService key path?
Are any further steps required except just loading the driver and writing the UpperFilters value?

Best Regards

Microwave89

Ok just tried to make it working using your second solution and succeeded.

Then, I was able in no time to reference the handle and end up getting the
much anticipated device object.
So if you happen to have the same problem just try using the IoCreateFile call in the exactly same matter as harald brown proposed.

The most important trick seems to be the undocumented? IO_ATTACH_DEVICE flag.
I will again reverse a bit, but as for now, I think it just skips calling the drivers IRP_MJ_CREATE dispatch routine what in fact would be exactly what I intended…

Thanks again!

And @ Doron, I know, that KMDF is much more proper nowadays, but I guess, it changes much
what I currently know about windows kernel internals. But I will have a look at it at some point.

Best Regards

Microwave89

In this case kmdf isn?t abstracting any internals, just the banality of copy/paste generic wdm code

Sent from Outlook Mailhttp: for Windows 10

From: xxxxx@gmail.com
Sent: Wednesday, July 29, 2015 3:15 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] How to Write Keyboard Filter Aware of New Devices?

Ok just tried to make it working using your second solution and succeeded.

Then, I was able in no time to reference the handle and end up getting the
much anticipated device object.
So if you happen to have the same problem just try using the IoCreateFile call in the exactly same matter as harald brown proposed.

The most important trick seems to be the undocumented? IO_ATTACH_DEVICE flag.
I will again reverse a bit, but as for now, I think it just skips calling the drivers IRP_MJ_CREATE dispatch routine what in fact would be exactly what I intended…

Thanks again!

And @ Doron, I know, that KMDF is much more proper nowadays, but I guess, it changes much
what I currently know about windows kernel internals. But I will have a look at it at some point.

Best Regards

Microwave89


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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</http:>

“I think it just skips calling the
drivers IRP_MJ_CREATE dispatch routine what in fact would be exactly what I
intended…”
you mistake. not skip. flag IO_ATTACH_DEVICE help in situation when device have DO_EXCLUSIVE flag and already open handle on it.
this faster help in situation with serial port (it usually have DO_EXCLUSIVE) but not with keyboard. so IoGetDeviceObjectPointer also mast work in case keyboard. in my drivers - this work
also exist undocumented flag for ZwOpenFile/ZwCreateFile -
#define IO_ATTACH_DEVICE_API 0x80000000

in IoCreate file exist next code:
// if The caller’s mode is kernel.

if (CreateOptions & IO_ATTACH_DEVICE_API)
{
Options |= IO_ATTACH_DEVICE;
CreateOptions &= ~IO_ATTACH_DEVICE_API;
}

interesting that flag IO_ATTACH_DEVICE_API used in IoAttachDevice function, when called ZwOpenFile, but not in IoGetDeviceObjectPointer. strange for my look.
hower this call IoGetDeviceObjectPointer(Notification->SymbolicLinkName, SYNCHRONIZE, &FileObject, &DeviceObject); also work with keyboard in my case. think you some mistake with shared access flags.
“I specify ACCESS_MASK of both FILE_READ_DATA or even 0”
try use SYNCHRONIZE. set shared access to 0 - usual return error begin from 2003 server, depended from global IopFailZeroAccessCreate.
win32k.sys already open file on keyboard with FILE_READ_DATA and no share mode - so IoCheckShareAccess (but not keyboard) return to you STATUS_SHARING_VIOLATION. so use SYNCHRONIZE as access mask and IoGetDeviceObjectPointer will be work too.