Skip to content

Commit

Permalink
Move VMA, XVA and VBK to dissect.archive (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
Schamper authored Nov 7, 2024
1 parent 4fe8392 commit 5dfad11
Show file tree
Hide file tree
Showing 17 changed files with 2,280 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1 @@
tests/data/basic.wim.gz filter=lfs diff=lfs merge=lfs -text
tests/data/* filter=lfs diff=lfs merge=lfs -text
290 changes: 290 additions & 0 deletions dissect/archive/c_vbk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
from dissect.cstruct import cstruct

vbk_def = """
#define PAGE_SIZE 4096
/* Storage header */
struct StorageHeader {
uint32 FormatVersion; /* 0x0000 */
uint32 Initialized; /* 0x0004 */
uint32 DigestTypeLength; /* 0x0008 */
char DigestType[251]; /* 0x000C */
uint32 SnapshotSlotFormat; /* 0x0107 format > 5 -> crc32c */
uint32 StandardBlockSize; /* 0x010B */
uint8 ClusterAlign; /* 0x010F */
char Unk0[16]; /* 0x0120 */
char ExternalStorageId[16]; /* 0x0130 */
};
/* Snapshot header */
struct SnapshotSlotHeader {
uint32 CRC;
uint32 ContainsSnapshot;
};
struct DirectoryRootRecord {
int64 RootPage; /* Root page of the directory */
uint64 Count; /* Number of children */
};
struct BlocksStoreHeader {
int64 RootPage; /* Root of the blocks store */
uint64 Count; /* Number of blocks store entries */
int64 FreeRootPage; /* Root of the free blocks tree */
int64 DeduplicationRootPage; /* Root of the deduplication tree */
int64 Unk0;
int64 Unk1;
};
struct CryptoStoreRecord {
int64 RootPage; /* Root of the crypto store */
};
struct SnapshotDescriptor {
uint64 Version; /* Acts as a sequence number, highest is active slot */
uint64 StorageEOF; /* End of file, aka file size */
uint32 BanksCount; /* Number of banks */
DirectoryRootRecord DirectoryRoot; /* Directory root record */
BlocksStoreHeader BlocksStore; /* Blocks store header */
CryptoStoreRecord CryptoStore; /* Crypto store record */
uint64 Unk0;
uint64 Unk1;
};
struct BankDescriptor {
uint32 CRC;
uint64 Offset;
uint32 Size;
};
struct BanksGrain {
uint32 MaxBanks;
uint32 StoredBanks;
// BankDescriptor Banks[StoredBanks];
};
/* Block headers */
struct BankHeader {
uint16 PageCount;
uint16 Flags;
char Unk0[3064];
uint64 Unk1;
char Unk2[1020];
};
struct BankHeaderV71 {
uint16 PageCount;
uint16 Flags; /* 2 == encrypted */
char Unk0[3072];
char KeySetId[16];
char Unk1[16];
char Unk2[16];
uint32 Unk3;
char Unk4[968];
};
struct MetaBlobHeader {
int64 NextPage;
int32 Unk0;
};
struct Lz4BlockHeader {
uint32 Magic; /* 0xF800000F */
uint32 CRC; /* CRC32C of the compressed data */
uint32 SourceSize;
};
/* DirItem headers */
struct BlocksVectorHeader {
uint64 RootPage;
uint64 Count;
};
struct SubFolderHeader {
uint64 RootPage; /* 0x94 */
uint32 Count; /* 0x9C */
char Data[32]; /* 0xA0 */
}; /* 0xC0 */
struct ExtFibHeader {
uint16 UpdateInProgress; /* 0x94 */
uint8 Unk3; /* 0x96 */
uint8 Format; /* 0x97 Bit 3 == 1 */
BlocksVectorHeader BlocksVector; /* 0x98 */
uint64 FibSize; /* 0xA8 */
uint64 Size; /* 0xB0 */
uint8 FsObjAttachState; /* 0xB8 */
char Data[7]; /* 0xB9 */
}; /* 0xC0 */
struct IntFibHeader {
uint16 UpdateInProgress; /* 0x94 */
uint8 Unk3; /* 0x96 */
uint8 Format; /* 0x97 Bit 3 == 1 */
BlocksVectorHeader BlocksVector; /* 0x98 */
uint64 FibSize; /* 0xA8 */
uint64 Size; /* 0xB0 */
uint8 FsObjAttachState; /* 0xB8 */
char Data[7]; /* 0xB9 */
}; /* 0xC0 */
struct PatchHeader {
uint32 Unk0; /* 0x94 */
BlocksVectorHeader BlocksVector; /* 0x98 */
uint64 FibSize; /* 0xA8 Source file size */
uint64 Unk4; /* 0xB0 */
char Data[8]; /* 0xB8 */
}; /* 0xC0 */
struct IncrementHeader {
uint32 Unk0; /* 0x94 */
BlocksVectorHeader BlocksVector; /* 0x98 */
uint64 FibSize; /* 0xA8 Original FIB size */
uint64 Unk4; /* 0xB0 */
char Data[8]; /* 0xB8 */
}; /* 0xC0 */
enum DirItemType : uint32 {
None = 0,
SubFolder = 1,
ExtFib = 2,
IntFib = 3,
Patch = 4,
Increment = 5,
};
struct DirItemRecord {
DirItemType Type; /* 0x00 */
uint32 NameLength; /* 0x04 */
char Name[128]; /* 0x08 */
int64 PropsRootPage; /* 0x88 */
uint32 Unk1; /* 0x90 */
union { /* 0x94 */
char Data[44];
SubFolderHeader SubFolder;
ExtFibHeader ExtFib;
IntFibHeader IntFib;
PatchHeader Patch;
IncrementHeader Increment;
};
};
/* Block descriptors */
flag BlockFlags : uint8 {
None = 0x00,
Updated = 0x01,
CommitInProgress = 0x02,
};
enum BlockLocationType : uint8 {
Normal = 0x00,
Sparse = 0x01,
Reserved = 0x02,
Archived = 0x03, /* CompressedSize | (CompressionType << 32) */
BlockInBlob = 0x04, /* BlockId? & 0x3FFFFFF | (BlobId << 26) | ((Offset >> 9) << 42) */
BlockInBlobReserved = 0x05, /* BlockId? | 0xFFFFFFFFFC000000 */
};
enum CompressionType : int8 {
Plain = -1,
RL = 2,
ZLH = 3,
ZLL = 4,
LZ4 = 7,
};
struct MetaTableDescriptor {
int64 RootPage;
uint64 BlockSize;
uint64 Count;
};
struct StgBlockDescriptor {
uint8 Format; /* Format != 4 == legacy */
uint32 UsageCounter;
uint64 Offset;
uint32 AllocatedSize;
uint8 Deduplication;
char Digest[16];
CompressionType CompressionType;
uint8 Unk0;
uint32 CompressedSize;
uint32 SourceSize;
};
struct StgBlockDescriptorV7 {
uint8 Format; /* Format != 4 == legacy */
uint32 UsageCounter;
uint64 Offset;
uint32 AllocatedSize;
uint8 Deduplication;
char Digest[16];
CompressionType CompressionType;
uint8 Unk0;
uint32 CompressedSize;
uint32 SourceSize;
char KeySetId[16];
};
struct FibBlockDescriptor {
uint32 BlockSize;
BlockLocationType Type;
char Digest[16];
// union {
// struct {
// uint32 ArchiveUsedSize;
// uint8 ArchiveCompressionType;
// uint8 Unk3;
// uint16 Unk4;
// } Archived;
// uint64 Offset;
// };
uint64 BlockId; /* For performance reasons we just put a uint64 here, but this is actually a union */
BlockFlags Flags;
};
struct FibBlockDescriptorV7 {
uint32 BlockSize;
BlockLocationType Type;
char Digest[16];
// union {
// struct {
// uint32 ArchiveUsedSize;
// uint8 ArchiveCompressionType;
// uint8 Unk3;
// uint16 Unk4;
// } Archived;
// uint64 Offset;
// };
uint64 BlockId; /* For performance reasons we just put a uint64 here, but this is actually a union */
BlockFlags Flags;
char KeySetId[16];
};
struct PatchBlockDescriptor {
};
struct PatchBlockDescriptorV7 {
};
/* Property dictionary */
enum PropertyType : int32 {
UInt32 = 1,
UInt64 = 2,
AString = 3,
WString = 4,
Binary = 5,
Boolean = 6,
End = -1,
};
""" # noqa: E501

c_vbk = cstruct().load(vbk_def)

PAGE_SIZE = c_vbk.PAGE_SIZE
"""VBK page size."""
60 changes: 60 additions & 0 deletions dissect/archive/c_vma.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from dissect.cstruct import cstruct

vma_def = """
#define VMA_BLOCK_BITS 12
#define VMA_BLOCK_SIZE (1 << VMA_BLOCK_BITS)
#define VMA_CLUSTER_BITS (VMA_BLOCK_BITS + 4)
#define VMA_CLUSTER_SIZE (1 << VMA_CLUSTER_BITS)
#define VMA_EXTENT_HEADER_SIZE 512
#define VMA_BLOCKS_PER_EXTENT 59
#define VMA_MAX_CONFIGS 256
#define VMA_MAX_EXTENT_SIZE (VMA_EXTENT_HEADER_SIZE + VMA_CLUSTER_SIZE * VMA_BLOCKS_PER_EXTENT)
/* File Format Definitions */
struct VmaDeviceInfoHeader {
uint32 devname_ptr; /* offset into blob_buffer table */
uint32 reserved0;
uint64 size; /* device size in bytes */
uint64 reserved1;
uint64 reserved2;
};
struct VmaHeader {
char magic[4];
uint32 version;
char uuid[16];
int64 ctime;
char md5sum[16];
uint32 blob_buffer_offset;
uint32 blob_buffer_size;
uint32 header_size;
char _reserved1[1984];
uint32 config_names[VMA_MAX_CONFIGS]; /* offset into blob_buffer table */
uint32 config_data[VMA_MAX_CONFIGS]; /* offset into blob_buffer table */
char _reserved2[4];
VmaDeviceInfoHeader dev_info[256];
};
struct VmaExtentHeader {
char magic[4];
uint16 reserved1;
uint16 block_count;
char uuid[16];
char md5sum[16];
uint64 blockinfo[VMA_BLOCKS_PER_EXTENT];
};
"""

c_vma = cstruct(endian=">").load(vma_def)


VMA_MAGIC = b"VMA\x00"
VMA_EXTENT_MAGIC = b"VMAE"
8 changes: 6 additions & 2 deletions dissect/archive/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ class InvalidHeaderError(Error):
pass


class NotADirectoryError(Error):
class FileNotFoundError(Error, FileNotFoundError):
pass


class FileNotFoundError(Error):
class IsADirectoryError(Error, IsADirectoryError):
pass


class NotADirectoryError(Error, NotADirectoryError):
pass


Expand Down
Empty file.
Loading

0 comments on commit 5dfad11

Please sign in to comment.