Skip to content

Commit c5b3451

Browse files
committed
Add support for Veeam Backup files (VBK)
1 parent 98a9a66 commit c5b3451

File tree

11 files changed

+1630
-178
lines changed

11 files changed

+1630
-178
lines changed

dissect/hypervisor/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from dissect.hypervisor.backup import vma, xva
1+
from dissect.hypervisor.backup import vbk, vma, xva
22
from dissect.hypervisor.descriptor import hyperv, ovf, pvs, vbox, vmx
33
from dissect.hypervisor.disk import hdd, qcow2, vdi, vhd, vhdx, vmdk
44
from dissect.hypervisor.util import envelope, vmtar
@@ -10,6 +10,7 @@
1010
"ovf",
1111
"pvs",
1212
"qcow2",
13+
"vbk",
1314
"vbox",
1415
"vdi",
1516
"vhd",

dissect/hypervisor/backup/c_vbk.py

+287
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
from dissect.cstruct import cstruct
2+
3+
vbk_def = """
4+
#define PAGE_SIZE 4096
5+
6+
/* Storage header */
7+
8+
struct StorageHeader {
9+
uint32 FormatVersion; /* 0x0000 */
10+
uint32 Initialized; /* 0x0004 */
11+
uint32 DigestTypeLength; /* 0x0008 */
12+
char DigestType[251]; /* 0x000C */
13+
uint32 SnapshotSlotFormat; /* 0x0107 format > 5 -> crc32c */
14+
uint32 StandardBlockSize; /* 0x010B */
15+
uint8 ClusterAlign; /* 0x010F */
16+
char Unk0[16]; /* 0x0120 */
17+
char ExternalStorageId[16]; /* 0x0130 */
18+
};
19+
20+
/* Snapshot header */
21+
22+
struct SnapshotSlotHeader {
23+
uint32 CRC;
24+
uint32 ContainsSnapshot;
25+
};
26+
27+
struct DirectoryRootRecord {
28+
int64 RootPage; /* Root page of the directory */
29+
uint64 Count; /* Number of children */
30+
};
31+
32+
struct BlocksStoreHeader {
33+
int64 RootPage; /* Root of the blocks store */
34+
uint64 Count; /* Number of blocks store entries */
35+
int64 FreeRootPage; /* Root of the free blocks tree */
36+
int64 DeduplicationRootPage; /* Root of the deduplication tree */
37+
int64 Unk0;
38+
int64 Unk1;
39+
};
40+
41+
struct CryptoStoreRecord {
42+
int64 RootPage; /* Root of the crypto store */
43+
};
44+
45+
struct SnapshotDescriptor {
46+
uint64 Version; /* Acts as a sequence number, highest is active slot */
47+
uint64 StorageEOF; /* End of file, aka file size */
48+
uint32 BanksCount; /* Number of banks */
49+
DirectoryRootRecord DirectoryRoot; /* Directory root record */
50+
BlocksStoreHeader BlocksStore; /* Blocks store header */
51+
CryptoStoreRecord CryptoStore; /* Crypto store record */
52+
uint64 Unk0;
53+
uint64 Unk1;
54+
};
55+
56+
struct BankDescriptor {
57+
uint32 CRC;
58+
uint64 Offset;
59+
uint32 Size;
60+
};
61+
62+
struct BanksGrain {
63+
uint32 MaxBanks;
64+
uint32 StoredBanks;
65+
// BankDescriptor Banks[StoredBanks];
66+
};
67+
68+
/* Block headers */
69+
70+
struct BankHeader {
71+
uint16 PageCount;
72+
uint16 Flags;
73+
char Unk0[3064];
74+
uint64 Unk1;
75+
char Unk2[1020];
76+
};
77+
78+
struct BankHeaderV71 {
79+
uint16 PageCount;
80+
uint16 Flags; /* 2 == encrypted */
81+
char Unk0[3072];
82+
char KeySetId[16];
83+
char Unk1[16];
84+
char Unk2[16];
85+
uint32 Unk3;
86+
char Unk4[968];
87+
};
88+
89+
struct MetaBlobHeader {
90+
int64 NextPage;
91+
int32 Unk0;
92+
};
93+
94+
struct Lz4BlockHeader {
95+
uint32 Magic; /* 0xF800000F */
96+
uint32 CRC; /* CRC32C of the compressed data */
97+
uint32 SourceSize;
98+
};
99+
100+
/* DirItem headers */
101+
struct BlocksVectorHeader {
102+
uint64 RootPage;
103+
uint64 Count;
104+
};
105+
106+
struct SubFolderHeader {
107+
uint64 RootPage; /* 0x94 */
108+
uint32 Count; /* 0x9C */
109+
char Data[32]; /* 0xA0 */
110+
}; /* 0xC0 */
111+
112+
struct ExtFibHeader {
113+
uint16 UpdateInProgress; /* 0x94 */
114+
uint8 Unk3; /* 0x96 */
115+
uint8 Format; /* 0x97 Bit 3 == 1 */
116+
BlocksVectorHeader BlocksVector; /* 0x98 */
117+
uint64 FibSize; /* 0xA8 */
118+
uint64 Size; /* 0xB0 */
119+
uint8 FsObjAttachState; /* 0xB8 */
120+
char Data[7]; /* 0xB9 */
121+
}; /* 0xC0 */
122+
123+
struct IntFibHeader {
124+
uint16 UpdateInProgress; /* 0x94 */
125+
uint8 Unk3; /* 0x96 */
126+
uint8 Format; /* 0x97 Bit 3 == 1 */
127+
BlocksVectorHeader BlocksVector; /* 0x98 */
128+
uint64 FibSize; /* 0xA8 */
129+
uint64 Size; /* 0xB0 */
130+
uint8 FsObjAttachState; /* 0xB8 */
131+
char Data[7]; /* 0xB9 */
132+
}; /* 0xC0 */
133+
134+
struct PatchHeader {
135+
uint32 Unk0; /* 0x94 */
136+
BlocksVectorHeader BlocksVector; /* 0x98 */
137+
uint64 FibSize; /* 0xA8 Source file size */
138+
uint64 Unk4; /* 0xB0 */
139+
char Data[8]; /* 0xB8 */
140+
}; /* 0xC0 */
141+
142+
struct IncrementHeader {
143+
uint32 Unk0; /* 0x94 */
144+
BlocksVectorHeader BlocksVector; /* 0x98 */
145+
uint64 FibSize; /* 0xA8 Original FIB size */
146+
uint64 Unk4; /* 0xB0 */
147+
char Data[8]; /* 0xB8 */
148+
}; /* 0xC0 */
149+
150+
enum DirItemType : uint32 {
151+
None = 0,
152+
SubFolder = 1,
153+
ExtFib = 2,
154+
IntFib = 3,
155+
Patch = 4,
156+
Increment = 5,
157+
};
158+
159+
struct DirItemRecord {
160+
DirItemType Type; /* 0x00 */
161+
uint32 NameLength; /* 0x04 */
162+
char Name[128]; /* 0x08 */
163+
int64 PropsRootPage; /* 0x88 */
164+
uint32 Unk1; /* 0x90 */
165+
union { /* 0x94 */
166+
char Data[44];
167+
SubFolderHeader SubFolder;
168+
ExtFibHeader ExtFib;
169+
IntFibHeader IntFib;
170+
PatchHeader Patch;
171+
IncrementHeader Increment;
172+
};
173+
};
174+
175+
/* Block descriptors */
176+
177+
flag BlockFlags : uint8 {
178+
None = 0x00,
179+
Updated = 0x01,
180+
CommitInProgress = 0x02,
181+
};
182+
183+
enum BlockLocationType : uint8 {
184+
Normal = 0x00,
185+
Sparse = 0x01,
186+
Reserved = 0x02,
187+
Archived = 0x03, /* CompressedSize | (CompressionType << 32) */
188+
BlockInBlob = 0x04, /* BlockId? & 0x3FFFFFF | (BlobId << 26) | ((Offset >> 9) << 42) */
189+
BlockInBlobReserved = 0x05, /* BlockId? | 0xFFFFFFFFFC000000 */
190+
};
191+
192+
enum CompressionType : int8 {
193+
Plain = -1,
194+
RL = 2,
195+
ZLH = 3,
196+
ZLL = 4,
197+
LZ4 = 7,
198+
};
199+
200+
struct MetaTableDescriptor {
201+
int64 RootPage;
202+
uint64 BlockSize;
203+
uint64 Count;
204+
};
205+
206+
struct StgBlockDescriptor {
207+
uint8 Format; /* Format != 4 == legacy */
208+
uint32 UsageCounter;
209+
uint64 Offset;
210+
uint32 AllocatedSize;
211+
uint8 Deduplication;
212+
char Digest[16];
213+
CompressionType CompressionType;
214+
uint8 Unk0;
215+
uint32 CompressedSize;
216+
uint32 SourceSize;
217+
};
218+
219+
struct StgBlockDescriptorV7 {
220+
uint8 Format; /* Format != 4 == legacy */
221+
uint32 UsageCounter;
222+
uint64 Offset;
223+
uint32 AllocatedSize;
224+
uint8 Deduplication;
225+
char Digest[16];
226+
CompressionType CompressionType;
227+
uint8 Unk0;
228+
uint32 CompressedSize;
229+
uint32 SourceSize;
230+
char KeySetId[16];
231+
};
232+
233+
struct FibBlockDescriptor {
234+
uint32 BlockSize;
235+
BlockLocationType Type;
236+
char Digest[16];
237+
// union {
238+
// struct {
239+
// uint32 ArchiveUsedSize;
240+
// uint8 ArchiveCompressionType;
241+
// uint8 Unk3;
242+
// uint16 Unk4;
243+
// } Archived;
244+
// uint64 Offset;
245+
// };
246+
uint64 BlockId; /* For performance reasons we just put a uint64 here, but this is actually a union */
247+
BlockFlags Flags;
248+
};
249+
250+
struct FibBlockDescriptorV7 {
251+
uint32 BlockSize;
252+
BlockLocationType Type;
253+
char Digest[16];
254+
// union {
255+
// struct {
256+
// uint32 ArchiveUsedSize;
257+
// uint8 ArchiveCompressionType;
258+
// uint8 Unk3;
259+
// uint16 Unk4;
260+
// } Archived;
261+
// uint64 Offset;
262+
// };
263+
uint64 BlockId; /* For performance reasons we just put a uint64 here, but this is actually a union */
264+
BlockFlags Flags;
265+
char KeySetId[16];
266+
};
267+
268+
struct PatchBlockDescriptor {
269+
};
270+
271+
struct PatchBlockDescriptorV7 {
272+
};
273+
274+
/* Property dictionary */
275+
276+
enum PropertyType : int32 {
277+
UInt32 = 1,
278+
UInt64 = 2,
279+
AString = 3,
280+
WString = 4,
281+
Binary = 5,
282+
Boolean = 6,
283+
End = -1,
284+
};
285+
""" # noqa: E501
286+
c_vbk = cstruct()
287+
c_vbk.load(vbk_def)

0 commit comments

Comments
 (0)