2017-02-23 1 views
0

Depuis le gestionnaire de périphériques, j'ai un nœud de périphérique USB. J'ai extrait son "nom d'objet de périphérique physique" (par exemple \Device\0000010f).Comment se rendre du périphérique device-manager (par exemple de son "nom d'objet périphérique physique") à sa lettre de lecteur?

Se battre pendant des heures avec NtOpenDirectoryObject, NtQueryDirectoryObject, NtOpenSymbolicLinkObject, NtQuerySymbolicLinkObject et QueryDosDevice, je ne pouvais pas trouver un moyen d'obtenir de ce « Physical Device Nom de l'objet » à la lettre de lecteur réelle (C:, D:, ...) .

Je cherche une solution de stockage (USB/SATA/...). Comment je fais ça?


(Il y a beaucoup de questions similaires, aucun d'entre eux répond par exemple comment obtenir du périphérique physique Nom de l'objet à \Device\HarddiskVolumeXYZ ou Volume{SOME_GUID})

+1

Il n'y a pas de correspondance 1: 1 pour cela, vous pouvez avoir plusieurs lettres de lecteur montées sur le périphérique physique. Mieux vaut parcourir les lettres de lecteur un par un et trouver leurs dispositifs physiques. –

+0

@JonathanPotter, bien sûr, mais il y a un mappage 1: N, et dans ce cas, j'ai besoin de toutes les partitions montées sur ce périphérique (ou vice versa - périphérique de partition, n'a pas d'importance). Ok - "Mieux vaut parcourir les lettres de lecteur un par un et trouver leurs dispositifs physiques" - comment? – Tar

+0

@Tar: Il n'y a pas de correspondance 1: N non plus. Un volume n'a pas besoin d'avoir une lettre de lecteur assignée. Les lettres de lecteur sont des restes des jours où MS DOS était nouveau. – IInspectable

Répondre

1

ce que vous affichez \Device\0000010f c'est AOP (Physical Device Object) créé par un chauffeur de bus (il a drapeau DO_BUS_ENUMERATED_DEVICE)

à elle peut être joint quelques FDO (Objet de périphérique fonctionnel). si cela est de la pile de stockage (basé sur CompatibleIDs chaînes renvoyées par le dispositif de bus pour ce AOP) typique nom FDO ont une forme \Device\Harddisk%d\DR%d et bien connu lien symbolique vers elle \Device\Harddisk%d\Partition0

pilote de disque FDO Énumérer partitions sur le volume et pour chaque partition créer AOP objet périphérique (avec bien connu lien symbolique \Device\Harddisk%d\Partition%d où le numéro de partition toujours> 0, Partition0 est reportez-vous à disque entier FDO)

partition habituelle est le même que le volume, mais pas toujours (Partitions and Volumes) noter également IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS - il revenir ensemble de structures DISK_EXTENT - regardez ici pour DiskNumber -The number of the disk that contains this extent. si le volume peut placé sur plusieurs disques. mais dans 99% + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS vous de retour seulement unDISK_EXTENT

