DSi cartridge header

The following tries to document the structure of the NDS ROM format and its DSi extended version.

OFFSET SIZE DESCRIPTION - ORIGINAL NDS ENTRIES
0x000 12 Game Title
0x00C 4 Gamecode
0x010 2 Makercode
0x012 1 Unitcode (00h=NDS, 02h=NDS+DSi, 03h=DSi) (bit1=DSi)
0x013 1 Encryption seed select
0x014 1 Devicecapacity
0x015 7 Reserved
0x01C 2 Game Revision (used by DSi titles)
0x01E 1 ROM Version
0x01F 1 Internal flags, (Bit2: Autostart)
0x020 4 ARM9 rom offset
0x024 4 ARM9 entry address
0x028 4 ARM9 load address
0x02C 4 ARM9 size
0x030 4 ARM7 rom offset
0x034 4 ARM7 entry address
0x038 4 ARM7 load address
0x03C 4 ARM7 size
0x040 4 File Name Table (FNT) offset
0x044 4 File Name Table (FNT) length
0x048 4 File Allocation Table (FAT) offset
0x04C 4 File Allocation Table (FAT) length
0x050 4 ARM9 overlay offset
0x054 4 ARM9 overlay length
0x058 4 ARM7 overlay offset
0x05C 4 ARM7 overlay length
0x060 4 Normal card control register settings
0x064 4 Secure card control register settings
0x068 4 Icon Banner offset (same as NDS, but with new extra entries)
0x06C 2 Secure area (2K) CRC
0x06E 2 Secure transfer timeout
0x070 4 ARM9 autoload
0x074 4 ARM7 autoload
0x078 8 Secure disable
0x080 4 NTR region ROM size (excluding DSi area)
0x084 4 Header size
0x088 56 Reserved (0x88, 0x8C, 0x90 = Unknown, used by DSi)
0x0C0 156 Nintendo Logo
0x15C 2 Nintendo Logo CRC
0x15E 2 Header CRC
0x160 32 Debugger reserved
OFFSET SIZE DESCRIPTION - EXTENDED DSi ENTRIES
0x180 20 Global MBK1..MBK5 Settings
0x194 12 Local MBK6..MBK8 Settings for ARM9
0x1A0 12 Local MBK6..MBK8 Settings for ARM7
0x1AC 4 Global MBK9 Setting
0x1B0 4 Region Flags
0x1B4 4 Access control
0x1B8 4 ARM7 SCFG EXT mask (controls which devices to enable)
0x1BC 4 Reserved/flags? When bit2 of byte 0x1bf is set, usage of banner.sav from the title data dir is enabled.(additional banner data)
0x1C0 4 ARM9i rom offset
0x1C4 4 Reserved
0x1C8 4 ARM9i load address
0x1CC 4 ARM9i size
0x1D0 4 ARM7i rom offset
0x1D4 4 Pointer to base address where various structures and parameters are passed to the title - what is that???
0x1D8 4 ARM7i load address
0x1DC 4 ARM7i size
0x1E0 4 Digest NTR region offset
0x1E4 4 Digest NTR region length
0x1E8 4 Digest TWL region offset
0x1EC 4 Digest TWL region length
0x1F0 4 Digest Sector Hashtable offset
0x1F4 4 Digest Sector Hashtable length
0x1F8 4 Digest Block Hashtable offset
0x1FC 4 Digest Block Hashtable length
0x200 4 Digest Sector size
0x204 4 Digest Block sectorcount
0x208 4 Icon Banner Size (usually 0x23C0)
0x20C 4 Unknown (used by DSi)
0x210 4 NTR+TWL region ROM size (total size including DSi area)
0x214 12 Unknown (used by DSi)
0x220 4 Modcrypt area 1 offset
0x224 4 Modcrypt area 1 size
0x228 4 Modcrypt area 2 offset
0x22C 4 Modcrypt area 2 size
0x230 8 Title ID
0x238 4 DSiWare: "public.sav" size
0x23C 4 DSiWare: "private.sav" size
0x240 176 Reserved (zero)
0x2F0 16 Unknown (used by DSi)
0x300 20 ARM9 (with encrypted secure area) SHA1 HMAC hash
0x314 20 ARM7 SHA1 HMAC hash
0x328 20 Digest master SHA1 HMAC hash
0x33C 20 Banner SHA1 HMAC hash
0x350 20 ARM9i (decrypted) SHA1 HMAC hash
0x364 20 ARM7i (decrypted) SHA1 HMAC hash
0x378 40 Reserved
0x3A0 20 ARM9 (without secure area) SHA1 HMAC hash
0x3B4 2636 Reserved
0xE00 0x180 Reserved and unchecked region, always zero. Used for passing arguments in debug environment.
0xF80 0x80 RSA signature (the first 0xE00 bytes of the header are signed with an 1024-bit RSA signature).

Modcrypt

Modcrypt is a new additional way of encrypting parts of the NDS ROM executable binary modules using AES CTR. It is mostly being used to encrypt the ARM9i and ARM7i binaries. For example, DSi hybrid card based games have only the ARM9i binary encrypted, while NAND based applications have both the ARM9i and ARM7i binaries encrypted. The modcrypt areas can span over any of the ARM9/ARM7/ARM9i/ARM7i areas.

The AES counter used for modcrypt area 1 is the first 16 bytes of the ARM9 SHA1 HMAC hash (0x300), and for area 2 the first 16 bytes of the ARM7 SHA1 HMAC hash (0x314). The AES key used is a little more complicated. The header can specify to use a secure or insecure key:

if ( (header[0x1C] & 4) || (header[0x1BF] & 0x80) )
  keytype = INSECURE;
else
  keytype = SECURE;

The insecure key is simply the first 16 bytes of the header. The secure key is constructed from a scrambled key pair, where one part is based on an 8-byte shared secret between all DSi's and an 8-byte expanded gamecode, and the other part is based on the first 16 bytes of the ARM9i SHA1 HMAC hash (0x350). The key pair is scrambled in an unknown way to form the final secure key.

It is likely that the insecure key is only used for a debug version of an application, since most card based and NAND based applications are using the secure key.


Digests

The NDS format has been extended with a hash tree to verify the entire contents of an NDS ROM. The NDS ROM is divided into sectors, and each sector will be hashed and have its hash stored in the digest sector hashtable. The size of a sector is defined in the header aswell. Furthermore, the sector hashtable is partitioned and hashed again to form block hashes. This block hashtable is hashed again into a single hash called the digest master hash. These hashtables can be used to verify that the sectors of a NDS ROM have not been tampered with, since the integrity of a sector hash can be verified by a block hash, which in turn can be verified by the master hash. And this hash is part of the header, which is signed with RSA.

The sector hashtable reaches over the NTR and TWL regions, respectively.

See Also