GetDriveType 無法區分移動硬碟與本地硬碟(同回傳 DRIVE_FIXED),透過 DeviceIoControl 查詢總線類型 (BusType) 準確識別 USB 裝置
Ring 3 (用戶模式) 實作
BOOL IsUsbDriver(TCHAR tchDrvName) {
TCHAR tcsDrvName[8] = TEXT("\\\\.\\X:");
tcsDrvName[4] = tchDrvName;
HANDLE hDevice = CreateFile(tcsDrvName, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) return FALSE;
STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery};
BYTE buff[1024] = {0};
PSTORAGE_DEVICE_DESCRIPTOR pDesc = (PSTORAGE_DEVICE_DESCRIPTOR)buff;
pDesc->Size = sizeof(buff);
DWORD dwOut;
BOOL res = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(query), pDesc, pDesc->Size, &dwOut, NULL);
CloseHandle(hDevice);
return res ? (pDesc->BusType == BusTypeUsb) : FALSE;
}
Ring 0 (核心模式) 實作
BOOLEAN IsUsbDriver(IN PDEVICE_OBJECT pDeviceObject) {
PIRP pIrp; PSTORAGE_DEVICE_DESCRIPTOR pDesc;
STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery};
CHAR buff[128]; KEVENT evt; NTSTATUS status; IO_STATUS_BLOCK iosb;
KeInitializeEvent(&evt, NotificationEvent, FALSE);
pIrp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_QUERY_PROPERTY,
pDeviceObject, &query, sizeof(query), buff, sizeof(buff),
FALSE, &evt, &iosb);
if (!pIrp) return FALSE;
status = IoCallDriver(pDeviceObject, pIrp);
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(&evt, Executive, KernelMode, FALSE, NULL);
status = iosb.Status;
}
if (!NT_SUCCESS(status)) return FALSE;
pDesc = (PSTORAGE_DEVICE_DESCRIPTOR)buff;
return pDesc->BusType == BusTypeUsb;
}
Ring 0 需配合 DiskDeviceObject 使用,參考部落格說明卷裝置與 DiskDeviceObject 關係。兩種方法皆透過查詢 StorageDeviceProperty 的 BusType 判斷是否為 USB 裝置,比 SetupDiGetDeviceRegistryProperty 簡潔可靠。