如何设置Virtual PC硬盘差异父路径

如何设置Virtual PC硬盘差异父路径

我有一个从以前的系统备份的旧 Windows XP Mode vhd,但是在新系统上运行它时遇到了困难。

vhd 是一个差异磁盘,其父磁盘是标准 Windows XP Mode 基础;我仍然有旧的父磁盘,并且已经验证它与我新安装的 XP Mode 中的 XP Mode 基础二进制相同。

但在新系统中,差异磁盘父级的路径与旧系统不同。

当我打开旧 XP 模式的 .vmcx 设置并选择“硬盘 1”时,“虚拟硬盘文件”设置正确,但“父磁盘:”字段指向错误的路径,我看不到任何编辑它的方法。

有人知道怎么做吗?

答案1

好吧,我自己解决了这个问题,但是它太难了。

父路径以几种不同的格式硬编码在 .vhd 中;在我的例子中,有相对路径和绝对路径,以 ASCII 和 UTF-16 编码,总共 4 条路径。您可以获取 .vhd 文件格式规范来自 Microsoft

但快速扫描字符串或者使用类似的实用程序(我在这里使用 Cygwin)来搜索字符串数据,可以比遍历 VHD 结构更容易地找到这些偏移量:

$ strings -t x Windows\ XP\ Mode-X.vhd | head -200 | grep vhd
40000 ..\..\..\..\..\..\..\other\xp-mode\Windows XP Mode base.vhd
40200 C:\other\xp-mode\Windows XP Mode base.vhd
$ strings -t x -e l Windows\ XP\ Mode-X.vhd | head -200 | grep vhd
40400 ..\..\..\..\..\..\..\other\xp-mode\Windows XP Mode base.vhd
40600 C:\other\xp-mode\Windows XP Mode base.vhd

这些字符串存储了大量空字节填充;我使用十六进制编辑器将路径更新到新位置。

但它不起作用;在 Virtual PC 设置编辑器中,路径显示为截断。字符串长度在其他地方编码;在我的情况下为 0x4AB、0x4C3 等。(我对旧路径长度进行了十六进制搜索)。我更新了这些长度,但 Virtual PC 设置编辑器认为 vhd 无效。我认为现在涉及校验和,下载了 VHD 规范,安装了 Word 文档查看器,以便我可以阅读 .doc,然后我编写了下面的程序。当将路径传递给 vhd 时,它的输出是更新的校验和以及校验和的位置;示例输出:

opening Windows XP Mode-X.vhd
dynamic header seems to be at 0x200
new checksum: ffffda30 at 0x224

使用十六进制编辑器输入这个新的校验和使得 vhd 工作,并且旧的 XP 模式成功启动。

校验和计算程序:

#include <fcntl.h>
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <unistd.h>

const int checksum_offset = 36;

long long flip_endian_ll(long long x)
{
    return ((x & 0x00000000000000FFULL) << 56)
        |  ((x & 0x000000000000FF00ULL) << 40)
        |  ((x & 0x0000000000FF0000ULL) << 24)
        |  ((x & 0x00000000FF000000ULL) << 8)
        |  ((x & 0x000000FF00000000ULL) >> 8)
        |  ((x & 0x0000FF0000000000ULL) >> 24)
        |  ((x & 0x00FF000000000000ULL) >> 40)
        |  ((x & 0xFF00000000000000ULL) >> 56);
}

int die(const char *msg)
{
    fprintf(stderr, "error: %s\n", msg);
    exit(1);
}

int main(int argc, const char *const *args)
{
    int f, r;
    long long dyn_ofs;
    unsigned char dyn_header[1024];

    if (argc != 2)
    {
        fprintf(stderr, "expected: .vhd argument\n");
        return 1;
    }

    printf("opening %s\n", args[1]);
    f = open(args[1], O_RDONLY | O_BINARY);
    if (f < 0)
        die("failed open");
    r = lseek(f, 0x10, SEEK_SET);
    if (r < 0)
        die("seek failed");
    r = read(f, &dyn_ofs, sizeof(dyn_ofs));
    if (r != 8)
        die("failed read");
    dyn_ofs = flip_endian_ll(dyn_ofs);
    printf("dynamic header seems to be at 0x%llx\n", dyn_ofs);

    r = lseek(f, dyn_ofs, SEEK_SET);
    if (r < 0)
        die("seek failed");
    r = read(f, dyn_header, sizeof(dyn_header));
    if (r != sizeof(dyn_header))
        die("read of dynamic header failed");

    if (memcmp("cxsparse", dyn_header, 8) != 0)
        die("dynamic header didn't start with cxsparse");

    {
        unsigned long sum = 0;
        int i;

        for (i = checksum_offset; i < checksum_offset + 4; ++i)
            dyn_header[i] = 0;
        for (i = 0; i < sizeof(dyn_header); ++i)
            sum += dyn_header[i];
        sum = ~sum; // flip_endian_l(~sum);
        printf("new checksum: %.8x at 0x%llx\n", sum, dyn_ofs + checksum_offset);
    }
    return 0;
}

这花了我几个小时,但最终我还是完成了。我相信最终会有人发布一个更容易完成此操作的 VHD 编辑器,但至少我再次进入了我的旧 XP 模式。

更新:有一种更简单的方法可以做到这一点,使用 PowerShell 编写一些 COM 对象脚本:https://obligatorymoniker.wordpress.com/2010/08/21/how-to-rebase-differencing-disk-vhds-or-how-to-change-the-parent-of-a-differencing-vhd-when-the-parent-has-moved/

在本质上:

$vpc=new-object -com VirtualPC.Application
$VHDChild = $vpc.GetHardDisk("C:\NAV2010.06.10_Diff")
$VHDParent = $vpc.GetHardDisk("\\devnas\Data_Backups SQLCluster1\NAV2010.06.10.vhd")
$VHDChild.Parent = $VHDParent

答案2

或者,如果您不想编写 C++ 代码来操作 .VHD 文件:

...从虚拟 PC 中,选择“虚拟磁盘向导”、“编辑现有虚拟磁盘”并选择有故障的差异磁盘,您将收到以下消息:

“父虚拟硬盘已被删除或已从其先前位置移走。请选择父虚拟硬盘的新位置。”

单击[更改...]并找到父磁盘。

相关内容