Skip to content

Commit 2aef79f

Browse files
committed
Improve VDI
1 parent b19a789 commit 2aef79f

File tree

7 files changed

+416
-114
lines changed

7 files changed

+416
-114
lines changed

dissect/hypervisor/disk/c_vdi.py

Lines changed: 85 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,90 +2,97 @@
22

33
from dissect.cstruct import cstruct
44

5-
# https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Storage/VDICore.h
6-
# https://forums.virtualbox.org/viewtopic.php?t=8046
7-
# 0000 3C 3C 3C 20 53 75 6E 20 78 56 4D 20 56 69 72 74 <<< Sun xVM Virt
8-
# 0010 75 61 6C 42 6F 78 20 44 69 73 6B 20 49 6D 61 67 ualBox Disk Imag
9-
# 0020 65 20 3E 3E 3E 0A 00 00 00 00 00 00 00 00 00 00 e >>>
10-
# 0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11-
#
12-
# 0040 7F 10 DA BE Image Signature
13-
# 01 00 01 00 Version 1.1
14-
# 90 01 00 00 Size of Header(0x190)
15-
# 01 00 00 00 Image Type (Dynamic VDI)
16-
# 0050 00 00 00 00 Image Flags
17-
# 00 00 00 00 00 00 00 00 00 00 00 00 Image Description
18-
# 0060-001F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
19-
# 0150 00 00 00 00
20-
# 00 02 00 00 offsetBlocks
21-
# 00 20 00 00 offsetData
22-
# 00 00 00 00 #Cylinders (0)
23-
# 0160 00 00 00 00 #Heads (0)
24-
# 00 00 00 00 #Sectors (0)
25-
# 00 02 00 00 SectorSize (512)
26-
# 00 00 00 00 -- unused --
27-
# 0170 00 00 00 78 00 00 00 00 DiskSize (Bytes)
28-
# 00 00 10 00 BlockSize
29-
# 00 00 00 00 Block Extra Data (0)
30-
# 0180 80 07 00 00 #BlocksInHDD
31-
# 0B 02 00 00 #BlocksAllocated
32-
# 5A 08 62 27 A8 B6 69 44 UUID of this VDI
33-
# 0190 A1 57 E2 B2 43 A5 8F CB
34-
# 0C 5C B1 E3 C5 73 ED 40 UUID of last SNAP
35-
# 01A0 AE F7 06 D6 20 69 0C 96
36-
# 00 00 00 00 00 00 00 00 UUID link
37-
# 01B0 00 00 00 00 00 00 00 00
38-
# 00 00 00 00 00 00 00 00 UUID Parent
39-
# 01C0 00 00 00 00 00 00 00 00
40-
# CF 03 00 00 00 00 00 00 -- garbage / unused --
41-
# 01D0 3F 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 -- garbage / unused --
42-
# 01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -- unused --
43-
# 01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -- unused --
44-
5+
# https://github.com/VirtualBox/virtualbox/blob/main/src/VBox/Storage/VDICore.h
456
vdi_def = """
46-
enum ImageType : uint32 {
47-
Dynamic = 0x01,
48-
Fixed = 0x02,
49-
Undo = 0x03,
50-
Differencing = 0x04
7+
enum VDI_IMAGE_TYPE {
8+
/** Normal dynamically growing base image file. */
9+
NORMAL = 1,
10+
/** Preallocated base image file of a fixed size. */
11+
FIXED,
12+
/** Dynamically growing image file for undo/commit changes support. */
13+
UNDO,
14+
/** Dynamically growing image file for differencing support. */
15+
DIFF,
5116
};
5217
53-
flag ImageFlags : uint32 {
54-
None = 0x00000000,
55-
Split2G = 0x00000001,
56-
ZeroExpand = 0x00000002
18+
flag VDI_IMAGE_FLAGS {
19+
/** Fill new blocks with zeroes while expanding image file. Only valid
20+
* for newly created images, never set for opened existing images. */
21+
ZERO_EXPAND = 0x0100,
5722
};
5823
59-
struct HeaderDescriptor {
60-
char FileInfo[64];
61-
uint32 Signature;
62-
uint32 Version;
63-
uint32 HeaderSize;
64-
ImageType ImageType;
65-
ImageFlags ImageFlags;
66-
char ImageDescription[256];
67-
uint32 BlocksOffset;
68-
uint32 DataOffset;
69-
uint32 NumCylinders;
70-
uint32 NumHeads;
71-
uint32 NumSectors;
72-
uint32 SectorSize;
73-
uint32 Unused1;
74-
uint64 DiskSize;
75-
uint32 BlockSize;
76-
uint32 BlockExtraData;
77-
uint32 BlocksInHDD;
78-
uint32 BlocksAllocated;
79-
char UUIDVDI[16];
80-
char UUIDSNAP[16];
81-
char UUIDLink[16];
82-
char UUIDParent[16];
83-
};
24+
typedef struct VDIDISKGEOMETRY {
25+
/** Cylinders. */
26+
uint32_t Cylinders;
27+
/** Heads. */
28+
uint32_t Heads;
29+
/** Sectors per track. */
30+
uint32_t Sectors;
31+
/** Sector size. (bytes per sector) */
32+
uint32_t Sector;
33+
} VDIDISKGEOMETRY, *PVDIDISKGEOMETRY;
34+
35+
typedef struct VDIPREHEADER {
36+
/** Just text info about image type, for eyes only. */
37+
char szFileInfo[64];
38+
/** The image signature (VDI_IMAGE_SIGNATURE). */
39+
uint32_t u32Signature;
40+
/** The image version (VDI_IMAGE_VERSION). */
41+
uint32_t u32Version;
42+
} VDIPREHEADER, *PVDIPREHEADER;
43+
44+
/**
45+
* Size of Comment field of HDD image header.
46+
*/
47+
#define VDI_IMAGE_COMMENT_SIZE 256
48+
49+
/* NOTE: All the header versions are additive, so just use the latest one. */
50+
typedef struct VDIHEADER1PLUS {
51+
/** Size of this structure in bytes. */
52+
uint32_t cbHeader;
53+
/** The image type (VDI_IMAGE_TYPE_*). */
54+
VDI_IMAGE_TYPE u32Type;
55+
/** Image flags (VDI_IMAGE_FLAGS_*). */
56+
VDI_IMAGE_FLAGS fFlags;
57+
/** Image comment. (UTF-8) */
58+
char szComment[VDI_IMAGE_COMMENT_SIZE];
59+
/** Offset of blocks array from the beginning of image file.
60+
* Should be sector-aligned for HDD access optimization. */
61+
uint32_t offBlocks;
62+
/** Offset of image data from the beginning of image file.
63+
* Should be sector-aligned for HDD access optimization. */
64+
uint32_t offData;
65+
/** Legacy image geometry (previous code stored PCHS there). */
66+
VDIDISKGEOMETRY LegacyGeometry;
67+
/** Was BIOS HDD translation mode, now unused. */
68+
uint32_t u32Dummy;
69+
/** Size of disk (in bytes). */
70+
uint64_t cbDisk;
71+
/** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Should be a power of 2! */
72+
uint32_t cbBlock;
73+
/** Size of additional service information of every data block.
74+
* Prepended before block data. May be 0.
75+
* Should be a power of 2 and sector-aligned for optimization reasons. */
76+
uint32_t cbBlockExtra;
77+
/** Number of blocks. */
78+
uint32_t cBlocks;
79+
/** Number of allocated blocks. */
80+
uint32_t cBlocksAllocated;
81+
/** UUID of image. */
82+
char uuidCreate[16];
83+
/** UUID of image's last modification. */
84+
char uuidModify[16];
85+
/** Only for secondary images - UUID of previous image. */
86+
char uuidLinkage[16];
87+
/** Only for secondary images - UUID of previous image's last modification. */
88+
char uuidParentModify[16];
89+
/** LCHS image geometry (new field in VDI1.2 version. */
90+
VDIDISKGEOMETRY Geometry;
91+
} VDIHEADER1PLUS, *PVDIHEADER1PLUS;
8492
"""
8593

