创建一个虚拟分区 [英] Create a Virtual Partition

查看:264
本文介绍了创建一个虚拟分区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用C ++在USB驱动器上创建隐藏的虚拟分区。

I am trying to create a hidden virtual partition on USB drive using C++.

我可以在Windows中使用虚拟磁盘API来做到这一点吗?

Can I use the virtual disk API in windows to do that?

推荐答案

是的,虚拟磁盘API支持在不分配驱动器号的情况下创建和装载卷的功能。这可以通过传递 ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER来完成 AttachVirtualDisk

Yes, the virtual disk API supports the ability to create and mount a volume without assigning it a drive letter. This is done by passing ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER to AttachVirtualDisk

// This call requires elevated privileges to succeed.
::AttachVirtualDisk(
    handle, // Handle returned by CreateVirtualDisk or OpenVirtualDisk
    NULL,
    ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER,
    0, // no provider-specific flags
    0, // no parameters
    NULL);

困难的部分是在没有驱动器号的情况下访问卷。虚拟磁盘API没有提供获取虚拟驱动器上卷列表的直接方法。这很重要,因为驱动器号不可用,因此必须通过UNC路径访问该卷。要获得UNC路径,您需要枚举所有已装入的卷以查找虚拟硬盘驱动器上的卷。通过打开每个已安装的卷并使用 DeviceIoControl 来检索与文件句柄关联的设备信息。

The difficult part is accessing the volume without a drive letter. The virtual disk API does not provide a straight forward way of getting a list of volumes that are on the virtual drive. This is important since you must access the volume through a UNC path as the drive letter is not available. To get the UNC path you need to enumerate all mounted volumes to find the volume(s) located on the virtual hard drive. This is done by opening each mounted volume and using DeviceIoControl to retrieve the device information associated with the file handle.

包含的示例执行以下步骤来:在我们的虚拟驱动器上创建,安装和访问隐藏卷。

The included example performs the following steps to create, mount and access a hidden volume on our virtual drive.


  1. 使用以下命令创建或打开虚拟磁盘文件 CreateVirtualDisk OpenVirtalDisk

  2. 使用 AttachVirtualDisk 您必须具有提升的特权才能成功执行此步骤

  3. 初始化设备。

  4. 在设备上创建卷

  5. 枚举已安装的卷以在虚拟磁盘上找到这些卷。

  1. Create or open the virtual disk file with CreateVirtualDisk or OpenVirtalDisk respectively.
  2. Attach the virtual disk with AttachVirtualDisk. You must have elevated privileges for this step to succeed.
  3. Initialize the device.
  4. Create a volume on the device.
  5. Enumerate mounted volumes to find the ones on the virtual disk.

[第3步和第4步需要从磁盘管理控制面板手动完成。当然,这可以通过编程方式完成,但是会向示例中添加更多代码。]

#include <iostream>
#include <fstream>
#include <string>
#include <virtdisk.h>

#pragma comment(lib, "virtdisk.lib")

// Fix unresolved link error
static const GUID VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = { 0xEC984AEC, 0xA0F9, 0x47e9, 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B };

#define ARRAY_SIZE(a)                               \
  ((sizeof(a) / sizeof(*(a))) /                     \
  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))


DWORD CreateDisk(PCWSTR virtualDiskFilePath, HANDLE *handle)
{
    VIRTUAL_STORAGE_TYPE storageType =
    {
        VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
        VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT
    };

    CREATE_VIRTUAL_DISK_PARAMETERS parameters = {};
    parameters.Version = CREATE_VIRTUAL_DISK_VERSION_1;
    parameters.Version1.MaximumSize = 1024 * 1024 * 1024;
    parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE;
    parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
    parameters.Version1.SourcePath = NULL;

    int result = ::CreateVirtualDisk(
        &storageType,
        virtualDiskFilePath,
        VIRTUAL_DISK_ACCESS_ALL,
        NULL,
        CREATE_VIRTUAL_DISK_FLAG_NONE,
        0,
        &parameters,
        NULL,
        handle);

    return result;
}


DWORD OpenDisk(PCWSTR virtualDiskFilePath, HANDLE *handle)
{
    VIRTUAL_STORAGE_TYPE storageType =
    {
        VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
        VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT
    };

    OPEN_VIRTUAL_DISK_PARAMETERS parameters =
    {
        OPEN_VIRTUAL_DISK_VERSION_1
    };

    parameters.Version1.RWDepth = 1024;

    return ::OpenVirtualDisk(
        &storageType,
        virtualDiskFilePath,
        VIRTUAL_DISK_ACCESS_ALL,
        OPEN_VIRTUAL_DISK_FLAG_NONE,
        &parameters,
        handle);
}



