简介
有时候我们想对某一类设备进行统一管理,比如常见的磁盘设备、卷设备、USB设备等等。
在WDM驱动模型中,就可以通过对某类设备,设置 上层过滤驱动 和 下层过滤驱动 的方式来实现。
WDM驱动模型
WDM模型中设备和驱动程序的层次结构如下图所示:

我们这里不讨论复杂的 WDM设备驱动 如何开发,只考虑过滤驱动逻辑相对简单。
添加某类设备的过滤驱动的方法,就是在对应设备类的注册表键下,创建 LowerFilters 值来表示
下层过滤驱动,创建 UpperFilters 值来表示 上层过滤驱动。
1
| HKLM\SYSTEM\CurrentControlSet\Control\Class\{36fc9e60-c465-11cf-8056-444553540000}
|
以 USB设备类 为例,假定我们过滤驱动的服务名为 MyUsbFltDrv ,在如上所示注册表路径下,创建
LowerFilters 值,并设定其内容为 MyUsbFltDrv ,注意该值为 REG_MULTI_SZ 类型。

创建完毕后,新接入USB设备时,操作系统就会启动我们的过滤驱动。
注意:假如过滤驱动启动失败,会导致IRP无法继续传递,从而所有新接入USB设备都无法识别。
USB设备类过滤
在WDM过滤驱动中,我们在 AddDevice 函数中附加过滤设备。USB设备的启动和停止都在
IRP_MJ_PNP 中处理,为了同时兼容XP和WIN7系统,我们还要处理 IRP_MJ_POWER 功能。
1 2 3 4 5 6 7 8 9 10 11 12 13
| NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath) { ULONG Index = 0; UNREFERENCED_PARAMETER(RegPath); for (Index = 0; Index <= IRP_MJ_MAXIMUM_FUNCTION; Index++) { DriverObject->MajorFunction[Index] = DispatchCommon; } DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; DriverObject->DriverExtension->AddDevice = MyAddDevice; return STATUS_SUCCESS; }
|
如下为我们关注的USB关键信息结构体定义,放入到每个设备的扩展内容中
1
| #define EXALLOCATE(x) ExAllocatePoolWithTag(NonPagedPool, (x), 'MEM');
|
1 2 3 4 5 6
| typedef struct _USB_INFO { UCHAR iType; USHORT idVendor; USHORT idProduct; WCHAR szSerial[128]; } USB_INFO, *PUSB_INFO;
|
1 2 3 4 5
| typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT TargetDevice; UCHAR iSerialOffset; USB_INFO UsbInfo; } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
每个新设备接入时,都会触发 AddDevice 函数,我们在这里创建过滤设备,并进行附加绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| NTSTATUS MyAddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDevice) { PDEVICE_EXTENSION DevExt = NULL; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT FilterDevice = NULL; Status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), NULL, PhysicalDevice->DeviceType, PhysicalDevice->Characteristics, FALSE, &FilterDevice); if (!NT_SUCCESS(Status)) return Status; FilterDevice->Flags |= PhysicalDevice->Flags; DevExt = (PDEVICE_EXTENSION)(FilterDevice->DeviceExtension); RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION)); Status = IoAttachDeviceToDeviceStackSafe( FilterDevice, PhysicalDevice, &DevExt->TargetDevice); if (!NT_SUCCESS(Status)) { IoDeleteDevice(FilterDevice); return Status; } FilterDevice->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; }
|
在 DispatchCommon 中不做任何处理,直接转发到下层设备
1 2 3 4 5 6 7 8
| NTSTATUS DispatchCommon(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PDEVICE_EXTENSION DevExt = NULL; DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(DevExt->TargetDevice, Irp); }
|
在 DispatchPower 中,针对不同的操作系统,使用的函数有所区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| NTSTATUS DispatchPower(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PDEVICE_EXTENSION DevExt = NULL; DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); #if (NTDDI_VERSION < NTDDI_VISTA) PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(DevExt->TargetDevice, Irp); #else IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(DevExt->TargetDevice, Irp); #endif }
|
在 DispatchPnp 中,我们只关注子功能 IRP_MN_START_DEVICE 和 IRP_MN_REMOVE_DEVICE 的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| NTSTATUS DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PDEVICE_EXTENSION DevExt = NULL; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT TargetDevice = NULL; PIO_STACK_LOCATION IrpStack = NULL; DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); TargetDevice = DevExt->TargetDevice; IrpStack = IoGetCurrentIrpStackLocation(Irp); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: Status = GetUsbType(DeviceObject); if (!NT_SUCCESS(Status)) break; Status = GetUsbSerial(DeviceObject); if (!NT_SUCCESS(Status)) break; if (DevExt->UsbInfo.iType == 0x8) { Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } break; case IRP_MN_REMOVE_DEVICE: IoDetachDevice(DevExt->TargetDevice); IoDeleteDevice(DeviceObject); break; } IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(TargetDevice, Irp); }
|
如何查询USB信息
查询USB信息,需要向 总线设备驱动 发送 URB 请求,所以在 下层过滤驱动 处进行处理。
具体查询步骤为,首先申请一段 URB 空间,初始化 URB 为查询相关信息的请求,
然后创建一个 IRP 请求,把 URB 绑定到 IRP 中,发送到 总线控制设备 进行查询。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| NTSTATUS UsbCallUSBDI(PDEVICE_OBJECT DeviceObject, PURB Urb) { PIRP Irp = NULL; KEVENT Event = { 0 }; NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK IoStatus = { 0 }; PIO_STACK_LOCATION IrpStack = NULL; PDEVICE_EXTENSION DevExt = NULL; KeInitializeEvent(&Event, NotificationEvent, FALSE); DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_SUBMIT_URB, DevExt->TargetDevice, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus); if (Irp == NULL) Status = STATUS_UNSUCCESSFUL; IrpStack = IoGetNextIrpStackLocation(Irp); IrpStack->Parameters.Others.Argument1 = Urb; Status = IoCallDriver(DevExt->TargetDevice, Irp); if (Status == STATUS_PENDING) { Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatus.Status; } return Status; }
|
如下为获取 设备描述符 信息的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| NTSTATUS UsbGetDeviceDescriptor( PDEVICE_OBJECT DeviceObject, PUSB_DEVICE_DESCRIPTOR *pDeviceDescriptor) { PURB Urb = NULL; NTSTATUS Status = STATUS_SUCCESS; Urb = (PURB)EXALLOCATE(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (Urb == NULL) return STATUS_UNSUCCESSFUL; *pDeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)EXALLOCATE( sizeof(USB_DEVICE_DESCRIPTOR)); if (*pDeviceDescriptor == NULL) { ExFreePool(Urb); return STATUS_UNSUCCESSFUL; } UsbBuildGetDescriptorRequest( Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, *pDeviceDescriptor, NULL, sizeof(USB_DEVICE_DESCRIPTOR), NULL); Status = UsbCallUSBDI(DeviceObject, Urb); ExFreePool(Urb); if (!NT_SUCCESS(Status)) return Status; return STATUS_SUCCESS; }
|
如下为获取 配置描述符 信息的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| NTSTATUS UsbGetConfigDescriptor( PDEVICE_OBJECT DeviceObject, PUSB_CONFIGURATION_DESCRIPTOR *pConfigDescriptor) { PURB Urb = NULL; USHORT wTotalLength = 0; NTSTATUS Status = STATUS_SUCCESS; Urb = (PURB)EXALLOCATE(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (Urb == NULL) return STATUS_UNSUCCESSFUL; *pConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)EXALLOCATE( sizeof(USB_CONFIGURATION_DESCRIPTOR)); if (*pConfigDescriptor == NULL) { ExFreePool(Urb); return STATUS_UNSUCCESSFUL; } UsbBuildGetDescriptorRequest( Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, *pConfigDescriptor, NULL, sizeof(USB_CONFIGURATION_DESCRIPTOR), NULL); Status = UsbCallUSBDI(DeviceObject, Urb); if (!NT_SUCCESS(Status)) { ExFreePool(Urb); return Status; } wTotalLength = (*pConfigDescriptor)->wTotalLength; ExFreePool(*pConfigDescriptor); *pConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)EXALLOCATE(wTotalLength); if (*pConfigDescriptor == NULL) { ExFreePool(Urb); return STATUS_UNSUCCESSFUL; } UsbBuildGetDescriptorRequest( Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, *pConfigDescriptor, NULL, wTotalLength, NULL); Status = UsbCallUSBDI(DeviceObject, Urb); ExFreePool(Urb); if (!NT_SUCCESS(Status)) return Status; return STATUS_SUCCESS; }
|
通过 设备描述符 和 配置描述符 可以得到该设备的VID、PID和设备类型信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| NTSTATUS GetUsbType(PDEVICE_OBJECT DeviceObject) { PDEVICE_EXTENSION DevExt = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; PUSB_DEVICE_DESCRIPTOR DeviceDescriptor = NULL; PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor = NULL; PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor = NULL; DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); do { Status = UsbGetDeviceDescriptor(DeviceObject, &DeviceDescriptor); if (!NT_SUCCESS(Status)) break; DevExt->UsbInfo.idVendor = DeviceDescriptor->idVendor; DevExt->UsbInfo.idProduct = DeviceDescriptor->idProduct; DevExt->iSerialOffice = DeviceDescriptor->iSerialNumber; Status = UsbGetConfigDescriptor(DeviceObject, &ConfigDescriptor); if (!NT_SUCCESS(Status)) break; InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx( ConfigDescriptor, ConfigDescriptor, -1, -1, 0x8, -1, -1); if (InterfaceDescriptor != NULL) { DevExt->UsbInfo.iType = 0x8; break; } InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx( ConfigDescriptor, ConfigDescriptor, -1, -1, 0xFF, -1, -1); if (InterfaceDescriptor != NULL) { DevExt->UsbInfo.iType = 0xFF; break; } Status = STATUS_SUCCESS; } while (0); if (DeviceDescriptor != NULL) ExFreePool(DeviceDescriptor); if (ConfigDescriptor != NULL) ExFreePool(ConfigDescriptor); return Status; }
|
如下为获取 字符串描述符 信息的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| NTSTATUS UsbGetStringDescriptor( IN PDEVICE_OBJECT DeviceObject, IN UCHAR DescriptorIndex, IN USHORT LanguageID, OUT PUSB_STRING_DESCRIPTOR StringDescriptor, IN UCHAR StringSize) { PURB Urb = NULL; NTSTATUS Status = STATUS_SUCCESS;; if ((StringDescriptor == NULL) || (StringSize == 0)) return STATUS_UNSUCCESSFUL; Urb = (PURB)EXALLOCATE(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (Urb == NULL) STATUS_UNSUCCESSFUL; UsbBuildGetDescriptorRequest( Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_STRING_DESCRIPTOR_TYPE, DescriptorIndex, LanguageID, StringDescriptor, NULL, StringSize, NULL); Status = UsbCallUSBDI(DeviceObject, Urb); ExFreePool(Urb); if (!NT_SUCCESS(Status)) return Status; return STATUS_SUCCESS; }
|
在 字符串描述符 中可能存在 多种语言 字符串,我们这里只获取 第1种语言 的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| NTSTATUS GetUsbString(PDEVICE_OBJECT DeviceObject) { PDEVICE_EXTENSION DevExt = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; PUSB_STRING_DESCRIPTOR StringLanguage = NULL; PUSB_STRING_DESCRIPTOR StringDescriptor = NULL; USHORT NumLanguageIDs = 0; PUSHORT LanguageIDs = NULL; do { DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); if (DevExt->iSerialOffset == 0) break; StringLanguage = (PUSB_STRING_DESCRIPTOR)EXALLOCATE(256); if (StringLanguage == NULL) break; Status = UsbGetStringDescriptor( DeviceObject, 0, 0, StringLanguage, 256); if (!NT_SUCCESS(Status)) break; if (StringLanguage->bLength < 2) break; NumLanguageIDs = (StringLanguage->bLength - 2) / 2; LanguageIDs = (PUSHORT)&(StringLanguage->bString[0]); StringDescriptor = (PUSB_STRING_DESCRIPTOR)EXALLOCATE(256); if (StringDescriptor == NULL) break; Status = UsbGetStringDescriptor( DeviceObject, DevExt->iSerialOffset, *LanguageIDs, StringDescriptor, 256); if (!NT_SUCCESS(Status)) break; if (StringDescriptor->bLength > 2) { RtlCopyMemory(DevExt->UsbInfo.szSerial, StringDescriptor->bString, StringDescriptor->bLength - 2); } Status = STATUS_SUCCESS; } while (0); if (StringLanguage != NULL) ExFreePool(StringLanguage); if (StringDescriptor != NULL) ExFreePool(StringDescriptor); return Status; }
|