專案包含兩檔:vhd2img.cpp (主邏輯) 與 layout.h (VHD 磁碟版面結構定義)。以 C++ 實作,Visual Studio 2010 編譯。
struct hd_ftr {
char cookie[8]; // "conectix"
u32 features; // HD_TEMPORARY | HD_RESERVED
u32 ff_version; // 0x00010000
u64 data_offset; // 絕對位移
u32 timestamp; // 秒數 since 2000-01-01
char crtr_app[4]; // 建立應用程式
u32 crtr_ver, crtr_os;
u64 orig_size, curr_size;
u32 geometry; // (cylinders<<16)|(heads<<8)|sectors
u32 type; // HD_TYPE_FIXED=2, DYNAMIC=3, DIFF=4
u32 checksum; // 1's complement
vhd_uuid_t uuid;
char saved, hidden, reserved[426];
};
struct dd_hdr {
char cookie[8]; // "cxsparse"
u64 data_offset; // 0xFFFFFFFFFFFFFFFF
u64 table_offset; // BAT 絕對位移
u32 hdr_ver; // 0x00010000
u32 max_bat_size; // BAT 最大項目數
u32 block_size; // 區塊大小 (預設 2MB, 2的冪次)
u32 checksum;
vhd_uuid_t prt_uuid; // 父磁碟 UUID
u32 prt_ts;
u32 res1;
char prt_name[512];
struct prt_loc loc[8];
char res2[256];
};
u32 bat[max_bat_size]0xFFFFFFFF 表示未配置 (稀疏區塊)struct dd_batmap_hdr {
char cookie[8]; // "tdbatmap"
u64 batmap_offset;
u32 batmap_size; // 扇區數
u32 batmap_version;
u32 checksum;
};
hd_ftr,檢查 cookie、類型 (動態/差異)dd_hdr,取得 block_size, max_bat_size, table_offsetis_have_batmapint read_vhd(vhd_info &vhd, byte* buf, u32 blkno) {
if (vhd.bat[blkno] == 0xFFFFFFFF) return 2; // 稀疏區塊,略過
// 計算區塊檔案位移 = bat[blkno] << 9 (SECTOR_SHIFT)
// 讀取 1 扇區位圖 (512 bytes) → spb_bitmap
// 讀取區塊資料 (block_size) → tbuf
// 依位圖逐扇區複製有效資料到 buf
}
位圖每 bit 對應區塊內 1 扇區,bit=1 表示該扇區有資料需複製。
for (i = 0; i < vhd.uBatNum; i++) {
memset(buf, 0, vhd.uBlkSize);
if (read_vhd(vhd, buf, i) != 1) continue; // 錯誤或稀疏
// 寫入目標檔案對應位置
liPos.QuadPart = (u64)i * vhd.uBlkSize;
SetFilePointerEx(hOut, liPos, &liNew, FILE_BEGIN);
WriteFile(hOut, buf, vhd.uBlkSize, &bWrite, NULL);
}
// 設定檔案結尾
SetEndOfFile(hOut);
VHD 磁碟格式為 **Big Endian**,程式碼提供 LE32()、LE64() 巨集轉換為主機序 (Little Endian)。
vhd2img.exe# 例: vhd2img.exe my.vhd d:\my.img # 直接寫入實體磁碟: vhd2img.exe my.vhd "\\.\PhysicalDrive1"
支援輸出至檔案或實體磁碟裝置。