donc ce que vous pouvez faire si vous avez chemin de PDO dans la pile de stockage?

  1. ouvrir l'appareil - si l'utilisation ZwOpenFile (bien sûr cela a fonctionné en mode utilisateur), nous pouvons utiliser \Device\0000010f comme il est. si nous voulons utiliser win32 api nous avons besoin d'utiliser le préfixe \\?\GLOBALROOT pour tous les noms. vraiment que nous ouvrons par ce bus AOP mais parce que le disque FDO est attaché à AOP toutes nos demandes seront envoyés via FDO et traitée ici. accès souhaité?SYNCHRONIZE est suffisant (en cas CreateFile si nous fixons pas FILE_FLAG_OVERLAPPED api ce drapeau ajouter implicitement à DESIRED_ACCESS)
  2. envoyer IOCTL_STORAGE_GET_DEVICE_NUMBER à l'appareil. vérifier que DeviceType == FILE_DEVICE_DISK && sdn.PartitionNumber == 0
  3. envoyer IOCTL_DISK_GET_DRIVE_LAYOUT_EX pour obtenir un tableau de taille variable de PARTITION_INFORMATION_EX structures
  4. sur la base DeviceNumber (que nous obtenons à l'étape 2) et PartitionNumber (que nous obtenons à l'étape 3) Format lien symbolique vers partition AOP-\\?\GLOBALROOT\Device\Harddisk%d\Partition%d
  5. partition ouverte AOP avec accès SYNCHRONIZE (assez parce que tous IOCTL que nous utilisons ont FILE_ANY_ACCESS de type
  6. envoyer IOCTL_MOUNTDEV_QUERY_DEVICE_NAME partitionner
  7. maintenant, nous devons gérer au dispositif MountManager (\\.\MountPointManager) pour lui envoyer IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH cette IOCTL défini dans mountmgr.h en entrée, il nécessite MOUNTDEV_NAME que nous obtenons à l'étape 6. sur la production que nous recevons MOUNTMGR_VOLUME_PATHS structure (également définie dans mountmgr.h) Sinon, nous pouvons utiliser IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS - si tout ok nous avons obtenu la liste des lettres de lecteur comme C:, D:, etc ..
  8. pour les lecteurs de disque énumèrent dans le système, nous pouvons utiliser CM_Get_Device_ID_ListW avec {4d36e967-e325-11ce-bfc1-08002be10318} filtre, ouvert tous les appareils exemple par CM_Locate_DevNodeW et enfin interroger pour DEVPKEY_Device_PDOName par appel CM_Get_DevNode_Property

ok, ici l'exemple de code correct qui fait tout ceci:

#include <mountmgr.h> 

// guz == 0 always, volatile for prevent CL "optimization" - it can drop alloca(0) call 
static volatile UCHAR guz; 

ULONG QueryPartitionW32(HANDLE hPartition, HANDLE hMountManager) 
{ 
    MOUNTDEV_STABLE_GUID guid; 
    ULONG dwBytesRet; 

    if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_STABLE_GUID, 0, 0, &guid, sizeof(guid), &dwBytesRet, NULL)) 
    { 
     DbgPrint("StableGuid = \\\\?\\Volume{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", 
      guid.StableGuid.Data1, guid.StableGuid.Data2, guid.StableGuid.Data3, 
      guid.StableGuid.Data4[0], 
      guid.StableGuid.Data4[1], 
      guid.StableGuid.Data4[2], 
      guid.StableGuid.Data4[3], 
      guid.StableGuid.Data4[4], 
      guid.StableGuid.Data4[5], 
      guid.StableGuid.Data4[6], 
      guid.StableGuid.Data4[7] 
     ); 
    } 

    // assume NumberOfDiskExtents == 1 
    VOLUME_DISK_EXTENTS vde; 
    if (DeviceIoControl(hPartition, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 0, 0, &vde, sizeof(vde), &dwBytesRet, 0)) 
    { 
     if (vde.NumberOfDiskExtents) 
     { 
      DbgPrint("ofs=%I64u, len=%I64u\n", vde.Extents->StartingOffset.QuadPart, vde.Extents->ExtentLength.QuadPart); 
     } 
    } 

    PVOID stack = alloca(guz); 

    union { 
     PVOID buf; 
     PMOUNTDEV_NAME pmdn; 
    }; 

    ULONG err; 
    ULONG cb = 0, rcb = sizeof(MOUNTDEV_NAME) + 0x10, InputBufferLength; 

    do 
    { 
     if (cb < rcb) 
     { 
      cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); 
     } 

     if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 0, 0, buf, cb, &dwBytesRet, NULL)) 
     { 
      DbgPrint("%.*S\n", pmdn->NameLength >> 1, pmdn->Name); 

      union { 
       PVOID pv; 
       PMOUNTMGR_VOLUME_PATHS pmvp; 
      }; 

      cb = 0, rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + 0x10, InputBufferLength = sizeof(MOUNTDEV_NAME) + pmdn->NameLength; 

      do 
      { 
       if (cb < rcb) 
       { 
        cb = RtlPointerToOffset(pv = alloca(rcb - cb), pmdn); 
       } 

       if (DeviceIoControl(hMountManager, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, 
        pmdn, InputBufferLength, pv, cb, &dwBytesRet, NULL)) 
       { 
        PWSTR sz = pmvp->MultiSz; 

        while(*sz) 
        { 
         DbgPrint("%S\n", sz); 
         sz += 1 + wcslen(sz); 
        } 
        return NOERROR; 
       } 

       rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + pmvp->MultiSzLength; 

      } while ((err = GetLastError()) == ERROR_MORE_DATA); 

      break; 
     } 

     rcb = sizeof(MOUNTDEV_NAME) + pmdn->NameLength; 

    } while ((err = GetLastError()) == ERROR_MORE_DATA); 

    return err; 
} 

