2017-09-01 122 views
-1

因此,我正在嘗試編寫僅附加到特定USB設備的微過濾器驅動程序,以區分使用產品ID +供應商ID +序列號組合的上述設備。使用IOCTL_STORAGE_QUERY_PROPERTY獲取序列號

我可以成功地將IOCTL_STORAGE_QUERY_PROPERTY發送到返回產品ID,供應商ID,序列號的設備。

我的問題是返回到我的微過濾器的序列號對於某些USB接口是正確的,但並非全部。

例如:當我打電話

C:\Windows\system32>wmic diskdrive get pnpdeviceid PNPDeviceID USBSTOR\DISK&VEN_SONY&PROD_STORAGE_MEDIA&REV_PMAP\5C3000637C2070A595&0 USBSTOR\DISK&VEN_BM&PROD_&REV_1.10\070007AA1F02CF40063F&0

而這些序列號從我的微過濾器返回:

Serial Number found 57C03A050905. Serial Number found 070007AA1F02CF400630.

因爲它可以看出,第二個設備的序列號成功返回,但不是第一個。那麼我的微過濾器正在接收的序列號是什麼?這是否存儲在可以查詢的地方?

如果需要,我可以附上代碼,但由於我正確地得到了一些序列號,我懷疑我的代碼是錯誤的。

編輯:代碼

STORAGE_PROPERTY_QUERY query; 
pQuery.PropertyId = StorageDeviceProperty; 
pQuery.QueryType = PropertyStandardQuery 

KeInitializeEvent(&event, NotificationEvent, FALSE); 
Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_QUERY_PROPERTY, pDeviceObject, (PVOID)&query, sizeof(query), infoBuffer, 
             sizeof(infoBuffer), FALSE, &event, &ioStatusBlock); 
if (Irp) { 
    if(!NT_SUCCESS(IoCallDriver(pDeviceObject, Irp))) 
     return STATUS_FLT_DO_NOT_ATTACH; 
} 
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 
pDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)infoBuffer; 

ULONG offset = pDescriptor->SerialNumberOfffset; 
size_t size; 
if (offset == 0) 
    return; 

PCHAR c = offset + &buffer[0]; 
size = strlen(c); 
*dest = ExAllocatePoolWithTag(PagedPool, size + 1, 'DIcI'); 
RtlZeroMemory(*dest, size + 1); 
RtlCopyMemory(*dest, c, size + 1); 

DbgPrint("Serial Number Found %s \n", *dest); 
// String comparison of serial number and more processing 

在我的外部硬盤進行測試,這是我從設備管理器

575834314137363534565656 

得到和我的微過濾器:

WX41A7654VVV 

似乎設備管理器中的序列號是我從微過濾器獲得的序列號的十六進制表示

57 58 34 31 41 37 36 35 34 56 56 56 

W X 4 1 A 7 6 5 4 V V V 

因此對於某些設備,它以十六進制格式表示,而其他設備是Char格式?

因此,無論如何,從內核級別獲取序列號或者它會更容易調用用戶應用程序?

+1

'...因爲我正確地得到一些序列號,我懷疑我的代碼是wrong'這是一種思維完全錯誤的方式...發佈您的代碼,並詢問是否有人能夠發現的bug – 4386427

+0

編輯的orignal post添加代碼 – qwn

+1

'infoBuffer,sizeof(infoBuffer)' - 這表示您使用硬編碼數組作爲'infoBuffer' - 這已經是錯誤。它的大小未知,你需要在運行時查詢它。正確的代碼 - https://stackoverflow.com/a/44656144/6401656 – RbMm

回答

0

STORAGE_DEVICE_DESCRIPTOR是可變長度結構。成功調用IOCTL_STORAGE_QUERY_PROPERTY後需要

檢查其尺寸成員確定 結構實際上需要的字節數。

但在您的代碼中,我查看infoBuffer, sizeof(infoBuffer) - 這意味着您使用STORAGE_DEVICE_DESCRIPTOR的硬編碼大小。