8694
c_vdi = cstruct().load(vdi_def)
8795

88-
VDI_SIGNATURE = 0xBEDA107F
89-
90-
UNALLOCATED = -1
91-
SPARSE = -2
96+
VDI_IMAGE_SIGNATURE = 0xBEDA107F
97+
VDI_IMAGE_BLOCK_FREE = ~0
98+
VDI_IMAGE_BLOCK_ZERO = ~1

dissect/hypervisor/disk/c_vdi.pyi

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Generated by cstruct-stubgen
2+
from typing import BinaryIO, Literal, TypeAlias, overload
3+
4+
import dissect.cstruct as __cs__
5+
6+
class _c_vdi(__cs__.cstruct):
7+
VDI_IMAGE_COMMENT_SIZE: Literal[256] = ...
8+
class VDI_IMAGE_TYPE(__cs__.Enum):
9+
NORMAL = ...
10+
FIXED = ...
11+
UNDO = ...
12+
DIFF = ...
13+
14+
class VDI_IMAGE_FLAGS(__cs__.Flag):
15+
ZERO_EXPAND = ...
16+
17+
class VDIDISKGEOMETRY(__cs__.Structure):
18+
Cylinders: _c_vdi.uint32
19+
Heads: _c_vdi.uint32
20+
Sectors: _c_vdi.uint32
21+
Sector: _c_vdi.uint32
22+
@overload
23+
def __init__(
24+
self,
25+
Cylinders: _c_vdi.uint32 | None = ...,
26+
Heads: _c_vdi.uint32 | None = ...,
27+
Sectors: _c_vdi.uint32 | None = ...,
28+
Sector: _c_vdi.uint32 | None = ...,
29+
): ...
30+
@overload
31+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
32+
33+
PVDIDISKGEOMETRY: TypeAlias = __cs__.Pointer[_c_vdi.VDIDISKGEOMETRY]
34+
class VDIPREHEADER(__cs__.Structure):
35+
szFileInfo: __cs__.CharArray
36+
u32Signature: _c_vdi.uint32
37+
u32Version: _c_vdi.uint32
38+
@overload
39+
def __init__(
40+
self,
41+
szFileInfo: __cs__.CharArray | None = ...,
42+
u32Signature: _c_vdi.uint32 | None = ...,
43+
u32Version: _c_vdi.uint32 | None = ...,
44+
): ...
45+
@overload
46+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
47+
48+
PVDIPREHEADER: TypeAlias = __cs__.Pointer[_c_vdi.VDIPREHEADER]
49+
class VDIHEADER1PLUS(__cs__.Structure):
50+
cbHeader: _c_vdi.uint32
51+
u32Type: _c_vdi.VDI_IMAGE_TYPE
52+
fFlags: _c_vdi.VDI_IMAGE_FLAGS
53+
szComment: __cs__.CharArray
54+
offBlocks: _c_vdi.uint32
55+
offData: _c_vdi.uint32
56+
LegacyGeometry: _c_vdi.VDIDISKGEOMETRY
57+
u32Dummy: _c_vdi.uint32
58+
cbDisk: _c_vdi.uint64
59+
cbBlock: _c_vdi.uint32
60+
cbBlockExtra: _c_vdi.uint32
61+
cBlocks: _c_vdi.uint32
62+
cBlocksAllocated: _c_vdi.uint32
63+
uuidCreate: __cs__.CharArray
64+
uuidModify: __cs__.CharArray
65+
uuidLinkage: __cs__.CharArray
66+
uuidParentModify: __cs__.CharArray
67+
Geometry: _c_vdi.VDIDISKGEOMETRY
68+
@overload
69+
def __init__(
70+
self,
71+
cbHeader: _c_vdi.uint32 | None = ...,
72+
u32Type: _c_vdi.VDI_IMAGE_TYPE | None = ...,
73+
fFlags: _c_vdi.VDI_IMAGE_FLAGS | None = ...,
74+
szComment: __cs__.CharArray | None = ...,
75+
offBlocks: _c_vdi.uint32 | None = ...,
76+
offData: _c_vdi.uint32 | None = ...,
77+
LegacyGeometry: _c_vdi.VDIDISKGEOMETRY | None = ...,
78+
u32Dummy: _c_vdi.uint32 | None = ...,
79+
cbDisk: _c_vdi.uint64 | None = ...,
80+
cbBlock: _c_vdi.uint32 | None = ...,
81+
cbBlockExtra: _c_vdi.uint32 | None = ...,
82+
cBlocks: _c_vdi.uint32 | None = ...,
83+
cBlocksAllocated: _c_vdi.uint32 | None = ...,
84+
uuidCreate: __cs__.CharArray | None = ...,
85+
uuidModify: __cs__.CharArray | None = ...,
86+
uuidLinkage: __cs__.CharArray | None = ...,
87+
uuidParentModify: __cs__.CharArray | None = ...,
88+
Geometry: _c_vdi.VDIDISKGEOMETRY | None = ...,
89+
): ...
90+
@overload
91+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
92+
93+
PVDIHEADER1PLUS: TypeAlias = __cs__.Pointer[_c_vdi.VDIHEADER1PLUS]
94+
95+
# Technically `c_vdi` is an instance of `_c_vdi`, but then we can't use it in type hints
96+
c_vdi: TypeAlias = _c_vdi
97+
98+
VDI_IMAGE_SIGNATURE: int
99+
VDI_IMAGE_BLOCK_FREE: int
100+
VDI_IMAGE_BLOCK_ZERO: int

0 commit comments

Comments
 (0)