Changes

317 bytes removed ,  21:26, 4 March 2020
no edit summary
Line 29: Line 29:  
| 0x204
 
| 0x204
 
| 0x1
 
| 0x1
| Distribution Type (0x00 = System NCA, 0x01 = Gamecard NCA)
+
| DistributionType (0x00 = System NCA, 0x01 = Gamecard NCA)
 
|-
 
|-
 
| 0x205
 
| 0x205
 
| 0x1
 
| 0x1
| Content Type (0x00 = Program, 0x01 = Meta, 0x02 = Control, 0x03 = Manual, 0x04 = Data, 0x05 = PublicData)
+
| ContentType (0x00 = Program, 0x01 = Meta, 0x02 = Control, 0x03 = Manual, 0x04 = Data, 0x05 = PublicData)
 
|-
 
|-
 
| 0x206
 
| 0x206
 
| 0x1
 
| 0x1
| Old Key Generation (0x00 = [[1.0.0]], 0x01 = Unused, 0x02 = [[3.0.0]])
+
| KeyGenerationOld (0x00 = [[1.0.0]], 0x01 = Unused, 0x02 = [[3.0.0]])
 
|-
 
|-
 
| 0x207
 
| 0x207
 
| 0x1
 
| 0x1
| Key Area Encryption Key Index (0x00 = Application, 0x01 = Ocean, 0x02 = System)
+
| KeyAreaEncryptionKeyIndex (0x00 = Application, 0x01 = Ocean, 0x02 = System)
 
|-
 
|-
 
| 0x208
 
| 0x208
 
| 0x8
 
| 0x8
| Size of the entire NCA
+
| ContentSize
 
|-
 
|-
 
| 0x210
 
| 0x210
 
| 0x8
 
| 0x8
| Title ID
+
| ProgramId
 
|-
 
|-
 
| 0x218
 
| 0x218
 
| 0x4
 
| 0x4
| Content Index
+
| ContentIndex
 
|-
 
|-
 
| 0x21C
 
| 0x21C
 
| 0x4
 
| 0x4
| SDK AddOn Version (used in "FS_ACCESS: { sdk_version: {byte3}.{byte2}.{byte1}, ..." with byte0 set to 0 and compared with a required minimum value: 0x000B0000)
+
| SdkAddonVersion (used in "FS_ACCESS: { sdk_version: {byte3}.{byte2}.{byte1}, ..." with byte0 set to 0 and compared with a required minimum value: 0x000B0000)
 
|-
 
|-
 
| 0x220
 
| 0x220
 
| 0x1
 
| 0x1
| Key Generation (0x03 = [[3.0.1]], 0x04 = [[4.0.0]], 0x05 = [[5.0.0]], 0x06 = [[6.0.0]], 0x07 = [[6.2.0]], 0x08 = [[7.0.0]], 0x09 = [[8.1.0]], 0x0A = [[9.0.0]], 0x0B = [[9.1.0]], 0xFF = Invalid)
+
| KeyGeneration (0x03 = [[3.0.1]], 0x04 = [[4.0.0]], 0x05 = [[5.0.0]], 0x06 = [[6.0.0]], 0x07 = [[6.2.0]], 0x08 = [[7.0.0]], 0x09 = [[8.1.0]], 0x0A = [[9.0.0]], 0x0B = [[9.1.0]], 0xFF = Invalid)
 
|-
 
|-
 
| 0x221
 
| 0x221
Line 69: Line 69:  
| 0x230
 
| 0x230
 
| 0x10
 
| 0x10
| Rights ID ([[Ticket]])
+
| RightsId
 
|-
 
|-
 
| 0x240
 
