mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
More NCA parsing changes.
This commit is contained in:
parent
b8992d1fdc
commit
37b63aee60
8 changed files with 92 additions and 41 deletions
|
@ -260,7 +260,7 @@ typedef enum {
|
|||
} NacpRuntimeUpgrade;
|
||||
|
||||
typedef enum {
|
||||
NacpSupportingLimitedLicenses_Demo = BIT(1),
|
||||
NacpSupportingLimitedLicenses_Demo = BIT(0),
|
||||
NacpSupportingLimitedLicenses_Count = 1 ///< Total values supported by this enum.
|
||||
} NacpSupportingLimitedLicenses;
|
||||
|
||||
|
@ -368,7 +368,7 @@ typedef struct {
|
|||
s64 device_save_data_journal_size;
|
||||
s64 bcat_delivery_cache_storage_size;
|
||||
char application_error_code_category[0x8];
|
||||
u64 local_communication_id[8];
|
||||
u64 local_communication_id[0x8];
|
||||
u8 logo_type; ///< NacpLogoType.
|
||||
u8 logo_handling; ///< NacpLogoHandling.
|
||||
u8 runtime_add_on_content_install; ///< NacpRuntimeAddOnContentInstall.
|
||||
|
@ -390,7 +390,7 @@ typedef struct {
|
|||
s64 cache_storage_journal_size;
|
||||
s64 cache_storage_data_and_journal_size_max;
|
||||
u16 cache_storage_index_max;
|
||||
u8 reserved_1[0x1];
|
||||
u8 reserved_1;
|
||||
u8 runtime_upgrade; ///< NacpRuntimeUpgrade.
|
||||
u32 supporting_limited_licenses; ///< NacpSupportingLimitedLicenses.
|
||||
u64 play_log_queryable_application_id[0x10];
|
||||
|
|
|
@ -85,7 +85,7 @@ typedef enum {
|
|||
NcaKeyGeneration_Since910NUP = 11, ///< 9.1.0 - 12.0.3.
|
||||
NcaKeyGeneration_Since1210NUP = 12, ///< 12.1.0.
|
||||
NcaKeyGeneration_Since1300NUP = 13, ///< 13.0.0 - 13.2.1.
|
||||
NcaKeyGeneration_Since1400NUP = 14, ///< 14.0.0 - 14.1.0.
|
||||
NcaKeyGeneration_Since1400NUP = 14, ///< 14.0.0 - 14.1.2.
|
||||
NcaKeyGeneration_Current = NcaKeyGeneration_Since1400NUP,
|
||||
NcaKeyGeneration_Max = 32
|
||||
} NcaKeyGeneration;
|
||||
|
@ -100,7 +100,7 @@ typedef enum {
|
|||
/// 'NcaSignatureKeyGeneration_Current' will always point to the last known key generation value.
|
||||
typedef enum {
|
||||
NcaSignatureKeyGeneration_Since100NUP = 0, ///< 1.0.0 - 8.1.1.
|
||||
NcaSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.0.
|
||||
NcaSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.2.
|
||||
NcaSignatureKeyGeneration_Current = NcaSignatureKeyGeneration_Since900NUP,
|
||||
NcaSignatureKeyGeneration_Max = (NcaSignatureKeyGeneration_Current + 1)
|
||||
} NcaSignatureKeyGeneration;
|
||||
|
@ -167,7 +167,10 @@ typedef enum {
|
|||
NcaHashType_Auto = 0,
|
||||
NcaHashType_None = 1,
|
||||
NcaHashType_HierarchicalSha256 = 2, ///< Used by NcaFsType_PartitionFs.
|
||||
NcaHashType_HierarchicalIntegrity = 3 ///< Used by NcaFsType_RomFs.
|
||||
NcaHashType_HierarchicalIntegrity = 3, ///< Used by NcaFsType_RomFs.
|
||||
NcaHashType_AutoSha3 = 4,
|
||||
NcaHashType_HierarchicalSha3256 = 5,
|
||||
NcaHashType_HierarchicalIntegritySha3 = 6
|
||||
} NcaHashType;
|
||||
|
||||
typedef enum {
|
||||
|
@ -175,7 +178,9 @@ typedef enum {
|
|||
NcaEncryptionType_None = 1,
|
||||
NcaEncryptionType_AesXts = 2,
|
||||
NcaEncryptionType_AesCtr = 3,
|
||||
NcaEncryptionType_AesCtrEx = 4
|
||||
NcaEncryptionType_AesCtrEx = 4,
|
||||
NcaEncryptionType_AesCtrSkipLayerHash = 5,
|
||||
NcaEncryptionType_AesCtrExSkipLayerHash = 6
|
||||
} NcaEncryptionType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -298,9 +303,18 @@ NXDT_ASSERT(NcaSparseInfo, 0x30);
|
|||
/// Used in NCAs with LZ4-compressed sections.
|
||||
typedef struct {
|
||||
NcaBucketInfo bucket;
|
||||
u8 reserved[0x8];
|
||||
} NcaCompressionInfo;
|
||||
|
||||
NXDT_ASSERT(NcaCompressionInfo, 0x20);
|
||||
NXDT_ASSERT(NcaCompressionInfo, 0x28);
|
||||
|
||||
typedef struct {
|
||||
u64 offset;
|
||||
u64 size;
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
} NcaMetaDataHashDataInfo;
|
||||
|
||||
NXDT_ASSERT(NcaMetaDataHashDataInfo, 0x30);
|
||||
|
||||
/// Four NCA FS headers are placed right after the 0x400 byte long NCA header in NCA2 and NCA3.
|
||||
/// NCA0 place the FS headers at the start sector from the NcaFsInfo entries.
|
||||
|
@ -315,7 +329,8 @@ typedef struct {
|
|||
NcaAesCtrUpperIv aes_ctr_upper_iv;
|
||||
NcaSparseInfo sparse_info;
|
||||
NcaCompressionInfo compression_info;
|
||||
u8 reserved_2[0x68];
|
||||
NcaMetaDataHashDataInfo hash_data_info;
|
||||
u8 reserved_2[0x30];
|
||||
} NcaFsHeader;
|
||||
|
||||
NXDT_ASSERT(NcaFsHeader, 0x200);
|
||||
|
@ -340,8 +355,9 @@ typedef struct {
|
|||
u8 section_num;
|
||||
u64 section_offset;
|
||||
u64 section_size;
|
||||
u8 section_type; ///< NcaFsSectionType.
|
||||
u8 hash_type; ///< NcaHashType.
|
||||
u8 encryption_type; ///< NcaEncryptionType.
|
||||
u8 section_type; ///< NcaFsSectionType.
|
||||
u8 ctr[AES_BLOCK_SIZE]; ///< Used to update the AES CTR context IV based on the desired offset.
|
||||
Aes128CtrContext ctr_ctx;
|
||||
Aes128XtsContext xts_decrypt_ctx;
|
||||
|
|
|
@ -42,7 +42,7 @@ extern "C" {
|
|||
/// 'NpdmSignatureKeyGeneration_Current' will always point to the last known key generation value.
|
||||
typedef enum {
|
||||
NpdmSignatureKeyGeneration_Since100NUP = 0, ///< 1.0.0 - 8.1.1.
|
||||
NpdmSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.0.
|
||||
NpdmSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.2.
|
||||
NpdmSignatureKeyGeneration_Current = NpdmSignatureKeyGeneration_Since900NUP,
|
||||
NpdmSignatureKeyGeneration_Max = (NpdmSignatureKeyGeneration_Current + 1)
|
||||
} NpdmSignatureKeyGeneration;
|
||||
|
@ -92,8 +92,8 @@ NXDT_ASSERT(NpdmMetaHeader, 0x80);
|
|||
typedef enum {
|
||||
NpdmMemoryRegion_Application = 0,
|
||||
NpdmMemoryRegion_Applet = 1,
|
||||
NpdmMemoryRegion_SystemSecure = 2,
|
||||
NpdmMemoryRegion_SystemNonSecure = 3,
|
||||
NpdmMemoryRegion_SecureSystem = 2,
|
||||
NpdmMemoryRegion_NonSecureSystem = 3,
|
||||
|
||||
/// Old.
|
||||
NpdmMemoryRegion_NonSecure = NpdmMemoryRegion_Application,
|
||||
|
@ -103,8 +103,8 @@ typedef enum {
|
|||
typedef struct {
|
||||
u32 production : 1;
|
||||
u32 unqualified_approval : 1;
|
||||
u32 memory_region : 2; ///< NpdmMemoryRegion.
|
||||
u32 reserved : 28;
|
||||
u32 memory_region : 5; ///< NpdmMemoryRegion.
|
||||
u32 reserved : 25;
|
||||
} NpdmAcidFlags;
|
||||
|
||||
NXDT_ASSERT(NpdmAcidFlags, 0x4);
|
||||
|
|
|
@ -148,7 +148,7 @@ NX_INLINE void gamecardCloseHandle(void);
|
|||
|
||||
static bool gamecardOpenStorageArea(u8 area);
|
||||
static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset);
|
||||
static void gamecardCloseStorageArea(void);
|
||||
static void gamecardCloseStorageArea(bool switch_to_normal);
|
||||
|
||||
static bool gamecardGetStorageAreasSizes(void);
|
||||
NX_INLINE u64 gamecardGetCapacityFromRomSizeValue(u8 rom_size);
|
||||
|
@ -864,7 +864,7 @@ static void gamecardFreeInfo(bool clear_status)
|
|||
|
||||
g_gameCardHfsCount = 0;
|
||||
|
||||
gamecardCloseStorageArea();
|
||||
gamecardCloseStorageArea(true);
|
||||
|
||||
if (clear_status) g_gameCardStatus = GameCardStatus_NotInserted;
|
||||
}
|
||||
|
@ -1033,9 +1033,6 @@ static bool gamecardGetHandleAndStorage(u32 partition)
|
|||
|
||||
NX_INLINE void gamecardCloseHandle(void)
|
||||
{
|
||||
/* TODO: find a way to properly close a gamecard handle. */
|
||||
if (!g_gameCardHandle.value) return;
|
||||
svcCloseHandle(g_gameCardHandle.value);
|
||||
g_gameCardHandle.value = 0;
|
||||
}
|
||||
|
||||
|
@ -1051,7 +1048,7 @@ static bool gamecardOpenStorageArea(u8 area)
|
|||
if (g_gameCardHandle.value && serviceIsActive(&(g_gameCardStorage.s)) && g_gameCardCurrentStorageArea == area) return true;
|
||||
|
||||
/* Close both gamecard handle and open storage area. */
|
||||
gamecardCloseStorageArea();
|
||||
gamecardCloseStorageArea(false);
|
||||
|
||||
/* Retrieve both a new gamecard handle and a storage area handle. */
|
||||
if (!gamecardGetHandleAndStorage(area - 1)) /* Zero-based index. */
|
||||
|
@ -1143,8 +1140,22 @@ end:
|
|||
return success;
|
||||
}
|
||||
|
||||
static void gamecardCloseStorageArea(void)
|
||||
static void gamecardCloseStorageArea(bool switch_to_normal)
|
||||
{
|
||||
if (g_gameCardCurrentStorageArea == GameCardStorageArea_None) return;
|
||||
|
||||
/* Workaround: try to reset the Lotus driver by switching to the normal storage area before closing all gamecard comms. */
|
||||
if (switch_to_normal && g_gameCardCurrentStorageArea == GameCardStorageArea_Secure)
|
||||
{
|
||||
LOG_MSG("Switching to normal area before shutting down.");
|
||||
if (gamecardOpenStorageArea(GameCardStorageArea_Normal))
|
||||
{
|
||||
/* Perform a bogus read (just one page). */
|
||||
u8 bogus[GAMECARD_PAGE_SIZE] = {0};
|
||||
gamecardReadStorageArea(bogus, sizeof(bogus), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceIsActive(&(g_gameCardStorage.s)))
|
||||
{
|
||||
fsStorageClose(&g_gameCardStorage);
|
||||
|
@ -1172,7 +1183,7 @@ static bool gamecardGetStorageAreasSizes(void)
|
|||
|
||||
rc = fsStorageGetSize(&g_gameCardStorage, (s64*)&area_size);
|
||||
|
||||
gamecardCloseStorageArea();
|
||||
gamecardCloseStorageArea(false);
|
||||
|
||||
if (R_FAILED(rc) || !area_size)
|
||||
{
|
||||
|
|
|
@ -573,14 +573,14 @@ static bool keysDeriveNcaHeaderKey(void)
|
|||
rc = splCryptoGenerateAesKey(g_ncaKeyset.nca_header_kek_sealed, g_ncaKeyset.nca_header_key_source, g_ncaKeyset.nca_header_key);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key, part 1).", rc);
|
||||
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key) (#1).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = splCryptoGenerateAesKey(g_ncaKeyset.nca_header_kek_sealed, g_ncaKeyset.nca_header_key_source + AES_128_KEY_SIZE, g_ncaKeyset.nca_header_key + AES_128_KEY_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key, part 2).", rc);
|
||||
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key) (#2).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -194,7 +194,26 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
/* Check if we're dealing with an invalid start offset or an empty size. */
|
||||
if (fs_ctx->section_offset < sizeof(NcaHeader) || !fs_ctx->section_size) continue;
|
||||
|
||||
/* Determine encryption type. */
|
||||
/* Determine hash and encryption types. */
|
||||
fs_ctx->hash_type = fs_ctx->header.hash_type;
|
||||
if (fs_ctx->hash_type == NcaHashType_Auto || fs_ctx->hash_type == NcaHashType_AutoSha3)
|
||||
{
|
||||
switch(fs_ctx->section_num)
|
||||
{
|
||||
case 0: /* ExeFS Partition FS. */
|
||||
fs_ctx->hash_type = (fs_ctx->hash_type == NcaHashType_Auto ? NcaHashType_HierarchicalSha256 : NcaHashType_HierarchicalSha3256);
|
||||
break;
|
||||
case 1: /* RomFS. */
|
||||
fs_ctx->hash_type = (fs_ctx->hash_type == NcaHashType_Auto ? NcaHashType_HierarchicalIntegrity : NcaHashType_HierarchicalIntegritySha3);
|
||||
break;
|
||||
case 2: /* Logo Partition FS. */
|
||||
fs_ctx->hash_type = NcaHashType_None;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fs_ctx->encryption_type = (out->format_version == NcaVersion_Nca0 ? NcaEncryptionType_AesXts : fs_ctx->header.encryption_type);
|
||||
if (fs_ctx->encryption_type == NcaEncryptionType_Auto)
|
||||
{
|
||||
|
@ -212,19 +231,21 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
}
|
||||
}
|
||||
|
||||
/* Check if we're dealing with an invalid encryption type value. */
|
||||
if (fs_ctx->encryption_type == NcaEncryptionType_Auto || fs_ctx->encryption_type > NcaEncryptionType_AesCtrEx) continue;
|
||||
/* Check if we're dealing with invalid hash/encryption type values. */
|
||||
if (fs_ctx->hash_type == NcaHashType_Auto || fs_ctx->hash_type == NcaHashType_AutoSha3 || fs_ctx->hash_type > NcaHashType_HierarchicalIntegritySha3 || \
|
||||
fs_ctx->encryption_type == NcaEncryptionType_Auto || fs_ctx->encryption_type > NcaEncryptionType_AesCtrExSkipLayerHash) continue;
|
||||
|
||||
/* Determine FS section type. */
|
||||
if (fs_ctx->header.fs_type == NcaFsType_PartitionFs && fs_ctx->header.hash_type == NcaHashType_HierarchicalSha256)
|
||||
if (fs_ctx->header.fs_type == NcaFsType_PartitionFs && (fs_ctx->hash_type == NcaHashType_HierarchicalSha256 || fs_ctx->hash_type == NcaHashType_HierarchicalSha3256))
|
||||
{
|
||||
fs_ctx->section_type = NcaFsSectionType_PartitionFs;
|
||||
} else
|
||||
if (fs_ctx->header.fs_type == NcaFsType_RomFs && fs_ctx->header.hash_type == NcaHashType_HierarchicalIntegrity)
|
||||
if (fs_ctx->header.fs_type == NcaFsType_RomFs && (fs_ctx->hash_type == NcaHashType_HierarchicalIntegrity || fs_ctx->hash_type == NcaHashType_HierarchicalIntegritySha3))
|
||||
{
|
||||
fs_ctx->section_type = (fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx ? NcaFsSectionType_PatchRomFs : NcaFsSectionType_RomFs);
|
||||
fs_ctx->section_type = ((fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx || fs_ctx->encryption_type == NcaEncryptionType_AesCtrExSkipLayerHash) ? \
|
||||
NcaFsSectionType_PatchRomFs : NcaFsSectionType_RomFs);
|
||||
} else
|
||||
if (fs_ctx->header.fs_type == NcaFsType_RomFs && fs_ctx->header.hash_type == NcaHashType_HierarchicalSha256 && out->format_version == NcaVersion_Nca0)
|
||||
if (fs_ctx->header.fs_type == NcaFsType_RomFs && fs_ctx->hash_type == NcaHashType_HierarchicalSha256 && out->format_version == NcaVersion_Nca0)
|
||||
{
|
||||
fs_ctx->section_type = NcaFsSectionType_Nca0RomFs;
|
||||
}
|
||||
|
@ -753,7 +774,7 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
|
|||
}
|
||||
|
||||
/* Clear encrypted key area. */
|
||||
memset(&(ctx->header.encrypted_key_area), 0, NCA_USED_KEY_AREA_SIZE);
|
||||
memset(&(ctx->header.encrypted_key_area), 0, sizeof(NcaEncryptedKeyArea));
|
||||
|
||||
/* Initialize AES-128-ECB encryption context using the retrieved KAEK. */
|
||||
aes128ContextCreate(&key_area_ctx, kaek, true);
|
||||
|
|
|
@ -341,7 +341,7 @@ static u32 save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_c
|
|||
|
||||
static bool save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, u64 master_hash_offset, ivfc_save_hdr_t *ivfc)
|
||||
{
|
||||
if (!ctx || !ctx->levels || !ivfc || !ivfc->num_levels)
|
||||
if (!ctx || !ivfc || !ivfc->num_levels)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
|
|
|
@ -238,6 +238,7 @@ static const TitleSystemEntry g_systemTitles[] = {
|
|||
{ 0x0100000000001014, "PlayReport" },
|
||||
{ 0x0100000000001015, "MaintenanceMenu" },
|
||||
{ 0x0100000000001016, "application_install" }, ///< Placeholder.
|
||||
{ 0x0100000000001017, "nn.am.SystemReportTask" }, ///< Placeholder.
|
||||
{ 0x0100000000001018, "systemupdate_dl_throughput" }, ///< Placeholder.
|
||||
{ 0x0100000000001019, "volume_update"}, ///< Placeholder.
|
||||
{ 0x010000000000101A, "gift" },
|
||||
|
@ -256,6 +257,7 @@ static const TitleSystemEntry g_systemTitles[] = {
|
|||
{ 0x0100000000001028, "ns_unknown_1" }, ///< Placeholder.
|
||||
{ 0x010000000000102A, "am_unknown_2" }, ///< Placeholder.
|
||||
{ 0x010000000000102B, "glue_unknown_1" }, ///< Placeholder.
|
||||
{ 0x010000000000102C, "am_unknown_3" }, ///< Placeholder.
|
||||
{ 0x010000000000102E, "blacklist" },
|
||||
{ 0x010000000000102F, "content_delivery" },
|
||||
{ 0x0100000000001031, "ns_unknown_2" }, ///< Placeholder.
|
||||
|
@ -264,6 +266,7 @@ static const TitleSystemEntry g_systemTitles[] = {
|
|||
{ 0x0100000000001034, "ngct_unknown" }, ///< Placeholder.
|
||||
{ 0x0100000000001037, "nim_unknown" }, ///< Placeholder.
|
||||
{ 0x0100000000001038, "sample" },
|
||||
{ 0x010000000000103C, "mnpp" }, ///< Placeholder.
|
||||
{ 0x0100000000001FFF, "EndOceanProgramId" },
|
||||
|
||||
/* Development system applets. */
|
||||
|
|
Loading…
Reference in a new issue