Xbox Virtual Disk

From XDevWiki
(Redirected from .xvd)
Jump to navigation Jump to search

XVD/XVC files are used by the Xbox One as file containers, an evolution on the STFS container format used by the Xbox 360.

It is theorized that the .xvd format is a modification of either the .vhd / .vhdx formats, or the .wim / .esd format. A function included in the Xbox One SDK named "XsCreateConvertVhd2XVD" gives credit to this theory.

XVD File Header[edit]

(this structure doesn't include the 0x200 byte signature at the top of XVD files)

Offset Length Type Information
0x00 0x08 string File magic (msft-xvd)
0x08 0x04 int32 Storage type
0x0C 0x04 int32 Unknown
0x10 0x04 int32 Unknown
0x14 0x04 int32 Unknown
0x18 0x08 int64 Unknown (seems to be important though)
0x20 0x10 bytes Content ID
0x30 0x10 bytes Duplicate of Content ID?
0x40 0x20 bytes Top Hash Table Hash
0x60 0x20 bytes Unknown (hash of some kind?)
0x80 0x4 int32 Unknown (seems to get used to check if XVC data is shifted, unsure how its used tho)
0x84 0x4 int32 Content type
0x88 0x4 int32 Unknown (seems important)
0x8C 0x4 int32 Unknown (seems important)
0x90 0x4 int32 XVC data size
0x94 0x4 int32 Block start offset (minus 0x4000 for header+hash table, divided by 0x400) (most likely incorrect in 99% of cases)
0x98 0x4 int32 Unknown
0x9C 0x70 bytes Unknown, padding?
0x10C 0x10 bytes Unknown
0x11C 0x10 bytes Unknown
0x12C 0x80 bytes Unknown, padding?
0x1AC 0x10 bytes Build ID, changed with every XVD package creation
0x1BC 0x8 int64 Package version
0x1C4 0xC3C bytes Rest of header, doesn't seem to be used
0xE00 0x2000 bytes padding up to the hash table / XVC info

Storage type is still a mystery, the following have been observed so far:

Type Encrypted Hashed Signed System File
0x07 N N N N
0x09 Y Y? Y Y
0x41 Y Y Y N
0x43 N Y Y N

Top hash table hash is calculated using SHA2-256 over the hash table at 0x3000-0x4000 (in files with storage type 0x41/0x43)
That table is composed of SHA2-256 hashes of the tables at 0x4000, 0x5000, 0x6000, etc.
Those tables are composed of SHA-256 hashes of each data block.
The hashes in these tables (including the top table) are truncated to 0x18 bytes, the hashes in the header are kept at a full 0x20 bytes.

The 0x200 byte signature that comes before the header is a RSA(4096?) signature of the SHA2-256 hash of the header following it (0x200 - 0x1000)

Storage type 0x07 files can be mounted on Windows by using the xsapi.dll file:

typedef int(__cdecl* XvdOpenAdapter)(HANDLE* handle);
typedef int(__cdecl* XvdCloseAdapter)(HANDLE handle);
typedef int(__cdecl* XvdMount)(void* unknownReturnValue1, void* unknownReturnValue2, HANDLE xvdHandle, LPCWSTR filePath, int64_t setToZero, int64_t setToZero2, int32_t setToZero3);
typedef int(__cdecl* XvdUnmountFile)(HANDLE xvdHandle, LPCWSTR filePath);

Type 0x43 files can also be modded into 0x07 files and mounted by removing the hash tables, nulling the signature and changing the storage type to 0x07.

XVC info[edit]

XVC info is stored at block 0, you can find the offset by taking the block start offset from the header, multiply it by 0x400 and add 0x4000. (todo: find the proper way, because this isn't it) However, if the storage type is 0x07 then block 0 will always be at 0x3000.

You can retrieve XVC data by using xsapi.dll, by setting data to NULL you can retrieve the size of it in case it changes:

typedef int(__cdecl* XsReadXvcInfoXVD)(LPCWSTR filename, void* data, int32_t* dataSize);

The size of it is also defined in the XVD header, usually 0x2000. Although true XVD files such as the ones in system updates don't have XVC info and have the XVC data size set to 0.

Offset Length Type Information
0x00 0x10 bytes Content ID
0x10 0x10 bytes Encryption Key GUID
0x20 0x1FE0 bytes Padding, may contain other encryption keys?

Files with encryption key ID 33ec8436-5a0e-4f0d-b1ce-3f29c3955039 are encrypted with the devkit key (aka DevContentKeyEscrow_v1_Public?)
This key can be found inside xvdsign.exe.