真的需要發送IOCTL_STORAGE_QUERY_PROPERTY和比較尺寸與對應OutputBufferLength成員,如果它更大 - 與大對應OutputBufferLength再次發送IOCTL_STORAGE_QUERY_PROPERTY

void PrintSerial(PDEVICE_OBJECT DeviceObject) 
{ 
    STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery }; 

    union { 
     PVOID buf; 
     PSTR psz; 
     PSTORAGE_DEVICE_DESCRIPTOR psdd; 
    }; 

    ULONG size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x100; 

    NTSTATUS status; 

    do 
    { 
     status = STATUS_INSUFFICIENT_RESOURCES; 

     if (buf = ExAllocatePool(PagedPool, size)) 
     { 
      switch (status = IoControlDevice(DeviceObject, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, size)) 
      { 
      case STATUS_SUCCESS: 
      case STATUS_BUFFER_OVERFLOW: 

       if (psdd->Version == sizeof(STORAGE_DEVICE_DESCRIPTOR)) 
       { 
        if (psdd->Size > size) 
        { 
         size = psdd->Size; 
         status = STATUS_BUFFER_OVERFLOW; 
        } 
        else 
        { 
         if (psdd->SerialNumberOffset) 
         { 
          DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset); 
         } 
         else 
         { 
          DbgPrint("SerialNumberOffset==0\n"); 
         } 
        } 
       } 
       else 
       { 
        status = STATUS_INVALID_PARAMETER; 
       } 
       break; 
      } 

      ExFreePool(buf); 
     } 
    } while (status == STATUS_BUFFER_OVERFLOW); 
} 

NTSTATUS IoControlDevice(
         PDEVICE_OBJECT DeviceObject, 
         ULONG IoControlCode, 
         PVOID InputBuffer, 
         ULONG InputBufferLength, 
         PVOID OutputBuffer, 
         ULONG OutputBufferLength, 
         BOOLEAN InternalDeviceIoControl = FALSE 
         ) 
{ 
    KEVENT Event; 
    KeInitializeEvent(&Event, NotificationEvent, FALSE); 

    IO_STATUS_BLOCK IoStatusBlock; 

    if (PIRP Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer, InputBufferLength, 
     OutputBuffer, OutputBufferLength, InternalDeviceIoControl, &Event, &IoStatusBlock)) 
    { 
     NTSTATUS status = IofCallDriver(DeviceObject, Irp); 

     if (status == STATUS_PENDING) 
     { 
      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0); 

      status = IoStatusBlock.Status; 
     } 

     return status; 
    } 

    return STATUS_INSUFFICIENT_RESOURCES; 
} 
+0

接受了答案,因爲它教會了我一些東西。雖然這並不能解決我的問題。 OSR論壇上的Slava Imameev表示:請求會傳播到設備堆棧中。完成它的第一個驅動程序/過濾器報告一些ID。在所有情況下,這可能不是有效的硬件ID。另外,有些設備沒有唯一的硬件ID。如果請求唯一ID,則驅動程序提供軟件生成的ID。在USB設備的情況下,該ID具有'&'符號。 我很可能會創建一個調用用戶級別應用程序的端口,從中可以檢索信息。謝謝您的幫助。 – qwn

+0

@qwn - 當然不是所有的硬件都有'SerialNumber'。這是如何正確查詢'STORAGE_DEVICE_DESCRIPTOR'。如果在某些情況下'SerialNumber'沒有返回 - 不是因爲代碼無效,而是因爲這個信息不存在。當然沒有什麼不同 - 在所有情況下都可以從用戶或內核空間 – RbMm

+0

查詢 - 這是對您的問題的回覆 - 「使用IOCTL_STORAGE_QUERY_PROPERTY獲取序列號」。如果你真的想要另一個 - 你需要問另一個問題。如果你想要一些其他信息 - 比如獲取設備接口 - 你需要調用[''IoGetDeviceInterfaces'](https://msdn.microsoft.com/en-us/library/windows/hardware/ff549186(v = vs.85)。 ASPX) – RbMm