Windows过滤驱动中如何判断DeviceObject是否为便携设备?
正确判断便携可移动设备的方法
你之前直接用上层DeviceObject的Characteristics字段判断行不通——过滤驱动通常附加在功能设备对象(FDO)或中间过滤设备上,这些上层设备的属性不会直接反映物理硬件的真实特性,必须先获取到最底层的物理设备对象(PDO),再查询PDO的硬件属性才能准确判断。
以下是两种可靠的实现方式:
方法1:通过IoQueryDeviceProperty查询可移动属性
这是最直接的方式,通过系统API直接获取设备的可移动能力:
NTSTATUS IsDeviceRemovable(PDEVICE_OBJECT DeviceObject, BOOLEAN* IsRemovable) { if (!IsRemovable) return STATUS_INVALID_PARAMETER; *IsRemovable = FALSE; // 获取底层PDO PDEVICE_OBJECT pdo = IoGetAttachedDeviceReference(DeviceObject); if (!pdo) return STATUS_UNSUCCESSFUL; DEVICE_CAPABILITIES caps = {0}; caps.Size = sizeof(DEVICE_CAPABILITIES); NTSTATUS status = IoQueryDeviceProperty( pdo, DevicePropertyCapabilities, sizeof(caps), &caps, NULL ); if (NT_SUCCESS(status)) { *IsRemovable = caps.Removable; } ObDereferenceObject(pdo); return status; }
调用这个函数后,若IsRemovable返回TRUE,则说明当前设备是可移动便携设备(包括U盘、SD卡、移动硬盘等)。
方法2:通过存储设备属性查询更细节信息
如果需要更精准的判断(比如只拦截USB类便携设备),可以通过IOCTL_STORAGE_QUERY_PROPERTY查询存储设备的总线类型和可移动属性:
NTSTATUS IsUsbPortableDevice(PDEVICE_OBJECT DeviceObject, BOOLEAN* IsUsbPortable) { if (!IsUsbPortable) return STATUS_INVALID_PARAMETER; *IsUsbPortable = FALSE; PDEVICE_OBJECT pdo = IoGetAttachedDeviceReference(DeviceObject); if (!pdo) return STATUS_UNSUCCESSFUL; STORAGE_PROPERTY_QUERY query = {0}; query.PropertyId = StorageDeviceProperty; query.QueryType = PropertyStandardQuery; // 先查询所需缓冲区大小 STORAGE_DEVICE_DESCRIPTOR desc = {0}; desc.Size = sizeof(desc); ULONG returnedSize = 0; NTSTATUS status = IoBuildDeviceIoControlRequest( IOCTL_STORAGE_QUERY_PROPERTY, pdo, &query, sizeof(query), &desc, sizeof(desc), FALSE, NULL, NULL ); if (status == STATUS_BUFFER_TOO_SMALL) { // 分配足够的缓冲区 PVOID buffer = ExAllocatePool2(POOL_FLAG_PAGED, desc.Size, 'DevQ'); if (buffer) { RtlCopyMemory(buffer, &desc, sizeof(desc)); status = IoBuildDeviceIoControlRequest( IOCTL_STORAGE_QUERY_PROPERTY, pdo, &query, sizeof(query), buffer, desc.Size, FALSE, NULL, NULL ); if (NT_SUCCESS(status)) { PSTORAGE_DEVICE_DESCRIPTOR pDesc = (PSTORAGE_DEVICE_DESCRIPTOR)buffer; // 判断是否为USB总线且可移动 if (pDesc->BusType == BusTypeUsb && pDesc->RemovableMedia) { *IsUsbPortable = TRUE; } } ExFreePool(buffer); } } ObDereferenceObject(pdo); return status; }
关键注意事项
- 必须获取底层PDO:上层设备对象的属性是继承或修改后的,不代表物理硬件;
IoGetAttachedDeviceReference会返回设备栈最底层的PDO,用完记得调用ObDereferenceObject释放引用。 - 同步处理IRP:在过滤驱动中查询设备属性时,建议用同步方式发送IRP(避免异步操作带来的上下文问题),可以用
IoCreateIrp+IoCallDriver+KeWaitForSingleObject的组合实现同步调用(上述示例简化了IRP发送逻辑,实际实现需完善同步处理)。
内容的提问来源于stack exchange,提问作者Sinusoidal Depleneration
相关产品推荐
相关产品推荐

