//-------------------------------------- //--- 010 Editor v5.0 Binary Template // // File: VHD interpretation // Author: lurker0ster@gmail.com // Revision: V1.0 // Purpose: Verify what I learn from Microsoft VHD specification. //-------------------------------------- BigEndian(); typedef uint64 ULONGLONG; enum OS { OS_WI2R = 0x57693272, OS_WINDOWS = 0x5769326B, OS_W2RU = 0x57327275, OS_W2KU = 0x57326B75, OS_MACINTOSH = 0x4D616320, OS_MACX = 0x4D163258, }; enum DISK { NONE = 0x0, DEPRECATE = 0x1, FIXED = 0x2, DYNAMIC = 0x3, DIFFERENCING = 0x4, DEPRECATE1= 0x5, DEPRECATE2 = 0x6, }; typedef struct{ char cookie[8]; /* Identifies original creator of the disk */ DWORD Features ; DWORD FileformatVersion; ULONGLONG DataOffset ; time_t TimeStamp ; //This is the number of seconds since January 1, 2000 12:00:00 AM in UTC/GMT char CreaterApplication[4]; DWORD CreaterVersion; OS CreaterHostOS; ULONGLONG OrginalSize; ULONGLONG CurrentSize; struct { WORD Cylinder; BYTE Heads; BYTE SectorsPerCylinder; }DiskGeometry; DISK DiskType; DWORD CheckSum ; BYTE UUID[16] ; BYTE SavedState ; BYTE hidden; //tapdisk-specific field BYTE Reserved[426]; }FOOTER ; string statecheck(BYTE SavedState ) { if (0x1 == SavedState) return "In saved state"; return "not saved"; } string feaRead(WORD Features) { string s; if (Features & 0x0001) { s=s+"Temporary, " ;} if (Features & 0x0002) { s=s+"Reserved, " ;} return s; } string CorrectTime(time_t TimeStamp) { /* VHD uses an epoch of 12:00AM, Jan 1, 2000. */ /* Need to adjust this to the expected epoch of 1970. */ return TimeTToString((DWORD)TimeStamp + 946684800); } string OffsetCheck(ULONGLONG DataOffset) { if((DataOffset & 0xFFFFFFFF) == 0xFFFFFFFF) { return "Fixed disks"; } return ""; } typedef struct { char Cookie[8]; ULONGLONG DataOffset; //unused ULONGLONG TableOffset; //pointer to BAT DWORD HeaderVersion; DWORD MaxTableEntries; //number of blocks in the disk DWORD BlockSize ; //does not include the size of block bitmap DWORD Checksum; BYTE ParentUUID[16]; //for differencing HD time_t ParentTimeStamp; DWORD reserved; BYTE parentUnicodeName[512]; typedef struct { DWORD PlatformCode; DWORD PlatformDataSpace; DWORD PlatformDataLength; DWORD reserved; ULONGLONG PlatformDataOffset; }ENTRY; ENTRY ParentLocatorEntry[8]; BYTE reserved1[256]; }DYNAMICDISKHDEAR ; string sizecmt(DWORD blocksize) { string s; SPrintf(s, "block siez:%dMB", blocksize/1024/1024); return s; } FOOTER copyOfFooter; DYNAMICDISKHDEAR DynamicDiskHeader; FSeek(DynamicDiskHeader.TableOffset); struct { DWORD entry[DynamicDiskHeader.MaxTableEntries] ; //1 entry for 4096 sectors (2MB) }bat ; //Block Allocation table string entryCmt(DWORD entry) { if (0xFFFFFFFF == entry) return "Unused"; return ""; } typedef struct { char magic[8]; //"tdbatmap" ULONGLONG batmap_offset; DWORD batmap_size; DWORD batmap_version; DWORD Checksum; }TDBATMAP; char magic[8]; if (Memcmp(magic, "tdbatmap", 8) == 0) { TDBATMAP batmap; }else{ FSkip(-8); } local int index = 0; local int BytesInSector = 512; local int SectorsPerBlock = DynamicDiskHeader.BlockSize / BytesInSector; local int BitmapBytes = SectorsPerBlock / 8; //local int ResetBytes = DynamicDiskHeader.BlockSize - BitmapBytes; //local int numsOfBlockAllocated = (FileSize()-512 - FTell() ) / (DynamicDiskHeader.BlockSize+BitmapBytes); typedef struct { BYTE bitmap[BitmapBytes]; //each bit represent a sector. 1: used, 0: full0s. BYTE data[DynamicDiskHeader.BlockSize]; }DATABLOCK; //DATABLOCK block[numsOfBlockAllocated]; do{ if (bat.entry[index] != 0xFFFFFFFF) { Printf("Block[%d] -> VHD sector:0x%x", index, bat.entry[index]); Printf(" VHD offset:0x%x\n", bat.entry[index]*512); FSeek(bat.entry[index]*512); DATABLOCK data; }else{ //Printf("Block[%d] sparse\n", index); } index ++; }while(index < DynamicDiskHeader.MaxTableEntries); FSeek(FileSize()-512); FOOTER Footer; //for demo only //offset is sector offset string readData( uint64 offset) { local uint64 BlockIndex = offset/SectorsPerBlock; local uint64 sectorIndex = offset%SectorsPerBlock; local uint64 byteoffset = offset/8; local uint64 bitfield = offset%8; if(bitfield & data[BlockIndex].bitmap[byteoffset]) { //spare Printf("Zeros sector"); } }