2017-02-23 555 views
0

从设备管理器,我有一个USB设备节点。我提取了它的“物理设备对象名称”(例如\Device\0000010f)。如何从设备管理器设备(例如从其“物理设备对象名称”)获取其驱动器号?

争取与NtOpenDirectoryObjectNtQueryDirectoryObjectNtOpenSymbolicLinkObjectNtQuerySymbolicLinkObjectQueryDosDevice小时,我无法找到一种方法,从“物理设备对象名称”获得实际的驱动器盘符(C:D:,...) 。

我正在寻找任何存储解决方案(USB/SATA/...)。我怎么做?


(还有很多类似的问题,他们没有回答例如,如何从物理设备对象名称去\Device\HarddiskVolumeXYZVolume{SOME_GUID}

+1

没有1:1映射为此,您可以有多个驱动器号安装在一个物理设备上。最好逐个查看驱动器号,找出他们的物理设备。 –

+0

@JonathanPotter,当然,但有1:N映射,在这种情况下,我需要安装在该设备上的所有分区(反之亦然 - 设备来自分区,并不重要)。好的 - “最好逐个查阅驱动器号并找出他们的物理设备” - 如何? – Tar

+0

@Tar:也没有1:N映射。卷不需要分配驱动器号。驱动器盘符从MS DOS新的日子里就被遗留下来了。 – IInspectable

回答

1

您查看的内容\Device\0000010f这是PDO物理设备通过一些总线驱动器创建的对象)(它具有标志DO_BUS_ENUMERATED_DEVICE

到它可以被附加了一些FDO功能设备对象)。如果这是从存储堆栈(基于CompatibleIDs串通过总线装置为这个PDO返回)典型FDO名称具有形式\Device\Harddisk%d\DR%d和公知的符号链接到它\Device\Harddisk%d\Partition0

磁盘驱动器FDO枚举分区体积和为每一个分区上创建PDO设备对象(与公知的符号链接\Device\Harddisk%d\Partition%d其中分区号总是> 0,Partition0是指整个磁盘FDO

平常分区是相同的体积,但并不总是(Partitions and Volumes)也注意到IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS - 它返回DISK_EXTENT结构的阵列 - 看看这里的DiskNumber -The number of the disk that contains this extent.因此体积可以放在多个磁盘。但在99%+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS回报你只一个DISK_EXTENT

所以如果你有路径存储堆栈,你可以做PDO什么?

  1. 打开设备 - 如果使用ZwOpenFile(当然这在 用户模式下工作),我们可以使用\Device\0000010f原样。如果我们要使用win32 api,我们需要为所有名称使用前缀\\?\GLOBALROOT。我们真的可以乘坐该巴士PDO打开,但因为磁盘FDO连接到PDO我们所有的请求都将通过被发送FDO和这里处理。期望的访问?SYNCHRONIZE就足够了(如果我们没有设置FILE_FLAG_OVERLAPPED api默示值,则将此标志添加到DESIRED_ACCESS
  2. IOCTL_STORAGE_GET_DEVICE_NUMBER发送到设备。检查 DeviceType == FILE_DEVICE_DISK && sdn.PartitionNumber == 0
  3. 发送IOCTL_DISK_GET_DRIVE_LAYOUT_EX用于得到一个可变大小 阵列PARTITION_INFORMATION_EX结构
  4. 基于DeviceNumber(我们在步骤2得到)和 PartitionNumber格式符号链接(我们在步骤3获得),以 的分区PDO - \\?\GLOBALROOT\Device\Harddisk%d\Partition%d
  5. 打开的分区PDOSYNCHRONIZE获得(足够,因为所有 IOCTL我们使用具有FILE_ANY_ACCESS
  6. 发送IOCTL_MOUNTDEV_QUERY_DEVICE_NAME分区
  7. 现在我们需要处理到MountManager设备(\\.\MountPointManager) 为送他IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH这个IOCTLmountmgr.h输入定义它需要MOUNTDEV_NAME 我们在步骤得到6.输出我们收到MOUNTMGR_VOLUME_PATHS 结构(mountmgr.h定义)我们也可以使用 IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS - 如果一切OK,我们像C:得到了 盘符列表,D:等。
  8. 在系统枚举磁盘驱动器,我们可以通过使用CM_Locate_DevNodeW CM_Get_Device_ID_ListW{4d36e967-e325-11ce-bfc1-08002be10318}过滤器,打开每个设备 实例,并最终通过电话查询 DEVPKEY_Device_PDOName CM_Get_DevNode_Property

OK,到这里代码示例正确的做到了这一切:

#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

好的哇。一旦我得到这个工作,如果我能......我会接受你的答案10次......但是,只是,呃,小事 - 你给'alloca(guz)'的那个'guz'是什么? – Tar

+0

@Tar'静态易失性UCHAR guz;'这真的是0.我使用'alloca(0)'获得顶层堆栈指针,但编译器非常'聪明',可以放弃这个调用。为了防止这种情况,我使用'alloca(guz)' - 这与''alloca(0)'具有相同的效果,但是因为我将'guz'定义为'volatile',所以这是禁用“优化”,所有工作都是例外。然而,这是我的(堆栈中分配内存的非常罕见的风格),你可以使用自己的方式。这不直接相关的问题(磁盘/卷/等) – RbMm

+0

仍然挣扎与'DeviceIoControl(hPartition,IOCTL_MOUNTDEV_QUERY_STABLE_GUID,0,0,&GUID,sizeof(guid),&dwBytesRet,NULL)':我得到'该请求不受支持'(错误编号50或0x32)。我确定并且使用'WinObj'装载了该设备(例如'\\?\ GLOBALROOT \ Device \ Harddisk2 \ Partition0')。 – Tar

1

另一种可能的解决方案,基于P owerShell和WMI独自:

$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

当我拥有的是powershell时,在另一台机器上非常有用 - 谢谢! – Tar