Changes

Jump to navigation Jump to search
5,648 bytes added ,  2 June
→‎InitialData: Fix struct being too large caused by having redundant data
Line 3: Line 3:     
== Overview ==
 
== Overview ==
There are two known specialisations of the NCSD container format. The CTR Cart Image (CCI) format and the CTR System Update (CSU). CCI is the format of retail game ROM dumps. CSU is used with developer system updates and tools
+
There are two known specialisations of the NCSD container format. The CTR Cart Image (CCI) format and the 3DS' raw [[Flash Filesystem#NAND structure|NAND format]]. CCI is the format of game ROM images.
 +
 
 +
'''CTR System Update (CSU)''' is a variant of CCI, where the only difference is in the file extension. This is used with developer System Updates and associated [[3DS Development Unit Software|Tools]].
 +
 
    
NCSD images start with a NCSD header, followed by up to a maximum of 8 [[NCCH]] partitions.
 
NCSD images start with a NCSD header, followed by up to a maximum of 8 [[NCCH]] partitions.
   −
For CCI/CSU images, the partitions are reserved as follows:
+
For CCI images, the partitions are reserved as follows:
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 22: Line 25:  
| 2
 
| 2
 
| [[Download Play]] Child container ([[NCCH#CFA|CFA]])
 
| [[Download Play]] Child container ([[NCCH#CFA|CFA]])
 +
|-
 +
| 6
 +
| New3DS [[System_Update_CFA|Update Data]] ([[NCCH#CFA|CFA]])
 
|-
 
|-
 
| 7
 
| 7
Line 54: Line 60:  
|  0x110
 
|  0x110
 
|  8
 
|  8
|  Partitions FS type
+
|  Partitions FS type (0=None, 1=Normal, 3=FIRM, 4=AGB_FIRM save)
 
|-
 
|-
 
|  0x118
 
|  0x118
 
|  8
 
|  8
|  Partitions crypt type  
+
|  Partitions crypt type (each byte corresponds to a partition in the partition table)
 
|-
 
|-
 
|  0x120
 
|  0x120
 
|  0x40=(4+4)*8
 
|  0x40=(4+4)*8
|  Offset & Length partition table
+
|  Offset & Length partition table, in media units
 +
|-
 +
|  0x160
 +
|  0xA0
 +
|  ...
 +
|}
 +
 
 +
For carts,
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Description
 
|-
 
|-
 
|  0x160
 
|  0x160
Line 85: Line 103:  
|-
 
|-
 
|  0x1D0
 
|  0x1D0
0x30
+
0x20
 
|  Reserved
 
|  Reserved
 +
|-
 +
| 0x1F0
 +
| 0xE
 +
| Reserved?
 +
|-
 +
| 0x1FE
 +
| 0x1
 +
| Support for this was implemented with [[9.6.0-24|9.6.0-X]] FIRM. Bit0=1 enables using bits 1-2, it's unknown what these two bits are actually used for(the value of these two bits get compared with some other value during NCSD verification/loading). This appears to enable a new, likely hardware-based, antipiracy check on cartridges.
 +
|-
 +
| 0x1FF
 +
| 0x1
 +
| Support for this was implemented with [[9.6.0-24|9.6.0-X]] FIRM, see below regarding save crypto.
 +
|}
 +
 +
For NAND,
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Description
 +
|-
 +
|  0x160
 +
|  0x5E
 +
|  Unknown
 +
|-
 +
|  0x1BE
 +
|  0x42
 +
|  Encrypted MBR partition-table, for the TWL partitions(key-data used for this keyslot is console-unique).
 
|}
 
|}
 +
 +
=== NCSD Signature ===
 +
The RSA public key used for gamecard NCSD is stored in [[Memory_layout|ITCM]]. The separate public key used for NAND NCSD is stored in Process9 .(ro)data instead of ITCM, and in [[Bootloader|boot ROM]].
 +
 +
For the boot ROM check, sighax may be used to fake-sign NAND headers.  Process9's check will fail, however, unless patched.
    
=== Partition Flags ===
 
=== Partition Flags ===
Line 121: Line 173:  
|-
 
|-
 
| 1
 
| 1
| Starting with [[6.0.0-11]] NATIVE_FIRM will use this flag to determine the gamecard [[Savegames|savegame]] keyY method, when flag[3] is set. 0 = [[2.0.0-2]] hashed keyY, 1 = [[Savegames|new]] keyY method implemented with [[6.0.0-11]].
+
| Starting with [[6.0.0-11]] NATIVE_FIRM will use this flag to determine the gamecard [[Savegames|savegame]] keyY method, when flag[3] is set. 0 = [[2.0.0-2]] hashed keyY, 1 = [[Savegames|new]] keyY method implemented with [[6.0.0-11]]. 0x0A = implemented with [[9.3.0-21|9.3.0-X]]. On Old3DS this is identical to the [[2.2.0-4]] crypto. On New3DS this is identical to the [[2.2.0-4]] crypto, except with New3DS-only gamecard savedata [[AES|keyslots]].
 +
Starting with [[9.6.0-24|9.6.0-X]] FIRM, Process9 now sets <savecrypto_stateval> to partitionflag[1] + <the u8 value from NCSD+0x1FF>, instead of just setting it to partitionflag[1].
 
|-
 
|-
 
| 3
 
| 3
 
| Support for this flag was implemented in NATIVE_FIRM with [[2.0.0-2]]. When this flag is set the hashed gamecard [[Savegames|savegame]] keyY method is used, this likely still uses the repeating-CTR however. With [[6.0.0-11]] the system will determine the gamecard savegame keyY method via flag[1], instead of just using the hashed keyY via this flag.
 
| Support for this flag was implemented in NATIVE_FIRM with [[2.0.0-2]]. When this flag is set the hashed gamecard [[Savegames|savegame]] keyY method is used, this likely still uses the repeating-CTR however. With [[6.0.0-11]] the system will determine the gamecard savegame keyY method via flag[1], instead of just using the hashed keyY via this flag.
|-
+
|-th
 
| 7
 
| 7
 
| This flag enables using the hashed gamecard [[Savegames|savegame]] keyY method, support for this flag was implemented in NATIVE_FIRM with [[2.2.0-4]]. All games with the NCSD image finalized since [[2.2.0-4]](and contains [[2.2.0-4]]+ in the system update partition) have this flag set, this flag also enables using new CTR method as well.
 
| This flag enables using the hashed gamecard [[Savegames|savegame]] keyY method, support for this flag was implemented in NATIVE_FIRM with [[2.2.0-4]]. All games with the NCSD image finalized since [[2.2.0-4]](and contains [[2.2.0-4]]+ in the system update partition) have this flag set, this flag also enables using new CTR method as well.
 
|}
 
|}
 +
 +
Starting with [[9.6.0-24|9.6.0-X]] FIRM, Process9 will just write val0 to a state field then return 0, instead of returning an error when the save crypto type isn't recognized. This was the *only* actual functionality change in the Old3DS Process9 function for gamecard savedata crypto init.
    
== Card Info Header ==
 
== Card Info Header ==
Line 146: Line 201:  
|-
 
|-
 
|  0x208
 
|  0x208
0xDF8
+
0xF8
Reserved1
+
Reserved
 +
|-
 +
|  0x300
 +
|  4
 +
|  Filled size of cartridge
 +
|-
 +
|  0x304
 +
|  0xC
 +
|  Reserved
 +
|-
 +
|  0x310
 +
|  2
 +
|  Title version
 +
|-
 +
|  0x312
 +
|  2
 +
|  Card revision
 +
|-
 +
|  0x314
 +
|  0xC
 +
|  Reserved
 +
|-
 +
|  0x320
 +
|  8
 +
|  Title ID of [[CVer]] in included update partition
 +
|-
 +
|  0x328
 +
|  2
 +
|  Version number of [[CVer]] in included update partition
 +
|-
 +
|  0x32A
 +
|  0xCD6
 +
|  Reserved
 
|-
 
|-
 
|  0x1000
 
|  0x1000
8
+
0x200
Media ID (same as first NCCH partitionId)
+
InitialData
 +
|}
 +
 
 +
=== InitialData ===
 +
 
 +
This data is returned by [[Gamecards|16-byte cartridge command]] 0x82.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
!  OFFSET
 +
!  SIZE
 +
!  DESCRIPTION
 +
|-
 +
|  0x00
 +
|  0x10
 +
|  Seed (keyY used to decrypt the title key - keyX is keyslot 0x3B for production cards, or a key of all zeroes for development cards), consisting of the title ID (little-endian) followed by reserved data (normally all-zero)
 +
|-
 +
|  0x10
 +
|  0x10
 +
|  TitleKey (AES-CCM encrypted)
 
|-
 
|-
0x1008
+
0x20
8
+
0x10
Reserved2
+
AES-CCM MAC
 
|-
 
|-
|  0x1010
   
|  0x30
 
|  0x30
Initial Data
+
0xC
 +
|  AES-CCM nonce
 
|-
 
|-
0x1040
+
0x3C
0xC0
+
0xC4
|  Reserved
+
|  Reserved (normally all-zero)
 
|-
 
|-
|  0x1100
   
|  0x100
 
|  0x100
Copy of first NCCH header (excluding RSA signature)
+
0x100
 +
|  NcchHeader (copy of the first NCCH header, excluding the RSA signature)
 
|}
 
|}
   Line 183: Line 289:  