| 0x240
| 0x10*0x4(0x40)
+
| 0x10 * 4
| Table for each section (see below)
+
| Array of [[#FsEntry]]
 
|-
 
|-
 
| 0x280
 
| 0x280
| 0x20*0x4(0x80)
+
| 0x20 * 4
| Table of SHA256 hashes (over each 0x200-byte [[#Section Header Block|Section Header Block]])
+
| Array of SHA256 hashes (over each [[#FsHeader|FsHeader]])
 
|-
 
|-
 
| 0x300
 
| 0x300
| 0x10*0x4(0x40)
+
| 0x10 * 4
| Key area
+
| EncryptedKeyArea
 
|}
 
|}
   −
The header is 0x400-bytes, at NCA+0.
+
When the above '''KeyGenerationOld''' field is 0x2 on >= v3.0, different {crypto/keydata} is used for the sections' data. With system content, this is used with every ncatype except ncatype0. The only other exception is {data-content} for the firm titles: this is required in order for older-system-versions to install it.
   −
When the above '''Old Key Generation''' field is 0x2 on >= v3.0, different {crypto/keydata} is used for the sections' data. With system content, this is used with every ncatype except ncatype0. The only other exception is {data-content} for the firm titles: this is required in order for older-system-versions to install it.
+
'''KeyGeneration''' 0x3 (with '''KeyGenerationOld''' set to 0x2) is used for all [[3.0.1]] sysmodules and the [[System_Version_Title]]. With [[3.0.2]], all updated titles use the crypto from [[3.0.1]] for non-ncatype0, except for firm {data-content}. In some cases various game content uses the above newer crypto as well.
   −
'''Key Generation''' 0x3 (with '''Old Key Generation''' set to 0x2) is used for all [[3.0.1]] sysmodules and the [[System_Version_Title]]. With [[3.0.2]], all updated titles use the crypto from [[3.0.1]] for non-ncatype0, except for firm {data-content}. In some cases various game content uses the above newer crypto as well.
+
'''KeyGeneration''' is always '''MasterKeyVersion''' + 1, except for generations 0 and 1 which are both version 0.
 
  −
'''Key Generation''' is always '''Master Key Version''' + 1, except for generations 0 and 1 which are both version 0.
      
The keyindex passed to <key-generation-related code> is determined as follows:
 
The keyindex passed to <key-generation-related code> is determined as follows:
* Pre-[[3.0.0]]: The '''Key Area Encryption Key Index''' field (0x207) is passed directly.
+
* Pre-[[3.0.0]]: The '''KeyAreaEncryptionKeyIndex''' field (0x207) is passed directly.
* [[3.0.0]]+: It's determined using the '''Key Area Encryption Key Index''' field (0x207) and the '''Old Key Generation''' field (0x206). The latter field must be 0, 1 or 2. In each ncahdr_keyindex block, it executes "if(ncahdr_x206>=3)<panic>", but that won't trigger due to the earlier check. The end result is basically the same as pre-[[3.0.0]], except when ncahdr_x206 == 0x2, final_index is new_base_index+ncahdr_keyindex. Actual implementation loads index from u32_array[ncahdr_crypto_type], where the address of u32_array is different for each ncahdr_keyindex.
+
* [[3.0.0]]+: It's determined using the '''KeyAreaEncryptionKeyIndex''' field (0x207) and the '''KeyGenerationOld''' field (0x206). The latter field must be 0, 1 or 2. In each ncahdr_keyindex block, it executes "if(ncahdr_x206>=3)<panic>", but that won't trigger due to the earlier check. The end result is basically the same as pre-[[3.0.0]], except when ncahdr_x206 == 0x2, final_index is new_base_index+ncahdr_keyindex. Actual implementation loads index from u32_array[ncahdr_crypto_type], where the address of u32_array is different for each ncahdr_keyindex.
* [[3.0.1]]+: The dedicated range check for the '''Old Key Generation''' field (0x206) was removed, since the updated code no longer needs it. The output from a function masked with 0xFF is now used instead of ncahdr_x206. The range check for that field was changed from {ncahdr_x206 check with panic described above}, to "if(index>=4)final_index=10;"(skips accessing the array and uses 10 directly). The arrays were updated with an additional entry: final_index=v301_base_index+ncahdr_keyindex.
+
* [[3.0.1]]+: The dedicated range check for the '''KeyGenerationOld''' field (0x206) was removed, since the updated code no longer needs it. The output from a function masked with 0xFF is now used instead of ncahdr_x206. The range check for that field was changed from {ncahdr_x206 check with panic described above}, to "if(index>=4)final_index=10;"(skips accessing the array and uses 10 directly). The arrays were updated with an additional entry: final_index=v301_base_index+ncahdr_keyindex.
 
** The keydata for the above index10 is not(?) known to be initialized.
 
** The keydata for the above index10 is not(?) known to be initialized.
 
** The new function called by the code described above does:
 
** The new function called by the code described above does:
 
** <code>if(ncahdr_x206 < ncahdr_x220){ret = ncahdr_x220; } else { ret = ncahdr_x206; } return ret;</code>
 
** <code>if(ncahdr_x206 < ncahdr_x220){ret = ncahdr_x220; } else { ret = ncahdr_x206; } return ret;</code>
   −
== Section Table Entry ==
+
== FsEntry ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 109: Line 107:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| Media Start Offset
+
| StartOffset (in Media Units which are 0x200 bytes)
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Media End Offset
+
| EndOffset (in Media Units which are 0x200 bytes)
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x4
 
| 0x4
| Unknown
+
| Reserved
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 0x4
 
| 0x4
| Unknown
+
| Reserved
 
|}
 
|}
   −
Entry size is 0x10-bytes.
+
= FsHeader =
 
  −
Media offset is absoluteoffset/{mediasize}, where mediasize is 0x200 bytes.
  −
 
  −
= Section Header Block =
   
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 141: Line 135:  
| 0x2
 
| 0x2
 
| 0x1
 
| 0x1
| Filesystem Type (0 = RomFS, 1 = PFS0)
+
| FsType (0 = RomFs, 1 = PartitionFs)
 
|-
 
|-
 
| 0x3
 
| 0x3
 
| 0x1
 
| 0x1
| Hash Type (2 = PFS0, 3 = RomFS)
+
| HashType (0 = Auto, 2 = HierarchicalSha256, 3 = HierarchicalIntegrity)
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x1
 
| 0x1
| Encryption Type (1 = None, 2 = AesCtrOld, 3 = AesCtr, 4 = AesCtrEx)
+
| EncryptionType (0 = Auto, 1 = None, 2 = AesCtrOld, 3 = AesCtr, 4 = AesCtrEx)
 
|-
 
|-
 
| 0x5
 
| 0x5
Line 157: Line 151:  
| 0x8
 
| 0x8
 
| 0xF8
 
| 0xF8
| FS-specific superblock
+
| [[#HashInfo|HashInfo]]
 
|-
 
|-
 
| 0x100
 
| 0x100
| ?
+
| 0x40
| Optional BKTR header (can be used with any section, but only known to be used with game-updates RomFS)
+
| [[#PatchInfo|PatchInfo]] (only used with game updates RomFs)
 +
|-
 +
| 0x140
 +
| 0x4
 +
| Generation
 +
|-
 +
| 0x144
 +
| 0x4
 +
| SecureValue
 +
|-
 +
| 0x148
 +
| 0xB8
 +
| Reserved
 
|}
 
|}
   −
The Section Header Block for each section is at absoluteoffset+0x400+(sectionid*0x200), where sectionid corresponds to the index used with the entry/hash tables.
+
The FsHeader for each section is at absoluteoffset+0x400+(sectionid*0x200), where sectionid corresponds to the index used with the entry/hash tables.
   −
The total size is 0x200-bytes.
+
== HashInfo ==
 +
This contains information specific to the hash type in use.
   −
== PFS0 superblock ==
+
=== HierarchicalSha256 ===
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 205: Line 212:  
| 0x48
 
| 0x48
 
| 0xB0
 
| 0xB0
| Empty
+
| Reserved
 
|}
 
|}
   −
== RomFS superblock ==
+
=== HierarchicalIntegrity ===
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 215: Line 222:  
! Description
 
! Description
 
|-
 
|-
 +
| 0x0
 
| 0x8
 
| 0x8
| 0xE0
+
| Reserved
| IVFC header (basically the same as [[Savegames]] IVFC except with 2 more levels and +0x0C is non-zero, see below)
  −
|}
  −
 
  −
This documents the structure of Section Header Block +0 for RomFS.
  −
 
  −
=== IVFC ===
  −
{| class="wikitable"
   
|-
 
|-
! Start
+
| 0x8
! Length
+
| 0x4
! Description
  −
|-
  −
| 0x00
  −
| 4
   
| Magicnum "IVFC"
 
| Magicnum "IVFC"
 
|-
 
|-
| 0x04
+
| 0xC
| 4
+
| 0x4
 
| Magic Number (0x20000)
 
| Magic Number (0x20000)
 
|-
 
|-
| 0x08
+
| 0x10
| 4
+
| 0x4
 
| Master hash size?
 
| Master hash size?
 
|-
 
|-
| 0x0C
+
| 0x14
| 4
+
| 0x4
 
| Usually 7? Unknown, could be related to total number of levels maybe?
 
| Usually 7? Unknown, could be related to total number of levels maybe?
 
|-
 
|-
| 0x10
+
| 0x18
| 8
+
| 0x8
 
| Level 1 offset
 
| Level 1 offset
 
|-
 
|-
| 0x18
+
| 0x20
| 8
+
| 0x8
 
| Level 1 size
 
| Level 1 size
 
|-
 
|-
| 0x20
+
| 0x28
| 4
+
| 0x4
 
| Level 1 block size (in log2)
 
| Level 1 block size (in log2)
 
|-
 
|-
| 0x24
+
| 0x2C
| 4
+
| 0x4
 
| Reserved
 
| Reserved
 
|-
 
|-
| 0x28
+
| 0x30
| 8
+
| 0x8
 
| Level 2 offset
 
| Level 2 offset
 
|-
 
|-
| 0x30
+
| 0x38
| 8
+
| 0x8
 
| Level 2 size
 
| Level 2 size
 
|-
 
|-
| 0x38
+
| 0x40
| 4
+
| 0x4
 
| Level 2 block size (in log2)
 
| Level 2 block size (in log2)
 
|-
 
|-
| 0x3C
+
| 0x44
| 4
+
| 0x4
 
| Reserved
 
| Reserved
 
|-
 
|-
| 0x40
+
| 0x48
| 8
+
| 0x8
 
| Level 3 offset
 
| Level 3 offset
 
|-
 
|-
| 0x48
+
| 0x50
| 8
+
| 0x8
 
| Level 3 size
 
| Level 3 size
 
|-
 
|-
| 0x50
+
| 0x58
| 4
+
| 0x4
 
| Level 3 block size (in log2)
 
| Level 3 block size (in log2)
 
|-
 
|-
| 0x54
+
| 0x5C
| 4
+
| 0x4
 
| Reserved
 
| Reserved
 
|-
 
|-
| 0x58
+
| 0x60
| 8
+
| 0x8
 
| Level 4 offset
 
| Level 4 offset
 
|-
 
|-
| 0x60
+
| 0x68
| 8
+
| 0x8
 
| Level 4 size
 
| Level 4 size
 
|-
 
|-
| 0x68
+
| 0x70
| 4
+
| 0x4
 
| Level 4 block size (in log2)
 
| Level 4 block size (in log2)
 
|-
 
|-
| 0x6C
+
| 0x74
| 4
+
| 0x4
 
| Reserved
 
| Reserved
 
|-
 
|-
| 0x70
+
| 0x78
| 8
+
| 0x8
 
| Level 5 offset
 
| Level 5 offset
 
|-
 
|-
| 0x78
+
| 0x80
| 8
+
| 0x8
 
| Level 5 size
 
| Level 5 size
 
|-
 
|-
| 0x80
+
| 0x88
| 4
+
| 0x4
 
| Level 5 block size (in log2)
 
| Level 5 block size (in log2)
 
|-
 
|-
| 0x84
+
| 0x8C
| 4
+
| 0x4
 
| Reserved
 
| Reserved
 
|-
 
|-
| 0x88
+
| 0x90
| 8
+
| 0x8
 
| Level 6 offset
 
| Level 6 offset
 
|-
 
|-
| 0x90
+
| 0x98
| 8
+
| 0x8
 
| Level 6 size
 
| Level 6 size
 
|-
 
|-
| 0x98
+
| 0xA0
| 4
+
| 0x4
 
| Level 6 block size (in log2)
 
| Level 6 block size (in log2)
 
|-
 
|-
| 0x9C
+
| 0xA4
| 4
+
| 0x4
 
| Reserved
 
| Reserved
 
|-
 
|-
| 0xA0
+
| 0xA8
| 32
+
| 0x20
| Unknown, reserved?
+
| Reserved
 
|-
 
|-
| 0xC0
+
| 0xC8
| 32
+
| 0x20
 
| Hash
 
| Hash
 +
|-
 +
| 0xE8
 +
| 0x10
 +
| Reserved
 
|}
 
|}
   −
== BKTR ==
+
== PatchInfo ==
{| class="wikitable"
+
{| class="wikitable" border="1"
 
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
Line 379: Line 380:  
| 0x1C
 
| 0x1C
 
| 0x4
 
| 0x4
| ?
+
|  
 
|-
 
|-
 
| 0x20
 
| 0x20
 
| 0x20
 
| 0x20
 
| Same as the above 0x20-bytes except with different data.
 
| Same as the above 0x20-bytes except with different data.
|-
  −
| 0x40
  −
| 0x4?
  −
| ?
  −
|-
  −
| 0x44
  −
| 0x4?
  −
| ?
   
|}
 
|}
  −
Using this header is enabled when offset 0x8 in this header is non-zero.
      
The above byte-offsets are relative to the start of the section-data.
 
The above byte-offsets are relative to the start of the section-data.
Line 400: Line 391:  
The two sections specified by the two BKTR entries are usually(?) at the very end of the section data(section_endoffset-{size of BKTR sections}).
 
The two sections specified by the two BKTR entries are usually(?) at the very end of the section data(section_endoffset-{size of BKTR sections}).
   −
=== RomFS Patching ===
+
=== RomFs Patching ===
The BKTR section enables combining data from an update NCA with the RomFS from a base NCA to create a single patched RomFS image.  
+
The [[#PatchInfo|PatchInfo]] section enables combining data from an update NCA with the RomFs from a base NCA to create a single patched RomFS image.  
   −
The first BKTR entry describes how to map regions of the two RomFS images to create the patched RomFS. It has the following format:
+
The first BKTR entry describes how to map regions of the two RomFs images to create the patched RomFs. It has the following format:
 
+
{| class="wikitable" border="1"
{| class="wikitable"
   
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x4 || Padding/Unused?
+
| 0x0
 +
| 0x4
 +
| Padding/Unused?
 
|-
 
|-
| 0x4 || 0x4 || Number of Buckets
+
| 0x4
 +
| 0x4
 +
| Number of Buckets
 
|-
 
|-
| 0x8 || 0x8 || Total Size of the Virtual RomFS Image
+
| 0x8
 +
| 0x8
 +
| Total Size of the Virtual RomFS Image
 
|-
 
|-
| 0x10 || 0x3FF0 || Base Virtual Offset for each Bucket (u64s, padded with 0s until end)
+
| 0x10
 +
| 0x3FF0
 +
| Base Virtual Offset for each Bucket (u64s, padded with 0s until end)
 
|-
 
|-
| 0x4000 || 0x4000*X || Relocation Buckets
+
| 0x4000
 +
| 0x4000*X
 +
| Relocation Buckets
 
|}
 
|}
    
Where relocation buckets are as follows:
 
Where relocation buckets are as follows:
 
+
{| class="wikitable" border="1"
{| class="wikitable"
   
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x4 || Padding/Unused?
+
| 0x0
 +
| 0x4
 +
| Padding/Unused?
 
|-
 
|-
| 0x4 || 0x4 || Number of Entries
+
| 0x4
 +
| 0x4
 +
| Number of Entries
 
|-
 
|-
| 0x8 || 0x8 || End offset for this Bucket
+
| 0x8
 +
| 0x8
 +
| End offset for this Bucket
 
|-
 
|-
| 0x10 || 0x3FF0 || Relocation Entries
+
| 0x10
 +
| 0x3FF0
 +
| Relocation Entries
 
|}
 
|}
    
Where relocation entries are as follows:
 
Where relocation entries are as follows:
 
+
{| class="wikitable" border="1"
{| class="wikitable"
   
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x8 || Address in Patched RomFS
+
| 0x0
 +
| 0x8
 +
| Address in Patched RomFs
 
|-
 
|-
| 0x8 || 0x8 || Address in Source RomFS
+
| 0x8
 +
| 0x8
 +
| Address in Source RomFs
 
|-
 
|-
| 0x10 || 0x4 || 1=Is from Patch RomFS, 0=Is from Base RomFS
+
| 0x10
 +
| 0x4
 +
| 1=Is from Patch RomFS, 0=Is from Base RomFS
 
|}
 
|}
   −
The second BKTR entry describes the subsections within the Patch RomFS. It has the following format:
+
The second BKTR entry describes the subsections within the Patch RomFs. It has the following format:
 
+
{| class="wikitable" border="1"
{| class="wikitable"
   
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x4 || Padding/Unused?
+
| 0x0
 +
| 0x4
 +
| Padding/Unused?
 
|-
 
|-
| 0x4 || 0x4 || Number of Buckets
+
| 0x4
 +
| 0x4
 +
| Number of Buckets
 
|-
 
|-
| 0x8 || 0x8 || Total Size of the Physical Patch Image
+
| 0x8
 +
| 0x8
 +
| Total Size of the Physical Patch Image
 
|-
 
|-
| 0x10 || 0x3FF0 || Base Physical Offset for each Bucket (u64s, padded with 0s until end)
+
| 0x10
 +
| 0x3FF0
 +
| Base Physical Offset for each Bucket (u64s, padded with 0s until end)
 
|-
 
|-
| 0x4000 || 0x4000*X || Subsection Buckets
+
| 0x4000
 +
| 0x4000*X
 +
| Subsection Buckets
 
|}
 
|}
    
Where subsection buckets are as follows:
 
Where subsection buckets are as follows:
 
+
{| class="wikitable" border="1"
{| class="wikitable"
   
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x4 || Padding/Unused?
+
| 0x0
 +
| 0x4
 +
| Padding/Unused?
 
|-
 
|-
| 0x4 || 0x4 || Number of Entries
+
| 0x4
 +
| 0x4
 +
| Number of Entries
 
|-
 
|-
| 0x8 || 0x8 || End offset for this Bucket
+
| 0x8
 +
| 0x8
 +
| End offset for this Bucket
 
|-
 
|-
| 0x10 || 0x3FF0 || Subsection Entries
+
| 0x10
 +
| 0x3FF0
 +
| Subsection Entries
 
|}
 
|}
    
Where subsection entries are as follows:
 
Where subsection entries are as follows:
 
+
{| class="wikitable" border="1"
{| class="wikitable"
   
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x8 || Address in Patch RomFS
+
| 0x0
 +
| 0x8
 +
| Address in Patch RomFs
 
|-
 
|-
| 0x8 || 0x4 || Padding/Unused?
+
| 0x8
 +
| 0x4
 +
| Padding/Unused?
 
|-
 
|-
| 0xC || 0x4 || Value for subsection AES-CTR
+
| 0xC
 +
| 0x4
 +
| Value for subsection AES-CTR
 
|}
 
|}
   −
Official code assumes the relocation entries are sorted, and performs a binary search when determining where to read from. Each subsection in the Patch RomFS has its CTR calculated separately from the others based on the value in its entry (the BKTR entries use normal crypto). Thus decrypting a Patch RomFS requires decrypting and parsing the BKTR entries before anything else.
+
Official code assumes the relocation entries are sorted, and performs a binary search when determining where to read from. Each subsection in the Patch RomFs has its CTR calculated separately from the others based on the value in its entry (the BKTR entries use normal crypto). Thus decrypting a Patch RomFS requires decrypting and parsing the BKTR entries before anything else.
   −
= Logo section =
+
= Logo Section =
 
This is a PFS0.
 
This is a PFS0.
    
See [[NCA_Content_FS|here]] for the mounted-FS logo contents.
 
See [[NCA_Content_FS|here]] for the mounted-FS logo contents.
   −
= ExeFS section =
+
= ExeFS Section =
 
This is a PFS0.
 
This is a PFS0.
    
See [[ExeFS|here]] for mounted-FS ExeFS contents.
 
See [[ExeFS|here]] for mounted-FS ExeFS contents.
   −
= Game-updates =
+
= Game Updates =
 
The section-data for ncatype1 RomFS section(section1) uses section-crypto-type 0x4.
 
The section-data for ncatype1 RomFS section(section1) uses section-crypto-type 0x4.
   −
Game-updates also contain multiple ncatype6 content, which contain "section0_pfs0/fragment". Some of these are just NCAs, unknown for the rest(presumably NCAs with additional crypto?). The first ncatype6 content fragment file has a NDV0 header, with the NCA starting at offset 0x44.
+
Game updates also contain multiple ncatype6 content, which contain "section0_pfs0/fragment". Some of these are just NCAs, unknown for the rest(presumably NCAs with additional crypto?). The first ncatype6 content fragment file has a NDV0 header, with the NCA starting at offset 0x44.
    
= PFS0 =
 
= PFS0 =
Line 584: Line 617:     
Where File Entry Table consists of Number of Files FileEntries:
 
Where File Entry Table consists of Number of Files FileEntries:
   
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-