int main(int argc, char *argv[])
{
    LPTSTR  virtualDiskFilePath = _T("c:\\source\\drive.vhd");
    HANDLE  handle;
    DWORD   result;
    ULONG   bytesUsed;
    bool    vhdCreated = false;

    //  Create or open a virtual disk file
    result = CreateDisk(virtualDiskFilePath, &handle);
    if(result == ERROR_FILE_EXISTS)
    {
        result = OpenDisk(virtualDiskFilePath, &handle);
        if(result != ERROR_SUCCESS)
        {
            std::wcout << "Unable to open virtual disk" << std::endl;
            return 1;
        }
    }
    else if(result != ERROR_SUCCESS)
    {
        std::wcout << "Unable to create virtual disk" << std::endl;
        return 1;
    }
    else
    {
        vhdCreated = true;
    }


    //  Now that the virtual disk is open we need to mount it.
    //
    //  FROM MSDN:
    //  To attach and detach a virtual disk, you must also have the
    //  SE_MANAGE_VOLUME_NAME privilege present in your token. This privilege
    //  is stripped from an administrator's token when User Account Control is
    //  in use, so you may need to elevate your application to gain access to
    //  the unrestricted token that includes this privilege. 
    result = ::AttachVirtualDisk(
        handle,
        NULL,
        ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER,
        0, // no provider-specific flags
        0, // no parameters
        NULL);
    if(result != ERROR_SUCCESS)
    {
        std::wcout << "Unable to attach virtual disk" << std::endl;
        return 1;
    }

    if(result == ERROR_SUCCESS && vhdCreated == true)
    {
        std::wcout
            << "Virtual disk image created. Go into the Computer Management admin panel" << std::endl
            << "and add a volume and format it.\n" << std::endl;
        system("pause");
    }

    // Now we need to grab the device name \\.\PhysicalDrive#
    TCHAR   physicalDriveName[MAX_PATH];
    DWORD   physicalDriveNameSize = ARRAY_SIZE(physicalDriveName);

    result = ::GetVirtualDiskPhysicalPath(handle, &physicalDriveNameSize, physicalDriveName);
    if(result != ERROR_SUCCESS)
    {
        std::wcout << "Unable to retrieve virtual disk path" << std::endl;
        return 1;
    }
    const std::wstring deviceName = physicalDriveName;


    //  HACK!!! Wait for windows to complete the mount.
    Sleep(2500);


    // In order to get the UNC path of the volumes located on the virtual disk we
    // need to enumerate all mounted volumes and check which device they are located
    // on.
    std::wstring volumeName;

    TCHAR volumeNameBuffer[MAX_PATH];
    HANDLE hVol = ::FindFirstVolume(volumeNameBuffer, ARRAY_SIZE(volumeNameBuffer));
    if(hVol == INVALID_HANDLE_VALUE)
    {
        std::wcout << "Unable to find first volume" << std::endl;
        return 1;
    }
    do
    {
        //  Get rid of trailing backslash so we can open the volume
        size_t len = wcslen(volumeNameBuffer);
        if (volumeNameBuffer[len-1] == '\\')
        {
            volumeNameBuffer[len-1] = 0;
        }

        HANDLE volumeHandle = ::CreateFile( 
            volumeNameBuffer, 
            GENERIC_READ,  
            FILE_SHARE_READ | FILE_SHARE_WRITE,  
            NULL, 
            OPEN_EXISTING, 
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 
            NULL); 
        if(volumeHandle == INVALID_HANDLE_VALUE)
        {
            std::wcout << "Unable to open volume " << volumeNameBuffer << std::endl;
        }
        else
        {
            // We can grab the id of the device and use it to create a
            // proper device name.
            STORAGE_DEVICE_NUMBER deviceInfo = {0};
            if (::DeviceIoControl(
                    volumeHandle,
                    IOCTL_STORAGE_GET_DEVICE_NUMBER,
                    NULL,
                    0,
                    &deviceInfo,
                    sizeof(deviceInfo),
                    &bytesUsed,
                    NULL))
            {
                std::wstring tmpName(
                    std::wstring(L"\\\\.\\PhysicalDrive")
                    + std::to_wstring((long long)deviceInfo.DeviceNumber));
                if(_wcsicmp(tmpName.c_str(), deviceName.c_str()) == 0)
                {
                    volumeName = std::wstring(volumeNameBuffer) + L"\\\\";
                    CloseHandle(volumeHandle);
                    break;
                }
            }

            CloseHandle(volumeHandle);
        }
    }
    while(::FindNextVolume(hVol, volumeNameBuffer, ARRAY_SIZE(volumeNameBuffer)) != FALSE);

    ::FindVolumeClose(hVol);

    if(volumeName.size() == 0)
    {
        std::wcout << "Unable to locate a volume on this device" << std::endl;
        return 1;
    }

    std::wcout << "Device: " << physicalDriveName << std::endl;
    std::wcout << "Volume: " << volumeName << std::endl;


    std::wcout << "\n\nSuccess! Now create the file!" << std::endl;

    // Now let's create a file for fits and giggles
    std::ofstream   output;

    output.open(volumeName + L"hello.txt");
    if(output.fail())
    {
        std::wcout << "Unable to open output file." << std::endl;
        return 1;
    }
    output.close();

    // Volume will be unmounted when the application closes
    system("pause");

    return 0;
}

这篇关于创建一个虚拟分区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