|  0x1400
 
|  0x1400
 
|  0x10
 
|  0x10
TitleKey
+
TitleKeyData
 
|-
 
|-
 
|  0x1410
 
|  0x1410
0xF0
+
0x1BF0
 
|  CardDeviceReserved2
 
|  CardDeviceReserved2
 +
|-
 +
|  0x3000
 +
|  0x1000
 +
|  TestData
 +
|}
 +
 +
TitleKeyData contains the decrypted version of the title key found in the InitialData. This field appears to be what development--and maybe production?--cards read to know what card encryption seed to use in the CTR protocol.
 +
 +
The CardDeviceReserved areas have random-looking data whose purpose is unknown, other than perhaps to hide the TitleKey.
 +
 +
Note that a particular flashcard vendor, namely Gateway, puts what many refer to as "private headers" at CardDeviceReserved1 in place of actual development card information. This header consists of:
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  OFFSET
 +
!  SIZE
 +
!  DESCRIPTION
 +
|-
 +
|  0x0
 +
|  0x40
 +
|  Unique cartridge ID; only the first 0x10 bytes are meaningful, the rest are 0xff; obtainable using encrypted [[Gamecards|16-byte cartridge command]] 0xc6; the first 0x10 bytes can also be obtained in userland via [[Process_Services_PXI|pxi:ps9::GetRomId]]
 +
