Monitor external devices activity using WDM driver

Hello everyone. I'm developing a filter driver to monitor external devices connected to the PC via USB ports. I've had experience developing Non-PnP and filesystem minifilter WDM driver, but non on PnP, so currently i'm sticking on WDM model.

The requirement of my driver includes the abilities to

  • Detect arrival/removal of the device (with timestamp)
  • Allow/deny working of the device

After reading the book Programming the Microsoft Windows Driver Model 2nd Edition, i think that i can implement my driver in this flow:

  1. Create a filter device object (FiDO) that represent my filter driver
  2. Use IoRegisterPlugPlayNotification to register changes on USB interface
  3. Check if this is an GUID_DEVICE_INTERFACE_ARRIVAL event
  4. If it's true, use IoGetDeviceObjectPointer to get pointer to the device object of the target device
  5. Attach my FiDO to the top of the target device object (UpperFilter) to receive events
  6. If IRP_MN_START_DEVICE arrives to my FiDO, check if the target device should be allowed, return STATUS_ACCESS_DENIED if it should be block.

Is my flow OK? Is there anything I need to pay attention to?

I know that there are many posts in this forum recommend KMDF for working with the PnP, but as i've said I'm pretty familiar to WDM so I'll try to explore this before getting to KMDF. I'd also appreciated if you give me some articles with samples on how to build a filter driver on KMDF so that i can get my hands dirty on that.

Thanks in advance.

Your investment in time for KMDF will be well worth the trouble. This is especially true for PnP filters, where the KMDF framework handles all of the details you would otherwise miss, and there are a lot of them. Remember, KMDF is not the "new kid". KMDF is now 20 years old.

You said you want to detect changes "on USB interface". Which USB interface? A typical USB device has half a dozen drivers in its stack.

You can't just "create a filter device object". A PnP filter does not exist on its own. A PnP filter gets loaded when a driver stack is being created. Thus, you have to tell PnP what it is that you want to filter -- a specific device by hardware ID (a "device filter"), or a specific install class of devices (a "class filter"). It's up to you to set up the registry for that.

Also remember that there are already group policies available to block USB storage devices, no programming required. What other devices would you care about?

1 Like

also, the device interface notification is sent after the device successfully starts, which is too late for you to attach and fail the start.

1 Like

@Tim_Roberts I think that i'm going with the class filter since I'm not going to monitor USB storages only but also other devices connecting to the PC via USB port, like transreceivers, old SD cards that takes advantages of USB ports, etc.

Do you recommend any tutorials or books that guidelines on KMDF PnP filters and interactions on PnP devices? I would appreciate any suggestion.

@Doron_Holan I didn't know that before you stated. Many thanks for the insight :smiley:

An SD card reader will appear as a USB Storage device. The problem with doing a class driver is, what class will you filter? There isn't an obvious answer to that question.

How will you identify which devices you want to block and which you want to allow? There are exceptions to every rule, so you need a way around it. That's why these kinds of blockers are usually a bad idea.

The sample drivers are your best source of information. They are effusively commented.

I've found a pretty friendly sample on our website and is playing with it to understand how KMDF works and how it is different from WDM: A Generic Device Class Filter Using WDF โ€“ OSR https://www.osr.com/nt-insider/2020-issue1/a-generic-device-class-filter-using-wdf/. The article is well-explained. I'll also look into the example you gave.

As far as I know, if I use KMDF, I can easily (compared to the WDM model) get the USB Device Descriptors https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-device-descriptors of a device if it is connected to the USB hub. At the moment I'm focusing on USB class and I think I'll take advantage of the pair bDeviceClass:bDeviceSubClass to indicate what kind of the device is (aside from storage), then I'll check for the device id before making a decision of blocking or allowing.

I also notice that some of the storage devices will have same device id and i might need to use something called STORAGE_DEVICE_UNIQUE_IDENTIFIER https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/storduid/ns-storduid-_storage_device_unique_identifier to distinguish them. What do you think about that?

The ease of getting the USB descriptors depends on where you are in the stack. That determines what requests you can send. If you are below the function driver and above the hub, then you can send all the URBs you want. If you're above the function driver, then the driver won't understand the request.

Why do you care if devices have the same ID? The STORAGE_DEVICE_UNIQUE_IDENTIFIER happens several layers above USB. You always have to keep the driver layering in mind. The storage layer handle all storage devices, no matter what bus they are hooked to. The USB Storage drivers translate from the USB world to the storage world. If you're talking to USB, then you don't have any storage stuff to play with. It's all just URBs.

I'm thinking about attaching as a lower filter to the usb class. It is possible for me to get the device descriptor and work with URBs at this level? What challenges might i face when working at this level?

About the ID, there are different USBs I need to monitor. There might be 2 USBs with the same device id, but one is allowed (it does not include sensitive data) and another is not. So I need some mechanism to identify them. Device id is good for USB devices that comes from trusted vendors, but might not for common/cheap devices. That what's I think. Can you correct me if I'm missing something?