FindFirstVolume 不返回 EFI 系统分区

Posted

技术标签:

【中文标题】FindFirstVolume 不返回 EFI 系统分区【英文标题】:FindFirstVolume does not return EFI system partition 【发布时间】:2017-03-05 15:54:17 【问题描述】:

我正在使用 FindFirstVolume/FindNextVolume 来获取机器上所有卷的列表。这工作得很好,但奇怪的是,由于某种原因,EFI 系统分区被跳过了。另一方面,Diskpart 返回 EFI 系统分区,磁盘管理 UI 也会显示它。

这是 diskpart 的输出:

DISKPART> list volume

  Volume ###  Ltr  Label        Fs     Type        Size     Status     Info
  ----------  ---  -----------  -----  ----------  -------  ---------  --------
  Volume 0     C                NTFS   Partition    476 GB  Healthy    Boot
  Volume 1         Recovery     NTFS   Partition    450 MB  Healthy    Hidden
  Volume 2                      FAT32  Partition    100 MB  Healthy    System
  Volume 3     D   Data         NTFS   Partition    953 GB  Healthy
  Volume 4     E   ESD-USB      FAT32  Removable     14 GB  Healthy

在该列表中,EFI 系统分区是第 2 卷。

FindFirstVolume/FindNextVolume 给我其他四个卷,但省略 EFI 系统分区。

任何想法如何获取 EFI 系统分区的卷 GUID 路径或以编程方式访问它的其他方式?

【问题讨论】:

***.com/questions/35102053/… 可能会给你一些想法 您是否以提升的权限运行?我不确切知道 Windows 如何保护 EFI 分区免受非特权用户的攻击,但它可能会导致在枚举时跳过该卷。 @HarryJohnston:是的,即使是本地系统 @HarryJohnston 我找到了分区属性 GPT_BASIC_DATA_ATTRIBUTE_HIDDEN 的描述。根据 MSDN,FindFirstVolume 会忽略具有该属性的分区。 EFI系统分区没有设置隐藏属性,但显然也是如此。来源:msdn.microsoft.com/en-us/library/windows/desktop/… Find*Volume internal send IOCTL_MOUNTMGR_QUERY_POINTS to mountmgr MOUNTMGR_DEVICE_NAME - 结果仅列出已安装的卷。 EFI 或 RAW 卷(分区)通常不挂载 - 所以不在 mountmgr 列表中。这与线程权限无关 【参考方案1】:

volume GUID path(即\??\Volume..)如果不是由FindFirstVolume/FindNextVolume返回则不存在,但我们可以通过不同的方式枚举系统中的所有卷。我们说可以使用Virtual Disk Service com api。 DISKPART> list volume 正是使用这个。另一种方式(更“低”和更快) - 使用 CM_Get_Device_ID_ListW 和 pszFilter = "71a27cdd-812a-11d0-bec7-08002be2092f"(在 devguid.h 中查看 GUID_DEVCLASS_VOLUME)而不是通过 @987654323 获取设备实例句柄@ 并使用CM_Get_DevNode_PropertyW 查询DEVPKEY_Device_PDOName - 我们得到了可以在ZwOpenFile 中使用的字符串(如\Device\HarddiskVolume<X>),然后使用一些ioctls(IOCTL_DISK_GET_PARTITION_INFO_EX 和其他)来获取卷属性。代码示例:

#include <initguid.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include <devpkey.h>
#include <diskguid.h>

void DumpVolume(HANDLE hFile);

void VolEnum()

    STATIC_WSTRING(DEVCLASS_VOLUME, "71a27cdd-812a-11d0-bec7-08002be2092f");

    enum  flags = CM_GETIDLIST_FILTER_CLASS|CM_GETIDLIST_FILTER_PRESENT ;

    ULONG len;
    ULONG cb = 0, rcb = 64;

    HANDLE hFile;
    IO_STATUS_BLOCK iosb;
    UNICODE_STRING ObjectName;
    OBJECT_ATTRIBUTES oa =  sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE ;

    if (!CM_Get_Device_ID_List_SizeW(&len, DEVCLASS_VOLUME, flags))
    
        PWSTR buf = (PWSTR)alloca(len << 1);
        if (!CM_Get_Device_ID_ListW(DEVCLASS_VOLUME, buf, len, flags))
        
            PVOID stack = buf;
            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);
                        

                        if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_PDOName, &PropertyType, pb, &rcb, 0)))
                        
                            if (PropertyType == DEVPROP_TYPE_STRING)
                            
                                DbgPrint("%S\n", sz);

                                RtlInitUnicodeString(&ObjectName, sz);
                                if (0 <= ZwOpenFile(&hFile, FILE_GENERIC_READ, &oa, &iosb, FILE_SHARE_VALID_FLAGS, 0))
                                
                                    DumpVolume(hFile);
                                    ZwClose(hFile);
                                
                            
                        

                     while (err == CR_BUFFER_SMALL);

                
                buf += 1 + wcslen(buf);
            
        
    


