hello all.
I want to develop a filter driver for controlling of devices in my system, I'm developing a filter driver for devices using wdf, but I have some questions: **1. In which callback should I identify the USB device type and read its device descriptor? Should I do this in EvtDevicePrepareHardware
, EvtDeviceD0Entry
, or somewhere else? I want to block certain USB devices from connecting to the system.
2. Where do I need to register this driver as an upper filter? Which registry path should I add it to?
What kind of devices? Have you looked at ANY of the WDF samples? There are many USB filters in there that can act as an example. There are also many filters across the Internet that do exactly what you are planning to do. This is not a new idea.
A USB function driver doesn't get started until the device is fully operational, so you can read descriptors as soon as AddDevice. In your case, you need to make your decision fairly early, otherwise the device will already be servicing requests.
The registration mechanism depends on whether you are writing a class filter, which gets loaded for every device in a specific install class, or a device filter, which applies to a single VID/PID combination.
I'm working on developing a filter driver to monitor and control onboard PCI peripheral devices (such as cameras, network cards, etc.) as well as USB PnP devices. So far, I haven’t found a reliable method to control onboard devices. However, I have successfully implemented an upper filter driver for the USB device setup class (GUID: {36FC9E60-C465-11CF-8056-444553540000}
), which allows interaction with USB devices in the EvtDevicePrepareHardware
callback.
Through this driver, I'm able to send IOCTLs to access device information. However, when attempting to read the DEVICE_DESCRIPTOR
, all fields (e.g., VID, PID) are returned with zero values, indicating that the descriptor may not be accessible at that point or requires a different approach.
i send IOCTL_GET_USB_DESCRIPTOR to lower pdo i give from WdfFdoInitWdmGetPhysicalDeice
I didnt find any source code or sample do this. not in windows driver samples and not in github (reading descriptors from upper filter driver)
IOCTL_GET_USB_DESCRIPTOR is part of the USB scanner interface. It is not used for other device classes.
In WDM, you would use UsbBuildGetDescriptorRequest to create a URB, wrap that in an IOCTL_INTERNAL_USB_SUBMIT_URB IRP, and call IoCallDriver.
In KMDF, there is a "rich" abstraction for USB drivers, so you can use WdfUsbTargetDeviceGetDeviceDescriptor.
Thank you.
I Found a solution by sending IOCTL_INTERNAL_USB_SUBMIT_URB
to lower PDO and reading device descriptor.
I think in upper filter driver working with WdfUsbDevice does not supported (i read in msdn references this facility is for client drivers)
#include <ntddk.h>
#include <usb.h>
#include <usbdlib.h> // For USBD structures
NTSTATUS GetUsbDeviceDescriptor(PDEVICE_OBJECT Pdo)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PURB urb = NULL;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
IO_STATUS_BLOCK ioStatus = {0};
KEVENT event;
PIRP irp;
// Allocate memory for the device descriptor
deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(USB_DEVICE_DESCRIPTOR), 'dscU');
if (!deviceDescriptor) {
return STATUS_INSUFFICIENT_RESOURCES;
}
// Allocate and initialize a URB
urb = (PURB)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), 'bruU');
if (!urb) {
ExFreePool(deviceDescriptor);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
UsbBuildGetDescriptorRequest(
urb,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0, // Index
0, // Language ID
deviceDescriptor,
NULL,
sizeof(USB_DEVICE_DESCRIPTOR),
NULL
);
// Initialize an event to wait for completion
KeInitializeEvent(&event, NotificationEvent, FALSE);
// Build the IRP
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
Pdo,
NULL,
0,
NULL,
0,
TRUE, // InternalDeviceIoControl
&event,
&ioStatus
);
if (!irp) {
ExFreePool(urb);
ExFreePool(deviceDescriptor);
return STATUS_INSUFFICIENT_RESOURCES;
}
// Set the URB in the next stack location
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(irp);
stack->Parameters.Others.Argument1 = urb;
// Send IRP down
status = IoCallDriver(Pdo, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (NT_SUCCESS(status)) {
DbgPrint("USB Device Descriptor:\n");
DbgPrint(" bLength: %u\n", deviceDescriptor->bLength);
DbgPrint(" bDescriptorType: %u\n", deviceDescriptor->bDescriptorType);
DbgPrint(" bcdUSB: 0x%04X\n", deviceDescriptor->bcdUSB);
DbgPrint(" bDeviceClass: %u\n", deviceDescriptor->bDeviceClass);
// ... Print other fields as needed ...
} else {
DbgPrint("Failed to get device descriptor: 0x%08X\n", status);
}
// Cleanup
ExFreePool(urb);
ExFreePool(deviceDescriptor);
return status;
}
Regarding the second question, I haven't found a solution to control all devices, including onboard devices. So far, I can control USB devices, but how can I check or manage, for example, network adapters or onboard cameras? Is it possible to control them using this driver?
No, there is no such mechanism.
You need to remember the distinction between what a device does and how it connects. When you have a USB device, that's not what it does. That's just how it connects. A network adapter can be a USB device (although they are sometimes PCIe), and onboard cameras are almost always USB devices.
And if you COULD intercept all devices, what do you think you're going to do with them? You don't know what these devices are. Even your generic USB filter has that problem. You don't know what all of these devices do. What kind of "control" do you think you're going to exert that applies to all device classes? What is the overall problem you're trying to solve?
There are already group policy controls to limit what devices are allowed to connect.
Usually this ends up being some ‘managed device’ security function like ‘no attachable storage’, but there is already a Windows policy for that.
when you say onboard, you probably mean PCIe. Drivers for those devices interact directly with the hardware, so other than a bus analyzer, there isn't even a theoretical way to do what you are suggesting.
Note that there are external PCIe, and internal USB. And those aren't the only bus types.