ULONG EnumDiskPartitionsW32(HANDLE hDisk, HANDLE hMountManager) 
{ 
    STORAGE_DEVICE_NUMBER sdn; 

    ULONG dwBytesRet; 

    if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL)) 
    { 
     return GetLastError(); 
    } 

    if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0) 
    { 
     return ERROR_GEN_FAILURE; 
    } 

    WCHAR sz[128], *c = sz + swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition", sdn.DeviceNumber); 

    PVOID stack = alloca(guz); 

    union { 
     PVOID buf; 
     PDRIVE_LAYOUT_INFORMATION_EX pdli; 
    }; 

    ULONG cb = 0, rcb, PartitionCount = 4; 

    for (;;) 
    { 
     if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount]))) 
     { 
      cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); 
     } 

     if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL)) 
     { 
      if (PartitionCount = pdli->PartitionCount) 
      { 
       PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry; 

       do 
       { 
        if (!PartitionEntry->PartitionNumber) 
        { 
         continue; 
        } 

        _itow(PartitionEntry->PartitionNumber, c, 10); 

        DbgPrint("%S\n", sz); 

        HANDLE hPartition = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0); 

        if (hPartition != INVALID_HANDLE_VALUE) 
        { 
         QueryPartitionW32(hPartition, hMountManager); 
         CloseHandle(hPartition); 
        } 

       } while (PartitionEntry++, --PartitionCount); 
      } 

      return NOERROR; 
     } 

     switch (ULONG err = GetLastError()) 
     { 
     case ERROR_MORE_DATA: 
      PartitionCount = pdli->PartitionCount; 
      continue; 
     case ERROR_BAD_LENGTH: 
     case ERROR_INSUFFICIENT_BUFFER: 
      PartitionCount <<= 1; 
      continue; 
     default: 
      return err; 
     } 
    } 
} 

void DiskEnumW32(HANDLE hMountManager) 
{ 
    static const WCHAR DEVCLASS_DISK[] = L"{4d36e967-e325-11ce-bfc1-08002be10318}"; 

    enum { flags = CM_GETIDLIST_FILTER_CLASS|CM_GETIDLIST_FILTER_PRESENT }; 

    ULONG len; 
    if (!CM_Get_Device_ID_List_SizeW(&len, DEVCLASS_DISK, flags)) 
    { 
     PWSTR buf = (PWSTR)alloca(len * sizeof(WCHAR)); 

     if (!CM_Get_Device_ID_ListW(DEVCLASS_DISK, buf, len, flags)) 
     { 
      PVOID stack = buf; 
      static const WCHAR prefix[] = L"\\\\?\\GLOBALROOT"; 

      ULONG cb = 0, rcb = sizeof(prefix) + 0x20; 

      while (*buf) 
      { 
       DbgPrint("%S\n", buf); 

       DEVINST dnDevInst; 
       if (!CM_Locate_DevNodeW(&dnDevInst, buf, CM_LOCATE_DEVNODE_NORMAL)) 
       { 
        DEVPROPTYPE PropertyType; 
        int err; 

        union { 
         PVOID pv; 
         PWSTR sz; 
         PBYTE pb; 
        }; 

        do 
        { 
         if (cb < rcb) 
         { 
          rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack); 
         } 

         rcb -= sizeof(prefix) - sizeof(WCHAR); 

         if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_PDOName, &PropertyType, 
          pb + sizeof(prefix) - sizeof(WCHAR), &rcb, 0))) 
         { 
          if (PropertyType == DEVPROP_TYPE_STRING) 
          { 
           memcpy(pv, prefix, sizeof(prefix) - sizeof(WCHAR)); 
           DbgPrint("%S\n", sz); 

           HANDLE hDisk = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0); 

           if (hDisk != INVALID_HANDLE_VALUE) 
           { 
            EnumDiskPartitionsW32(hDisk, hMountManager); 
            CloseHandle(hDisk); 
           } 
          } 
          else 
          { 
           err = ERROR_GEN_FAILURE; 
          } 

          break; 
         } 

         rcb += sizeof(prefix) - sizeof(WCHAR); 

        } while (err == CR_BUFFER_SMALL); 

       } 
       buf += 1 + wcslen(buf); 
      } 
     } 
    } 
} 