|-
 +
|  0x40
 +
|  0x4
 +
|  Cartridge ID1; obtainable using 8-byte cartridge command 0x90 or 16-byte cartridge command 0xa2
 +
|-
 +
|  0x44
 +
|  0x4
 +
|  Cartridge ID2; obtainable using 8-byte cartridge command 0xa0 or 16-byte cartridge command 0xa4
 +
|-
 +
|  0x48
 +
|  0x8
 +
|  Padding (all-0xff)
 +
|}
 +
 +
The legitimacy of the unique cartridge ID can be validated by online services.
 +
 +
Some dumping tools, notably GodMode9 as of 2024-05-26, erroneously always write 0x00000000 into the position of the Cartridge ID2. This is presumably because the cartridge ID2 is always zero for retail carts.
 +
 +
=== TestData ===
 +
The test data is the same one encountered in development DS/DSi cartridges. Its layout is as follows:
 +
{| class="wikitable" border="1"
 +
|-
 +
!  OFFSET
 +
!  SIZE
 +
!  DESCRIPTION
 +
|-
 +
|  0x0
 +
|  0x8
 +
|  The bytes FF 00 FF 00 AA 55 AA 55.
 +
|-
 +
|  0x8
 +
|  0x1F8
 +
|  An ascending byte sequence equal to the offset mod 256 (08 09 0A ... FE FF 00 01 ... FF).
 +
|-
 +
|  0x200
 +
|  0x200
 +
|  A descending byte sequence equal to 255 minus the offset mod 256 (FF FE FD ... 00 FF DE ... 00).
 +
|-
 +
|  0x400
 +
|  0x200
 +
|  Filled with 00 (0b00000000) bytes.
 +
|-
 +
|  0x600
 +
|  0x200
 +
|  Filled with FF (0b11111111) bytes.
 +
|-
 +
|  0x800
 +
|  0x200
 +
|  Filled with 0F (0b00001111) bytes.
 +
|-
 +
|  0xA00
 +
|  0x200
 +
|  Filled with F0 (0b11110000) bytes.
 +
|-
 +
|  0xC00
 +
|  0x200
 +
|  Filled with 55 (0b01010101) bytes.
 +
|-
 +
|  0xE00
 +
|  0x1FF
 +
|  Filled with AA (0b10101010) bytes.
 +
|-
 +
|  0xFFF
 +
|  0x1
 +
|  The final byte is 00 (0b00000000).
 
|}
 
|}
 +
 +
Production cards always return FF when attempting to read 0x1200-0x3FFF. They probably actually have the same data as development cards, but there's no way to read it.
    
== Tools ==
 
== Tools ==

Navigation menu