首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

VHD 轉 IMG 工具原始碼解析:動態 VHD 區塊對應表 (BAT) 與位圖處理

     編輯:關於C++

工具架構

專案包含兩檔:vhd2img.cpp (主邏輯) 與 layout.h (VHD 磁碟版面結構定義)。以 C++ 實作,Visual Studio 2010 編譯。

核心資料結構 (layout.h)

磁碟頁腳

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];
};

BAT 區塊對應表

  • 陣列 u32 bat[max_bat_size]
  • 每項為**絕對扇區位移** (單位 512 bytes)
  • 0xFFFFFFFF 表示未配置 (稀疏區塊)

BATMAP (位圖標頭)

struct dd_batmap_hdr {
    char cookie[8];       // "tdbatmap"
    u64 batmap_offset;
    u32 batmap_size;      // 扇區數
    u32 batmap_version;
    u32 checksum;
};

關鍵演算法流程 (vhd2img.cpp)

1. 開啟 VHD 並驗證

  • 讀取尾部 hd_ftr,檢查 cookie、類型 (動態/差異)
  • 讀取開頭 dd_hdr,取得 block_size, max_bat_size, table_offset
  • 讀取 BAT 陣列
  • 嘗試讀取 BATMAP,判斷 is_have_batmap

2. 讀取單一區塊

int 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 表示該扇區有資料需複製。

3. 主迴圈轉換

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"

支援輸出至檔案或實體磁碟裝置。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved