From xboxdevwiki
Revision as of 15:47, 6 March 2022 by Qubits (talk | contribs) (Volume descriptor)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

XDVDFS (Also known as XISO) is the image format used for Xbox Game Discs. It is stored in the data area.


Each sector is 2048 bytes.



Volume descriptor

The Volume descriptor islocated at Sector #32 and #33 of the game partition.

  • Sector #32:
Offset Type Field Notes
0x14 u32 Root Directory Table Sector Multiply with 0x800 for offset
0x18 u32 Root Directory Table Size Size in bytes. Always multiple of 0x800
0x1C u64 Timestamp (LDAP/Win32 FILETIME)
  • Sector #33: The first 24 Bits is the magic. It is always "XBOX_DVD_LAYOUT_TOOL_SIG". [FIXME]



Wave 1

Developers used xblayout to create DVD layout. Then generated the final image using xbpremaster. The final image was submitted to Microsoft.

  • Azurik: Rise of Perathia (NTSC)
    • xblayout version: 1.0.3926.1
    • xbpremaster version: 1.0.3926.1
  • Genma Onimusha (PAL)
    • xblayout version: 1.0.4039.1
    • xbpremaster version: 1.0.4039.2
  • Max Payne (PAL)
    • xblayout version: 1.0.4134.1
    • xbpremaster version: 1.0.4242.1
  • Petit Copter (Japanese)
    • xblayout version: 1.0.4361.1
    • xbpremaster version: 1.0.4361.2
  • 007 - Agent Under Fire (PAL)
    • xblayout version: 1.0.4432.1
    • xbpremaster version: 1.0.4432.1
Wave 2

[FIXME]. Developers used a new version of xblayout and submitted the layout + content to Microsoft

Microsoft generated the final image.

Sometime during this wave, the new padding algorithm got introduced. Judging from the examples below, the padding algorithm does not seem to be bound to the xblayout version or to a specific date.

Other Examples of games with 1.0.4721.1 version that don't use the old algorithm: Mat Hoffman's Pro BMX 2 (France), MLB SlugFest 2003 (USA), NCAA Football 2003 (USA), Phantom Crash (USA), Syberia (USA, Europe)

Wave 3

[FIXME]. Same as wave 2

Wave 4

[FIXME]. Same as wave 3, but developers now had to use the xbgamedisc tool instead of xblayout. The mastering tool used by microsoft also leaves a version identifier now.

Directory Entry

Version 4361

File entry flags:

  • READONLY = 0x01
  • HIDDEN = 0x02
  • SYSTEM = 0x04
  • DIRECTORY = 0x10
  • ARCHIVE = 0x20
  • NORMAL = 0x80

File data blocks

Version 4361

Incomplete sectors are padded with 0x00 bytes.

Random blocks

Version 3926 - 4808

Seeded and then starting to emit bytes in data area. Filled with the following algorithm:

// State
uint32_t a;
uint32_t b;
uint32_t c;

// Helper
static uint32_t Value(void) {
  uint64_t result;
  result = c;
  result += 1;
  result *= b;
  result %= 0xFFFFFFFB;
  c = result & 0xFFFFFFFF;
  return c ^ a;

// buffer must be at even address, length must be multiple of 2
void Fill(uint16_t* buffer, size_t length) {
  while(length >= 2) {
    *buffer++ = Value() >> 8;
    length -= 2;

void Seed() {
  const uint32_t b_seeds[8] = {

  uint32_t seed = ft.dwLowDateTime ^ ft.dwHighDateTime;
  a = 0;
  b = b_seeds[seed & 7];
  c = seed;
  a = Value();

The RNG is seeded when the mastering tool / wizard is started. The first portion of the code to use this random number generator is the code which generates layer 0 and layer 1.

Version 4831 - 5849

The algorithm was switched to RC4-256-drop-2048.

#include <openssl/rc4.h>

RC4_KEY rc4key;

void Fill(uint8_t* buffer, size_t length) {
  // We need a zero buffer as OpenSSL will want to XOR the keystream with data.
  // The XDVDFS random data is the keystream without changes, so we let XOR OpenSSL XOR with 0x00 bytes.
  uint8_t zero_buffer[length];
  memset(zero_buffer, 0x00, length);
  RC4(&rc4key, length, zero_buffer, buffer);

void Seed() {
  union {
    uint8_t raw[16];
    struct {
      struct _FILETIME SystemTimeAsFileTime; // first 8 bytes, little-endian
      uint64_t tsc; // later 8 bytes, little-endian
  } key;

  // Initialize seed
  key.tsc = rdtsc();
  RC4_set_key(&rc4key, 16, &key);

  // Drop the first 2048 bytes of the RC4 keystream
  uint8_t discard_buffer[2048];
  Fill(discard_buffer, 2048);

The RNG is seeded when the mastering tool / wizard is started. The first portion of the code to use this random number generator is the code which generates layer 0 and layer 1.

Edit: This assumption is not true, at least not for all instances. For example, all region variants of Conker Live & Reloaded share the same padding stream.

Security blocks

Version 4361

Treated like random block.