void DumpVolume(HANDLE hFile)

    NTSTATUS status;
    PARTITION_INFORMATION_EX pi;
    IO_STATUS_BLOCK iosb;

    if (0 <= (status = ZwDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, &pi, sizeof(pi))))
    
        CHAR PartitionName[40], *szPartitionName;

        PCSTR szps = "??";
        switch (pi.PartitionStyle)
        
        case PARTITION_STYLE_MBR: szps = "MBR";
            break;
        case PARTITION_STYLE_GPT: szps = "GPT";
            break;
        

        DbgPrint("%u %s %I64u(%I64x) %I64u ", 
            pi.PartitionNumber, 
            szps, 
            pi.StartingOffset.QuadPart, pi.StartingOffset.QuadPart, 
            pi.PartitionLength.QuadPart);

        switch (pi.PartitionStyle)
        

        case PARTITION_STYLE_MBR: 
            DbgPrint("type=%x boot=%x", pi.Mbr.PartitionType, pi.Mbr.BootIndicator);
            break;

        case PARTITION_STYLE_GPT:

            if (IsEqualGUID(pi.Gpt.PartitionType, PARTITION_ENTRY_UNUSED_GUID))
            
                szPartitionName = "UNUSED";
            
            else if (IsEqualGUID(pi.Gpt.PartitionType, PARTITION_SYSTEM_GUID))
            
                szPartitionName = "SYSTEM";
            
            else if (IsEqualGUID(pi.Gpt.PartitionType, PARTITION_MSFT_RESERVED_GUID))
            
                szPartitionName = "RESERVED";
            
            else if (IsEqualGUID(pi.Gpt.PartitionType, PARTITION_BASIC_DATA_GUID))
            
                szPartitionName = "DATA";
            
            else if (IsEqualGUID(pi.Gpt.PartitionType, PARTITION_MSFT_RECOVERY_GUID))
            
                szPartitionName = "RECOVERY";
            
            else if (IsEqualGUID(pi.Gpt.PartitionType, PARTITION_MSFT_SNAPSHOT_GUID))
            
                szPartitionName = "SNAPSHOT";
            
            else
            
                sprintf(szPartitionName = PartitionName, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 
                    pi.Gpt.PartitionType.Data1,
                    pi.Gpt.PartitionType.Data2,
                    pi.Gpt.PartitionType.Data3,
                    pi.Gpt.PartitionType.Data4[0],
                    pi.Gpt.PartitionType.Data4[1],
                    pi.Gpt.PartitionType.Data4[2],
                    pi.Gpt.PartitionType.Data4[3],
                    pi.Gpt.PartitionType.Data4[4],
                    pi.Gpt.PartitionType.Data4[5],
                    pi.Gpt.PartitionType.Data4[6],
                    pi.Gpt.PartitionType.Data4[7]);
            
            DbgPrint("[%s] %I64x \"%S\"", 
                szPartitionName,
                pi.Gpt.Attributes,
                pi.Gpt.Name);
            break;
        

        ULONG cb = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[32]);
        PFILE_FS_ATTRIBUTE_INFORMATION pffai = (PFILE_FS_ATTRIBUTE_INFORMATION)alloca(cb);

        switch (ZwQueryVolumeInformationFile(hFile, &iosb, pffai, cb, FileFsAttributeInformation))
        
        case STATUS_SUCCESS:
        case STATUS_BUFFER_OVERFLOW:
            DbgPrint(" \"%.*S\"", pffai->FileSystemNameLength >> 1 , pffai->FileSystemName);
            break;
        

        DbgPrint("\n");
    
    else
    
        DbgPrint("status=%x\n", status);
    

和调试输出

STORAGE\Volume\d2bfdb30-4d04-11e5-824e-806e6f6e6963#0000000012D00000
\Device\HarddiskVolume2
2 GPT 315621376(12d00000) 104857600 [SYSTEM] 8000000000000000 "EFI system partition" "FAT32"
STORAGE\Volume\d2bfdb30-4d04-11e5-824e-806e6f6e6963#0000000000100000
\Device\HarddiskVolume1
1 GPT 1048576(100000) 314572800 [RECOVERY] 8000000000000001 "Basic data partition" "NTFS"
STORAGE\Volume\d2bfdb30-4d04-11e5-824e-806e6f6e6963#0000000021100000
\Device\HarddiskVolume4
4 GPT 554696704(21100000) 255506513920 [DATA] 0 "Basic data partition" "NTFS"
STORAGE\Volume\d2bfdb30-4d04-11e5-824e-806e6f6e6963#0000000019100000
\Device\HarddiskVolume3
3 GPT 420478976(19100000) 134217728 [RESERVED] 8000000000000000 "Microsoft reserved partition" "RAW"
STORAGE\Volume\a4d55aa5-4d7f-11e5-8256-5cc5d4ea6270#0000000000007E00
\Device\HarddiskVolume5
1 MBR 32256(7e00) 32017013248 type=7 boot=1 "NTFS"

查看属性 - https://msdn.microsoft.com/en-us/library/windows/desktop/aa365449(v=vs.85).aspx

【讨论】:

非常有用,非常感谢!显然 CM_* 函数是唯一返回 EFI 系统分区(以及 RAW 分区)的函数。 SetupDi* 函数不这样做(我检查过)。

以上是关于FindFirstVolume 不返回 EFI 系统分区的主要内容,如果未能解决你的问题,请参考以下文章

见鬼,U盘空间怎么少了,原来是EFI分区搞的鬼,删除它

见鬼,U盘空间怎么少了,原来是EFI分区搞的鬼,删除它

第一启动项里没硬盘,没u盘的启动盘,只有EFI

clover如何使用UEFI引导和EFI驱动选择

惠普笔记本启动要手动选择efi才能进系统

ubuntu安装必须要有efi吗,win7与ubuntu12.04双系统如何使用efi,efi分区应必须是硬盘的第一个分区吗?