Changes

1,076 bytes added ,  18:23, 30 March 2021
no edit summary
Line 1: Line 1: −
Known internally as "XCI" (NX Card Image), this is the format used for storing the contents of a Nintendo Switch Gamecard.  
+
This is the format used for storing the contents of a Nintendo Switch Gamecard.
   −
= Gamecard Header =
+
= Structure =
This header is 0x200 bytes and is located at offset 0 in the Gamecard.
+
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1000
 +
| [[#CardKeyArea]]
 +
|-
 +
| 0x1000
 +
| 0x200
 +
| [[#CardHeader]]
 +
|-
 +
| 0x1200
 +
| 0x6E00
 +
| ReservedArea
 +
|-
 +
| 0x8000
 +
| 0x8000
 +
| [[#CertArea]]
 +
|-
 +
| 0x10000
 +
| Variable
 +
| [[#NormalArea]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#RomArea]]
 +
|-
 +
| Invalid
 +
| Invalid
 +
| BackupArea
 +
|}
 +
 
 +
== CardKeyArea ==
 +
This region cannot be read directly once written to the Gamecard. Therefore, it is hidden away during read/write operations on the raw Gamecard data.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x200
 +
| [[#InitialData]]
 +
|-
 +
| 0x200
 +
| 0xD00
 +
| [[#TitleKeyArea]]
 +
|-
 +
| 0xF00
 +
| 0x100
 +
| Reserved
 +
|}
 +
 
 +
=== InitialData ===
 +
This region is used for challenge–response authentication when changing to the Gamecard's secure mode.
 +
 
 +
[[Filesystem_services|FS]] calculates a SHA-256 hash over the whole 0x200 bytes and compares it with the hash stored at offset 0x160 in the [[#CardHeader]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| Package ID from [[#CardHeader]] at offset 0x110
 +
|-
 +
| 0x8
 +
| 0x8
 +
| Empty
 +
|-
 +
| 0x10
 +
| 0x10
 +
| Challenge–response authentication data
 +
|-
 +
| 0x20
 +
| 0x10
 +
| Challenge–response authentication MAC
 +
|-
 +
| 0x30
 +
| 0xC
 +
| Challenge–response authentication Nonce
 +
|-
 +
| 0x3C
 +
| 0x1C4
 +
| Reserved (must be empty)
 +
|}
 +
 
 +
=== TitleKeyArea ===
 +
This region is stored encrypted and contains the title keys used by the [[#InitialData]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| TitleKey1
 +
|-
 +
| 0x8
 +
| 0x8
 +
| TitleKey2
 +
|-
 +
| 0x10
 +
| 0xCF0
 +
| Reserved
 +
|}
    +
== CardHeader ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 16: Line 130:  
| 0x100
 
| 0x100
 
| 0x4
 
| 0x4
| Magicnum "HEAD"
+
| MagicCode ("HEAD")
 
|-
 
|-
 
| 0x104
 
| 0x104
 
| 0x4
 
| 0x4
| Secure Area Start Address (in Media Units which are 0x200 bytes)
+
| RomAreaStartPageAddress (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x108
 
| 0x108
 
| 0x4
 
| 0x4
| Backup Area Start Address (always 0xFFFFFFFF)
+
| BackupAreaStartPageAddress (always 0xFFFFFFFF)
 
|-
 
|-
 
| 0x10C
 
| 0x10C
 
| 0x1
 
| 0x1
| TitleKeyDec Index (high nibble) and KEK Index (low nibble)
+
| TitleKeyDecIndex (high nibble) and KekIndex (low nibble)
 
|-
 
|-
 
| 0x10D
 
| 0x10D
 
| 0x1
 
| 0x1
| [[#Gamecard Size|Gamecard Size]]
+
| [[#RomSize]]
 
|-
 
|-
 
| 0x10E
 
| 0x10E
 
| 0x1
 
| 0x1
| Gamecard Header Version
+
| CardHeaderVersion
 
|-
 
|-
 
| 0x10F
 
| 0x10F
 
| 0x1
 
| 0x1
| [[#Gamecard Flags|Gamecard Flags]]
+
| [[#Flags]]
 
|-
 
|-
 
| 0x110
 
| 0x110
 
| 0x8
 
| 0x8
| Package ID (used for challenge–response authentication)
+
| PackageId (used for challenge–response authentication)
 
|-
 
|-
 
| 0x118
 
| 0x118
 
| 0x8
 
| 0x8
| Valid Data End Address (in Media Units which are 0x200 bytes)
+
| ValidDataEndAddress (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x120
 
| 0x120
 
| 0x10
 
| 0x10
| Gamecard Info IV (reversed)
+
| Iv (reversed)
 
|-
 
|-
 
| 0x130
 
| 0x130
 
| 0x8
 
| 0x8
| HFS0 partition offset
+
| PartitionFsHeaderAddress
 
|-
 
|-
 
| 0x138
 
| 0x138
 
| 0x8
 
| 0x8
| HFS0 header size
+
| PartitionFsHeaderSize
 
|-
 
|-
 
| 0x140
 
| 0x140
 
| 0x20
 
| 0x20
| SHA-256 hash of the [[#HFS0 Header|HFS0 Header]]
+
| PartitionFsHeaderHash (SHA-256 hash of the [[#PartitionFsHeader]])
 
|-
 
|-
 
| 0x160
 
| 0x160
 
| 0x20
 
| 0x20
| SHA-256 hash of the [[#Initial Data|Initial Data]]
+
| InitialDataHash (SHA-256 hash of the [[#InitialData]])
 
|-
 
|-
 
| 0x180
 
| 0x180
 
| 0x4
 
| 0x4
| Security Mode (0x01 = T1, 0x02 = T2)
+
| SelSec (0x01 = T1, 0x02 = T2)
 
|-
 
|-
 
| 0x184
 
| 0x184
 
| 0x4
 
| 0x4
| T1 Key Index (always 2)
+
| SelT1Key (always 2)
 
|-
 
|-
 
| 0x188
 
| 0x188
 
| 0x4
 
| 0x4
| Key Index (always 0)
+
| SelKey (always 0)
 
|-
 
|-
 
| 0x18C
 
| 0x18C
 
| 0x4
 
| 0x4
| Normal Area End Address (in Media Units which are 0x200 bytes)
+
| LimArea (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x190
 
| 0x190
 
| 0x70
 
| 0x70
| [[#Gamecard Info|Gamecard Info]] (AES-128-CBC encrypted)
+
| [[#CardInfo]] ( encrypted)
 +
|}
 +
 
 +
=== CardInfo ===
 +
This region is stored encrypted (AES-128-CBC).
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| FwVersion (0x00 = Development, 0x01 = Retail, [4.0.0+] 0x02 = Retail, [11.0.0+] 0x04 = Retail)
 +
|-
 +
| 0x8
 +
| 0x4
 +
| AccCtrl1 (0x00A10011 = 25MHz access, 0x00A10010 = 50MHz access)
 +
|-
 +
| 0xC
 +
| 0x4
 +
| Wait1TimeRead (always 0x1388)
 +
|-
 +
| 0x10
 +
| 0x4
 +
| Wait2TimeRead (always 0)
 +
|-
 +
| 0x14
 +
| 0x4
 +
| Wait1TimeWrite (always 0)
 +
|-
 +
| 0x18
 +
| 0x4
 +
| Wait2TimeWrite (always 0)
 +
|-
 +
| 0x1C
 +
| 0x4
 +
| FwMode (the current SdkAddonVersion)
 +
|-
 +
| 0x20
 +
| 0x4
 +
| UppVersion
 +
|-
 +
| 0x24
 +
| 0x1
 +
| [9.0.0+] CompatibilityType (0x00 = Normal, 0x01 = Terra)
 +
|-
 +
| 0x25
 +
| 0x3
 +
| Empty
 +
|-
 +
| 0x28
 +
| 0x8
 +
| UppHash (SHA-256 hash of the [[#UpdatePartition]])
 +
|-
 +
| 0x30
 +
| 0x8
 +
| UppId (always 0x0100000000000816)
 +
|-
 +
| 0x38
 +
| 0x38
 +
| Empty
 
|}
 
|}
   −
== Gamecard Size ==
+
=== RomSize ===
 
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardSize|GameCardSize]].
 
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardSize|GameCardSize]].
   Line 118: Line 294:  
|}
 
|}
   −
== Gamecard Flags ==
+
=== Flags ===
 
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardAttribute|GameCardAttribute]].
 
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardAttribute|GameCardAttribute]].
   Line 142: Line 318:  
|}
 
|}
   −
== Gamecard Info ==
+
== CertArea ==
When decrypted, this 0x70 byte region is as follows:
+
This is the Gamecard's unique certificate.
 
  −
{| class="wikitable" border="1"
  −
|-
  −
! Offset
  −
! Size
  −
! Description
  −
|-
  −
| 0x0
  −
| 0x8
  −
| Firmware Version (0x00 = Development, 0x01 = Retail, [4.0.0+] 0x02 = Retail, [11.0.0+] 0x04 = Retail)
  −
|-
  −
| 0x8
  −
| 0x4
  −
| Access Control (0x00A10011 = 25MHz access, 0x00A10010 = 50MHz access)
  −
|-
  −
| 0xC
  −
| 0x4
  −
| Read Time Wait1 (always 0x1388)
  −
|-
  −
| 0x10
  −
| 0x4
  −
| Read Time Wait2 (always 0)
  −
|-
  −
| 0x14
  −
| 0x4
  −
| Write Time Wait1 (always 0)
  −
|-
  −
| 0x18
  −
| 0x4
  −
| Write Time Wait2 (always 0)
  −
|-
  −
| 0x1C
  −
| 0x4
  −
| Firmware Mode
  −
|-
  −
| 0x20
  −
| 0x4
  −
| CUP Version
  −
|-
  −
| 0x24
  −
| 0x1
  −
| [9.0.0+] Compatibility Type (0x00 = Normal, 0x01 = Terra)
  −
|-
  −
| 0x25
  −
| 0x3
  −
| Empty
  −
|-
  −
| 0x28
  −
| 0x8
  −
| Update Partition Hash
  −
|-
  −
| 0x30
  −
| 0x8
  −
| CUP ID (always 0x0100000000000816, which is the title-listing data archive's title ID)
  −
|-
  −
| 0x38
  −
| 0x38
  −
| Empty
  −
|}
  −
 
  −
= Gamecard Certificate =
  −
This is the Gamecard's unique certificate and is located at offset 0x7000.
      
[[Filesystem_services|FS]] retrieves this data with [[Filesystem_services#GetGameCardDeviceCertificate|GetGameCardDeviceCertificate]].
 
[[Filesystem_services|FS]] retrieves this data with [[Filesystem_services#GetGameCardDeviceCertificate|GetGameCardDeviceCertificate]].
Line 221: Line 335:  
| 0x100
 
| 0x100
 
| 0x4
 
| 0x4
| Magicnum "CERT"
+
| MagicCode ("CERT")
 
|-
 
|-
 
| 0x104
 
| 0x104
 
| 0x4
 
| 0x4
| Empty
+
| Version
 
|-
 
|-
 
| 0x108
 
| 0x108
 
| 0x1
 
| 0x1
| KEK Index
+
| KekIndex
 
|-
 
|-
 
| 0x109
 
| 0x109
 
| 0x7
 
| 0x7
| Empty
+
| Reserved
 
|-
 
|-
 
| 0x110
 
| 0x110
 
| 0x10
 
| 0x10
| Device ID
+
| DeviceId
 
|-
 
|-
 
| 0x120
 
| 0x120
 
| 0x10
 
| 0x10
| Unknown
+
| Iv
 
|-
 
|-
 
| 0x130
 
| 0x130
 
| 0xD0
 
| 0xD0
| Encrypted data
+
| Data (encrypted)
 +
|-
 +
| 0x200
 +
| 0x7E00
 +
| Reserved
 
|}
 
|}
   −
The data between the Gamecard Certificate and the start of the HFS0 region is all 0xFF, except for a few carts that have been found, inwhich it is 0x00.
+
== NormalArea ==
 
+
This region contains all non-secure partitions of the Gamecard file system.
= Initial Data =
  −
This data is used for challenge–response authentication when changing to the Gamecard's secure mode.
  −
 
  −
[[Filesystem_services|FS]] calculates a SHA-256 hash over the whole 0x200 bytes and compares it with the hash stored at offset 0x160 in the [[#Gamecard Header|Gamecard Header]].
      
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 261: Line 375:  
! Description
 
! Description
 
|-
 
|-
| 0x0
+
| Variable
| 0x8
+
| Variable
| Package ID from [[#Gamecard Header|Gamecard Header]] at offset 0x110
+
| [[#PartitionFsHeader|RootPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#PartitionFsHeader|UpdatePartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#UpdatePartition]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [4.0.0+] [[#PartitionFsHeader|LogoPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [4.0.0+] [[#LogoPartition]]
 
|-
 
|-
| 0x8
+
| Variable
| 0x8
+
| Variable
| Empty
+
| [[#PartitionFsHeader|NormalPartitionHeader]]
 
|-
 
|-
| 0x10
+
| Variable
| 0x10
+
| Variable
| Challenge–response authentication data
+
| [[#NormalPartition]]
 +
|}
 +
 
 +
=== UpdatePartition ===
 +
This partition contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.
 +
 
 +
=== NormalPartition ===
 +
This partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition. Game icon data can still be shown in the home menu on old firmwares.
 +
 
 +
[4.0.0+] This partition is now empty.
 +
 
 +
=== LogoPartition ===
 +
[4.0.0+] This partition now contains the contents of the [[#NormalPartition]].
 +
 
 +
== RomArea ==
 +
This region contains all secure partitions of the Gamecard file system.
 +
 
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x20
+
! Offset
| 0x10
+
! Size
| Challenge–response authentication MAC
+
! Description
 
|-
 
|-
| 0x30
+
| Variable
| 0xC
+
| Variable
| Challenge–response authentication Nonce
+
| [[#PartitionFsHeader|SecurePartitionHeader]]
 
|-
 
|-
| 0x3C
+
| Variable
| 0x1C4
+
| Variable
| Reserved (must be empty)
+
| [[#SecurePartition]]
 
|}
 
|}
   −
= HFS0 =
+
=== SecurePartition ===
 +
This partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.
 +
 
 +
== PartitionFs ==
 
This is the Gamecard file system which starts with magicnum "HFS0".
 
This is the Gamecard file system which starts with magicnum "HFS0".
   −
== Header ==
+
=== PartitionFsHeader ===
The "SHA-256 File System" or "HFS0" starts at offset 0xF000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure).
+
The "SHA-256 File System" or "HFS0" starts at offset 0x10000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure).
   −
A hash for this header is stored at offset 0x140 in the [[#Gamecard Header|Gamecard Header]].
+
A hash for this header is stored at offset 0x140 in the [[#CardHeader]].
 
  −
== File System ==
  −
The actual file system is as follows (also valid for the root partition):
      
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 305: Line 452:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| Magicnum "HFS0"
+
| MagicCode ("HFS0")
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Number of files
+
| FileCount
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x4
 
| 0x4
| Size of the string table
+
| StringTableSize
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 0x4
 
| 0x4
| Zero/Reserved
+
| Reserved
 
|-
 
|-
 
| 0x10
 
| 0x10
 
| X
 
| X
| File Entry Table
+
| [[#FileEntryTable]]
 
|-
 
|-
 
| 0x10 + X
 
| 0x10 + X
 
| Y
 
| Y
| String Table
+
| StringTable
 
|-
 
|-
 
| 0x10 + X + Y
 
| 0x10 + X + Y
 
| Z
 
| Z
| Raw File Data
+
| RawFileData
 
|}
 
|}
   −
Where File Entry Table consists of Number of Files FileEntries:
+
==== FileEntryTable ====
 
   
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 366: Line 512:     
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).
 
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).
  −
= Cartridge Layout =
  −
Observed gamecards contain three partitions: "update", "normal", and "secure".
  −
  −
The update partition (Gamecard partition 0 for fsp-srv cmd 31) contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.
  −
  −
The normal partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition, Game icon data can still be shown in the home menu on old firmwares.
  −
  −
The secure partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.
  −
  −
The entire rest of the Gamecard after the secure partition ends is all FF padding.
  −
  −
[4.0.0+] The "normal" partition is now empty and a new partition "logo" was added.
  −
A partition "boot" got added with exact same content than "logo".