GameCube DVD Format
Posted: Sat Jun 22, 2024 5:50 pm
You can find my write up here: https://www.gc-forever.com/wiki/index.p ... =DVDFormat
If I'm missing anything or it needs corrections feel free to reply below.
Please Note this reverse engineering the format is WIP.
Decryption seems to be done on the MN103 Microcontroller. keys also exist in there, I believe XADPCM stream decoding is also done on that processor.
MN102 Microcontroller checks for Nintendo Game Disk string in the mediaID and does BCA check, it is the System Manager with a RTOS, ROM is 128KB.
Copy Protection
Physical Format
Disc Image Format
If I'm missing anything or it needs corrections feel free to reply below.

Please Note this reverse engineering the format is WIP.
Decryption seems to be done on the MN103 Microcontroller. keys also exist in there, I believe XADPCM stream decoding is also done on that processor.
MN102 Microcontroller checks for Nintendo Game Disk string in the mediaID and does BCA check, it is the System Manager with a RTOS, ROM is 128KB.
Copy Protection
Code: Select all
Custom Data Sector Format(Data Frames)
Custom Filesystem
Sectors are encrypted by DiskID(Key1) and RandomKey(Key2)
DiskID = GameID + MakerID
RandomKeys:
0: 3
1: 48
2: 32512
3: 28673
4: 6
5: 69
6: 32256
7: 24579
8: 12
9: 192
10: 31744
11: 16391
12: 24
13: 384
14: 30720
15: 15
Check for the Security Code of 6 BCA marks on the disc, from the 6 positions stored on the BCA encrypted area
The 6 BCA mark positions corrupt the sector data stored on the disc, the BCA data tells the locations.
Disc sectors get decrypted with a DiscID and RandomKey from RandomKey list. using the MN102H & MN103S system controller in the DVD drive
Encryption doesn't have a random key for NR disc instead it's a fixed key after the discID, the fixed key value is 9
Encryption with the gamecode and random key xor encryption is similar to the nintendo ds
Encryption(XOR): DiscID(KEY1) -> RandomKey(KEY2)
Security Check: Get DiscID -> Check BCA Marks -> Run Apploader code -> BOOT
Code: Select all
// Burst-Cutting Area(BCA)
struct_DiscBca
{
// UserData(unencrypted), 64B
u8 optInfo[52]; // optional info this can be any data access with the new command on the wii, this is used in NSMB Wii
u8 manufacturer[2];
u8 recorderDevice[2];
u8 APMRecorderDevice;
u8 discDate[2];
u8 discTime[2];
u8 discNumber[3];
// SecureData(unencrypted), 12B
u8 key[8];
u8 id[4];
// AuthenticationData(encrypted with key), 48B
PsnRegion psn[6];
u8 pad[64];
}; // 188B
struct_PsnRegion
{
u32 start;
u32 end;
};
struct_DataFrame
{
u32 id; // PSN(Physical Sector Number)
u16 ied; // ID Error Detection Code, CRC16
u8 userdata[2048]; // Data
u8 cpr_mai[6]; // Copyright Management Information(Unused)
u32 edc; // Error Detection Code, CRC32
}; // 2064B
struct_ControlDataZone
{
DiscManufacturingInfo m_dmi;
PhysicalFormatInfo m_pfi;
};
struct_PhysicalFormatInfo
{
u8 reversed[6];
u8 discMagic; // value is -1.
u8 discSizeMinTransferRate; // The value is fixed on 16.
u8 discStructure; // The value is fixed on 1.
u8 recordedDensity; // The value is fixed on 1.
DataAreaAllocation m_dataAreaAllocation;
u8 reversed2[2000];
u8 reversed3[6];
}; // 2048B
struct_DiscManufacturingInfo
{
u8 reversed[6];
u8 secret1[6];
u8 randomNumber2[6];
u8 secret2[6];
u8 randomNumber3[6];
char mediaId[19]; // "Nintendo Game Disk"
u8 randomNumber4[6];
u8 bookTypePartVersion; // value must be 1.
u8 discSizeMinReadoutRate; // The value is fixed on 16.
u8 discStructure; // The value is fixed on 1.
u8 recordedDensity; // The value is fixed on 0.
DataAreaAllocation m_dataAreaAllocation;
u8 bcaDescriptor; // The value is fixed on 128.
u8 reversed2[1967];
u8 reversed3[6];
}; // 2048B
struct_DataAreaAllocation
{
u8 reversed;
u16 startSector; // 196608
u8 reversed2;
u16 endSector; // 909487
u8 reversed3[3];
}; // 12 Bytes
Code: Select all
struct_root
{
BootHeader m_header; // boot.bin
BootHeaderInfo m_bi; // bi2.bin
AppLoader m_apploader; // appldr.img
FileSystemTable m_fst; // fst.bin
u8* userdata; // application is stored here, including boot file
};
struct_BootHeader
{
u8 ConsoleID; // G = Gamecube, R = Wii.
u8 Gamecode[2];
u8 CountryCode; // J=JAP . P=PAL . E=USA
u8 MakerCode[2];
u8 DiscID;
u8 Version;
u8 AudioStreaming; //01 = Enable it. 00 = Don't
u8 StreamBufSize; // For the AudioEnable.
u8 unused_1[18];
u32 DVDMagicWord; // 3258163005
char GameName[64];
u8 unused_2[416];
u32 NKitMagicWord;
u32 NKitVersion;
u32 ImageCRC;
u32 ForceCRC;
u32 ImageSize;
u32 JunkID;
u8 unused_3[488];
u32 ApploaderSize;
u32 ApploaderFunc1;
u32 ApploaderFunc2;
u32 ApploaderFunc3;
u8 unused_4[16];
u32 DOLOffset;
u32 FSTOffset;
u32 FSTSize;
u32 MaxFSTSize;
u32 FSTAddress;
u32 UserPos;
u32 UserLength;
u32 unused_5;
};
struct_BootHeaderInfo
{
u32 DebugMonSize;
u32 SimMemSize;
u32 ArgOffset;
u32 DebugFlag;
u32 DebugOffset;
u32 DebugSize;
u32 RegionCode;
u32 TotalDisc;
u32 LongFileName;
u32 padSpec;
u32 dolLimit;
u8 pad[8148];
}; // 8192 Bytes
struct_AppLoader
{
char revision[16]; // Revision compile date (example "2001/12/17")
u32 entryPoint; // Apploader's entrypoint
u32 size; // Size of apploader code
u32 rebootSize; // Size of reboot code
u8 pad[4]; // zeroes
u8* code; // PPC code
};
struct_FileSystemTable
{
u32 entityCount;
FileSystemEntity* m_entity;
StringTable* m_string;
};
struct_FileSystemEntity
{
u8 flags;
u16 filenameOffset;
u32 fileOffset;
u32 fileSize;
};
struct_StringTable
{
char* name;
u8 dummy;
};