void DiskEnumW32() 
{ 
    HANDLE hMountManager = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0); 

    if (hMountManager != INVALID_HANDLE_VALUE) 
    { 
     DiskEnumW32(hMountManager); 
     CloseHandle(hMountManager); 
    } 
} 
+0

Ok wow. Une fois que j'aurai commencé à travailler, j'accepterai votre réponse 10 fois si je peux ... mais juste, eh, petite chose - qu'est-ce que ce 'guz' vous donnez à' alloca (guz) '? – Tar

+0

@Tar 'statique UCHAR guz;' c'est vraiment 0. j'utilise 'alloca (0)' pour obtenir le pointeur de la pile supérieure, mais le compilateur est très 'intelligent' et peut laisser tomber cet appel. pour éviter cela i et utiliser 'alloca (guz)' - c'est le même effet que'alloca (0) 'mais parce que je définis' guz' comme 'volatile' c'est désactiver 'optimisation' et tout fonctionne comme excepté. Cependant, c'est mon (style très rare pour la mémoire allouée en pile), vous pouvez utiliser vous-même.ceci n'est pas directement lié à la question (disque/volumes/etc) – RbMm

+0

Toujours aux prises avec 'DeviceIoControl (hPartition, IOCTL_MOUNTDEV_QUERY_STABLE_GUID, 0, 0, & guid, taille de (guid), & dwBytesRet, NULL)': J'obtiens 'La demande n'est pas supportée '(erreur numéro 50 ou 0x32). Je me suis assuré et j'ai ce périphérique monté (par exemple '\\? \ GLOBALROOT \ Device \ Harddisk2 \ Partition0') avec' WinObj'. – Tar

1

Une autre solution possible pour vous, basée sur P owerShell et WMI seuls:

$PDO = "\Device\00000052" 
$DiskDriverData = Get-WmiObject Win32_PNPSignedDriver | Where {$_.PDO -eq $PDO} 
$DeviceID = """" + $DiskDriverData.DeviceID.Replace("\","\\") + """" 
$ComputerInfo = Get-WmiObject Win32_Computersystem 
$name = $ComputerInfo.Name 
$FullString = "\\$name\root\cimv2:Win32_PnPEntity.DeviceID=$DeviceID" 

$PNPDevice = Get-WmiObject Win32_PNPDevice | Where {$_.SystemElement -eq $FullString} 

$DiskDriveToPartition = Get-WmiObject -Class Win32_DiskDriveToDiskPartition | where {$_.Antecedent -eq $PNPDevice.SameElement} 

foreach ($i in $DiskDriveToPartition) { 
$Partition = Get-WmiObject -Class Win32_LogicalDiskToPartition | Where {$_.Antecedent -eq $i.Dependent} 
$PartitionLetter = $Partition.Dependent.split('"')[1] 
Write-Host -ForegroundColor Green "Detected Partition for the given PDO: $PartitionLetter" 
} 
+0

Très utile sur une autre machine, quand tout ce que j'ai est powershell - merci! – Tar