From 0229124173f3c68720368cf7f5f155e854251414 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Wed, 28 Oct 2020 18:48:46 -0400 Subject: [PATCH] NACP changes. Fixed types for some NACP struct entries (thanks @0Liam !) + added functions to generate and write NACP patches. --- code_templates/nsp_dumper_sd.c | 31 +++++++---- code_templates/nsp_dumper_usb.c | 30 ++++++---- source/cnmt.c | 4 +- source/cnmt.h | 2 +- source/nacp.c | 97 +++++++++++++++++++++++++++------ source/nacp.h | 82 ++++++++++++++-------------- source/npdm.c | 4 +- source/npdm.h | 2 +- source/romfs.c | 2 + source/romfs.h | 5 +- todo.txt | 27 ++++----- 11 files changed, 185 insertions(+), 101 deletions(-) diff --git a/code_templates/nsp_dumper_sd.c b/code_templates/nsp_dumper_sd.c index 9a65ace..812fab8 100644 --- a/code_templates/nsp_dumper_sd.c +++ b/code_templates/nsp_dumper_sd.c @@ -47,8 +47,11 @@ typedef struct { static options_t options[] = { { "set download distribution type", false }, { "remove console specific data", false }, - { "remove titlekey crypto (implies previous option)", false }, - { "change acid rsa key/sig", false } + { "remove titlekey crypto (overrides previous option)", false }, + { "change acid rsa key/sig", false }, + { "disable linked account requirement", false }, + { "enable screenshots", false }, + { "enable video capture", false } }; static const u32 options_count = MAX_ELEMENTS(options); @@ -85,7 +88,14 @@ static void nspDump(TitleInfo *title_info) for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no"); printf("______________________________\n\n"); - bool set_download_type = options[0].val, remove_console_data = options[1].val, remove_titlekey_crypto = options[2].val, change_acid_rsa = options[3].val, success = false; + bool set_download_type = options[0].val; + bool remove_console_data = options[1].val; + bool remove_titlekey_crypto = options[2].val; + bool change_acid_rsa = options[3].val; + bool patch_sua = options[4].val; + bool patch_screenshot = options[5].val; + bool patch_video_capture = options[6].val; + bool success = false; u8 *buf = NULL; char *dump_name = NULL, *path = NULL; @@ -263,7 +273,11 @@ static void nspDump(TitleInfo *title_info) goto end; } - // add nacp mods here + if (!nacpGenerateNcaPatch(cur_nacp_ctx, patch_sua, patch_screenshot, patch_video_capture)) + { + consolePrint("nacp nca patch failed (%s)\n", cur_nca_ctx->content_id_str); + goto end; + } if (!nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx))) { @@ -505,18 +519,13 @@ static void nspDump(TitleInfo *title_info) switch(cur_nca_ctx->content_type) { case NcmContentType_Meta: - { cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset); break; - } case NcmContentType_Program: - { - ProgramInfoContext *cur_program_info_ctx = (ProgramInfoContext*)cur_nca_ctx->content_type_ctx; - programInfoWriteNcaPatch(cur_program_info_ctx, buf, blksize, offset); + programInfoWriteNcaPatch((ProgramInfoContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset); break; - } case NcmContentType_Control: - // write nacp patches here + nacpWriteNcaPatch((NacpContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset); break; default: break; diff --git a/code_templates/nsp_dumper_usb.c b/code_templates/nsp_dumper_usb.c index 50278e2..9d64bd4 100644 --- a/code_templates/nsp_dumper_usb.c +++ b/code_templates/nsp_dumper_usb.c @@ -46,8 +46,11 @@ typedef struct { static options_t options[] = { { "set download distribution type", false }, { "remove console specific data", false }, - { "remove titlekey crypto (implies previous option)", false }, - { "change acid rsa key/sig", false } + { "remove titlekey crypto (overrides previous option)", false }, + { "change acid rsa key/sig", false }, + { "disable linked account requirement", false }, + { "enable screenshots", false }, + { "enable video capture", false } }; static const u32 options_count = MAX_ELEMENTS(options); @@ -84,7 +87,13 @@ static void nspDump(TitleInfo *title_info) for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no"); printf("______________________________\n\n"); - bool set_download_type = options[0].val, remove_console_data = options[1].val, remove_titlekey_crypto = options[2].val, change_acid_rsa = options[3].val; + bool set_download_type = options[0].val; + bool remove_console_data = options[1].val; + bool remove_titlekey_crypto = options[2].val; + bool change_acid_rsa = options[3].val; + bool patch_sua = options[4].val; + bool patch_screenshot = options[5].val; + bool patch_video_capture = options[6].val; u8 *buf = NULL; char *dump_name = NULL, *path = NULL; @@ -262,7 +271,11 @@ static void nspDump(TitleInfo *title_info) goto end; } - // add nacp mods here + if (!nacpGenerateNcaPatch(cur_nacp_ctx, patch_sua, patch_screenshot, patch_video_capture)) + { + consolePrint("nacp nca patch failed (%s)\n", cur_nca_ctx->content_id_str); + goto end; + } if (!nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx))) { @@ -523,18 +536,13 @@ static void nspDump(TitleInfo *title_info) switch(cur_nca_ctx->content_type) { case NcmContentType_Meta: - { cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset); break; - } case NcmContentType_Program: - { - ProgramInfoContext *cur_program_info_ctx = (ProgramInfoContext*)cur_nca_ctx->content_type_ctx; - programInfoWriteNcaPatch(cur_program_info_ctx, buf, blksize, offset); + programInfoWriteNcaPatch((ProgramInfoContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset); break; - } case NcmContentType_Control: - // write nacp patches here + nacpWriteNcaPatch((NacpContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset); break; default: break; diff --git a/source/cnmt.c b/source/cnmt.c index 897c26b..13f98a4 100644 --- a/source/cnmt.c +++ b/source/cnmt.c @@ -320,14 +320,14 @@ void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u6 /* Using cnmtIsValidContext() here would probably take up precious CPU cycles. */ if (!cnmt_ctx || !cnmt_ctx->nca_ctx || cnmt_ctx->nca_ctx->content_type != NcmContentType_Meta || !cnmt_ctx->nca_ctx->content_type_ctx_patch || cnmt_ctx->nca_patch.written) return; - /* Attempt to write Partition FS entry. */ + /* Attempt to write Partition FS entry patch. */ pfsWriteEntryPatchToMemoryBuffer(&(cnmt_ctx->pfs_ctx), &(cnmt_ctx->nca_patch), buf, buf_size, buf_offset); /* Check if we need to update the NCA content type context patch status. */ if (cnmt_ctx->nca_patch.written) { cnmt_ctx->nca_ctx->content_type_ctx_patch = false; - LOGFILE("CNMT Partition FS file entry patch successfully written to NCA \"%s\"!", cnmt_ctx->nca_ctx->content_id_str); + LOGFILE("CNMT Partition FS entry patch successfully written to NCA \"%s\"!", cnmt_ctx->nca_ctx->content_id_str); } } diff --git a/source/cnmt.h b/source/cnmt.h index 0fd4ed7..f5e1edd 100644 --- a/source/cnmt.h +++ b/source/cnmt.h @@ -247,7 +247,7 @@ bool cnmtUpdateContentInfo(ContentMetaContext *cnmt_ctx, NcaContext *nca_ctx); /// Generates a Partition FS entry patch for the NcaContext pointed to by the input ContentMetaContext, using its raw CNMT data. bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx); -/// Writes data from the Partition FS patch in the input ContentMetaContext to the provided buffer. +/// Writes data from the Partition FS entry patch in the input ContentMetaContext to the provided buffer. void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u64 buf_offset); /// Generates an AuthoringTool-like XML using information from a previously initialized ContentMetaContext, as well as a pointer to 'nca_ctx_count' NcaContext with content information. diff --git a/source/nacp.c b/source/nacp.c index eb32cb4..ca5cfa8 100644 --- a/source/nacp.c +++ b/source/nacp.c @@ -329,6 +329,71 @@ end: return success; } +bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_screenshot, bool patch_video_capture) +{ + if (!nacpIsValidContext(nacp_ctx)) + { + LOGFILE("Invalid parameters!"); + return false; + } + + _NacpStruct *data = nacp_ctx->data; + u8 nacp_hash[SHA256_HASH_SIZE] = {0}; + + /* Check if we're not patching anything. */ + if (!patch_sua && !patch_screenshot && !patch_video_capture) return true; + + /* Patch StartupUserAccount, StartupUserAccountOption and UserAccountSwitchLock. */ + if (patch_sua) + { + data->startup_user_account = NacpStartupUserAccount_None; + data->startup_user_account_option &= ~NacpStartupUserAccountOption_IsOptional; + data->user_account_switch_lock = NacpUserAccountSwitchLock_Disable; + } + + /* Patch Screenshot. */ + if (patch_screenshot) data->screenshot = NacpScreenshot_Allow; + + /* Patch VideoCapture. */ + if (patch_video_capture) data->video_capture = NacpVideoCapture_Enable; + + /* Check if we really need to generate this patch. */ + sha256CalculateHash(nacp_hash, data, sizeof(_NacpStruct)); + if (!memcmp(nacp_hash, nacp_ctx->data_hash, sizeof(nacp_hash))) + { + LOGFILE("Skipping NACP patching - no flags have changed."); + return true; + } + + /* Generate RomFS file entry patch. */ + if (!romfsGenerateFileEntryPatch(&(nacp_ctx->romfs_ctx), nacp_ctx->romfs_file_entry, data, sizeof(_NacpStruct), 0, &(nacp_ctx->nca_patch))) + { + LOGFILE("Failed to generate RomFS file entry patch!"); + return false; + } + + /* Update NCA content type context patch status. */ + nacp_ctx->nca_ctx->content_type_ctx_patch = true; + + return true; +} + +void nacpWriteNcaPatch(NacpContext *nacp_ctx, void *buf, u64 buf_size, u64 buf_offset) +{ + /* Using nacpIsValidContext() here would probably take up precious CPU cycles. */ + if (!nacp_ctx || !nacp_ctx->nca_ctx || nacp_ctx->nca_ctx->content_type != NcmContentType_Control || !nacp_ctx->nca_ctx->content_type_ctx_patch || nacp_ctx->nca_patch.written) return; + + /* Attempt to write RomFS file entry patch. */ + romfsWriteFileEntryPatchToMemoryBuffer(&(nacp_ctx->romfs_ctx), &(nacp_ctx->nca_patch), buf, buf_size, buf_offset); + + /* Check if we need to update the NCA content type context patch status. */ + if (nacp_ctx->nca_patch.written) + { + nacp_ctx->nca_ctx->content_type_ctx_patch = false; + LOGFILE("NACP RomFS file entry patch successfully written to NCA \"%s\"!", nacp_ctx->nca_ctx->content_id_str); + } +} + bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version) { if (!nacpIsValidContext(nacp_ctx)) @@ -424,13 +489,13 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir /* Rating. */ for(i = 0, count = 0; i < NacpRatingAgeOrganization_Count; i++) { - u8 age = *((u8*)&(nacp->rating_age) + i); - if (age == 0xFF) continue; + s8 age = *(((s8*)&(nacp->rating_age)) + i); + if (age < 0) continue; if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ " \n" \ " %s\n" \ - " %u\n" \ + " %d\n" \ " \n", \ nacpGetRatingAgeOrganizationString(i), age)) goto end; @@ -450,19 +515,19 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SaveDataOwnerId", nacp->save_data_owner_id)) goto end; /* UserAccountSaveDataSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSize", nacp->user_account_save_data_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSize", (u64)nacp->user_account_save_data_size)) goto end; /* UserAccountSaveDataJournalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSize", nacp->user_account_save_data_journal_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSize", (u64)nacp->user_account_save_data_journal_size)) goto end; /* DeviceSaveDataSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSize", nacp->device_save_data_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSize", (u64)nacp->device_save_data_size)) goto end; /* DeviceSaveDataJournalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSize", nacp->device_save_data_journal_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSize", (u64)nacp->device_save_data_journal_size)) goto end; /* BcatDeliveryCacheStorageSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatDeliveryCacheStorageSize", nacp->bcat_delivery_cache_storage_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatDeliveryCacheStorageSize", (u64)nacp->bcat_delivery_cache_storage_size)) goto end; /* ApplicationErrorCodeCategory. */ if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end; @@ -541,28 +606,28 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end; /* UserAccountSaveDataSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", nacp->user_account_save_data_size_max)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", (u64)nacp->user_account_save_data_size_max)) goto end; /* UserAccountSaveDataJournalSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSizeMax", nacp->user_account_save_data_journal_size_max)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSizeMax", (u64)nacp->user_account_save_data_journal_size_max)) goto end; /* DeviceSaveDataSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSizeMax", nacp->device_save_data_size_max)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSizeMax", (u64)nacp->device_save_data_size_max)) goto end; /* DeviceSaveDataJournalSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSizeMax", nacp->device_save_data_journal_size_max)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSizeMax", (u64)nacp->device_save_data_journal_size_max)) goto end; /* TemporaryStorageSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "TemporaryStorageSize", nacp->temporary_storage_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "TemporaryStorageSize", (u64)nacp->temporary_storage_size)) goto end; /* CacheStorageSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageSize", nacp->cache_storage_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageSize", (u64)nacp->cache_storage_size)) goto end; /* CacheStorageJournalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageJournalSize", nacp->cache_storage_journal_size)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageJournalSize", (u64)nacp->cache_storage_journal_size)) goto end; /* CacheStorageDataAndJournalSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageDataAndJournalSizeMax", nacp->cache_storage_data_and_journal_size_max)) goto end; + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageDataAndJournalSizeMax", (u64)nacp->cache_storage_data_and_journal_size_max)) goto end; /* CacheStorageIndexMax. */ if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageIndexMax", nacp->cache_storage_index_max, true)) goto end; diff --git a/source/nacp.h b/source/nacp.h index e4cb439..e427bf1 100644 --- a/source/nacp.h +++ b/source/nacp.h @@ -75,7 +75,11 @@ typedef enum { NacpLanguage_TraditionalChinese = 13, NacpLanguage_SimplifiedChinese = 14, NacpLanguage_BrazilianPortuguese = 15, - NacpLanguage_Count = 16 ///< Total values supported by this enum. + NacpLanguage_Count = 16, ///< Total values supported by this enum. + + /// Old. + NacpLanguage_Taiwanese = NacpLanguage_TraditionalChinese, + NacpLanguage_Chinese = NacpLanguage_SimplifiedChinese } NacpLanguage; typedef enum { @@ -156,20 +160,20 @@ typedef enum { } NacpRatingAgeOrganization; typedef struct { - u8 cero; - u8 gracgcrb; - u8 gsrmr; - u8 esrb; - u8 class_ind; - u8 usk; - u8 pegi; - u8 pegi_portugal; - u8 pegibbfc; - u8 russian; - u8 acb; - u8 oflc; - u8 iarc_generic; - u8 reserved[0x13]; + s8 cero; + s8 grac_gcrb; + s8 gsrmr; + s8 esrb; + s8 class_ind; + s8 usk; + s8 pegi; + s8 pegi_portugal; + s8 pegi_bbfc; + s8 russian; + s8 acb; + s8 oflc; + s8 iarc_generic; + s8 reserved[0x13]; } NacpRatingAge; typedef enum { @@ -293,11 +297,11 @@ typedef struct { char display_version[0x10]; u64 add_on_content_base_id; u64 save_data_owner_id; - u64 user_account_save_data_size; - u64 user_account_save_data_journal_size; - u64 device_save_data_size; - u64 device_save_data_journal_size; - u64 bcat_delivery_cache_storage_size; + s64 user_account_save_data_size; + s64 user_account_save_data_journal_size; + s64 device_save_data_size; + s64 device_save_data_journal_size; + s64 bcat_delivery_cache_storage_size; char application_error_code_category[0x8]; u64 local_communication_id[8]; u8 logo_type; ///< NacpLogoType. @@ -311,14 +315,14 @@ typedef struct { char bcat_passphrase[0x41]; u8 startup_user_account_option; ///< NacpStartupUserAccountOption. u8 reserved_2[0x6]; - u64 user_account_save_data_size_max; - u64 user_account_save_data_journal_size_max; - u64 device_save_data_size_max; - u64 device_save_data_journal_size_max; - u64 temporary_storage_size; - u64 cache_storage_size; - u64 cache_storage_journal_size; - u64 cache_storage_data_and_journal_size_max; + s64 user_account_save_data_size_max; + s64 user_account_save_data_journal_size_max; + s64 device_save_data_size_max; + s64 device_save_data_journal_size_max; + s64 temporary_storage_size; + s64 cache_storage_size; + s64 cache_storage_journal_size; + s64 cache_storage_data_and_journal_size_max; u16 cache_storage_index_max; u8 reserved_3[0x6]; u64 play_log_queryable_application_id[0x10]; @@ -363,6 +367,15 @@ typedef struct { /// Initializes a NacpContext using a previously initialized NcaContext (which must belong to a Control NCA). bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx); +/// Changes flags in the NACP from the input NacpContext and generates a RomFS file entry patch if needed. +/// If 'patch_sua' is true, StartupUserAccount is set to None, the IsOptional bit in StartupUserAccountOption is cleared and UserAccountSwitchLock is set to Disable. +/// If 'patch_screenshot' is true, Screenshot is set to Allow. +/// If 'patch_video_capture' is true, VideoCapture is set to Enable. +bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_screenshot, bool patch_video_capture); + +/// Writes data from the RomFS file entry patch in the input NacpContext to the provided buffer. +void nacpWriteNcaPatch(NacpContext *nacp_ctx, void *buf, u64 buf_size, u64 buf_offset); + /// Generates an AuthoringTool-like XML using information from a previously initialized NacpContext, as well as the Application/Patch version and the required system version. /// If the function succeeds, XML data and size will get saved to the 'authoring_tool_xml' and 'authoring_tool_xml_size' members from the NacpContext. bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version); @@ -438,17 +451,4 @@ NX_INLINE bool nacpIsValidContext(NacpContext *nacp_ctx) return true; } -NX_INLINE bool nacpIsNcaPatchRequired(NacpContext *nacp_ctx) -{ - if (!nacpIsValidContext(nacp_ctx)) return false; - u8 tmp_hash[SHA256_HASH_SIZE] = {0}; - sha256CalculateHash(tmp_hash, nacp_ctx->data, sizeof(_NacpStruct)); - return (memcmp(tmp_hash, nacp_ctx->data_hash, SHA256_HASH_SIZE) != 0); -} - -NX_INLINE bool nacpGenerateNcaPatch(NacpContext *nacp_ctx) -{ - return (nacpIsValidContext(nacp_ctx) && romfsGenerateFileEntryPatch(&(nacp_ctx->romfs_ctx), nacp_ctx->romfs_file_entry, nacp_ctx->data, sizeof(_NacpStruct), 0, &(nacp_ctx->nca_patch))); -} - #endif /* __NACP_H__ */ diff --git a/source/npdm.c b/source/npdm.c index a3ff7bc..b447258 100644 --- a/source/npdm.c +++ b/source/npdm.c @@ -306,13 +306,13 @@ void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_o if (!npdm_ctx || !npdm_ctx->pfs_ctx || !npdm_ctx->pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)npdm_ctx->pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || \ !nca_ctx->content_type_ctx_patch || npdm_ctx->nca_patch.written) return; - /* Attempt to write Partition FS entry. */ + /* Attempt to write Partition FS entry patch. */ pfsWriteEntryPatchToMemoryBuffer(npdm_ctx->pfs_ctx, &(npdm_ctx->nca_patch), buf, buf_size, buf_offset); /* Check if we need to update the NCA content type context patch status. */ if (npdm_ctx->nca_patch.written) { nca_ctx->content_type_ctx_patch = false; - LOGFILE("NPDM Partition FS file entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str); + LOGFILE("NPDM Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str); } } diff --git a/source/npdm.h b/source/npdm.h index bbbb972..2bfa680 100644 --- a/source/npdm.h +++ b/source/npdm.h @@ -557,7 +557,7 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx /// Changes the ACID public key from the NPDM in the input NpdmContext, updates the ACID signature from the NCA header in the underlying NCA context and generates a Partition FS entry patch. bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx); -/// Writes data from the Partition FS patch in the input NpdmContext to the provided buffer. +/// Writes data from the Partition FS entry patch in the input NpdmContext to the provided buffer. void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset); /// Helper inline functions. diff --git a/source/romfs.c b/source/romfs.c index f718de7..c001ec3 100644 --- a/source/romfs.c +++ b/source/romfs.c @@ -524,6 +524,8 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt success = ncaGenerateHierarchicalIntegrityPatch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->cur_format_patch)); } + out->written = false; + if (!success) LOGFILE("Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry!", data_size, \ ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? "Sha256" : "Integrity", fs_offset); diff --git a/source/romfs.h b/source/romfs.h index 9d4806e..37976b4 100644 --- a/source/romfs.h +++ b/source/romfs.h @@ -106,6 +106,7 @@ typedef struct { typedef struct { bool use_old_format_patch; ///< Old format patch flag. + bool written; ///< Set to true if the patch has been completely written. NcaHierarchicalSha256Patch old_format_patch; ///< Used with NCA0 RomFS sections. NcaHierarchicalIntegrityPatch cur_format_patch; ///< Used with NCA2/NCA3 RomFS sections. } RomFileSystemFileEntryPatch; @@ -183,17 +184,19 @@ NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx, if (patch->use_old_format_patch) { ncaWriteHierarchicalSha256PatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, &(patch->old_format_patch), buf, buf_size, buf_offset); + patch->written = patch->old_format_patch.written; } else { ncaWriteHierarchicalIntegrityPatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, &(patch->cur_format_patch), buf, buf_size, buf_offset); + patch->written = patch->cur_format_patch.written; } } NX_INLINE void romfsFreeFileEntryPatch(RomFileSystemFileEntryPatch *patch) { if (!patch) return; - patch->use_old_format_patch = false; ncaFreeHierarchicalSha256Patch(&(patch->old_format_patch)); ncaFreeHierarchicalIntegrityPatch(&(patch->cur_format_patch)); + memset(patch, 0, sizeof(RomFileSystemFileEntryPatch)); } #endif /* __ROMFS_H__ */ diff --git a/todo.txt b/todo.txt index 48fb768..458ac5b 100644 --- a/todo.txt +++ b/todo.txt @@ -7,31 +7,28 @@ list of top level functions designed to alter nca data in order of (possible) us * ncaRemoveTitlekeyCrypto (can be used with digital titles + game updates in gamecards) - * cnmtGenerateNcaPatch (Meta) - * calls pfsGenerateEntryPatch - * calls ncaGenerateHierarchicalSha256Patch - * programInfoGenerateNcaPatch (Program) - * calls npdmChangeAcidPublicKeyAndNcaSignature + * calls npdmGenerateNcaPatch * calls pfsGenerateEntryPatch * calls ncaGenerateHierarchicalSha256Patch * nacpGenerateNcaPatch (Control) * calls romfsGenerateFileEntryPatch * calls ncaGenerateHierarchicalSha256Patch / ncaGenerateHierarchicalIntegrityPatch - * nacpIsNcaPatchRequired is used to check if a nacp patch was applied - * missing wrapper for romfsWriteFileEntryPatchToMemoryBuffer !!! - * missing functions for nacp mods !!! * ncaEncryptHeader (doesn't modify anything per se, but it's used to generate new encrypted header data if needed) inside dump loop: + * cnmtGenerateNcaPatch (Meta) + * calls pfsGenerateEntryPatch + * calls ncaGenerateHierarchicalSha256Patch + * returns true if cnmt needs no patching + * demands an immediate ncaEncryptHeader call + * ncaIsHeaderDirty (doesn't modify anything per se, but it's used to check if any of the functions above has been used, basically - and by extension, if the functions below need to be used) * ncaWriteEncryptedHeaderDataToMemoryBuffer (write encrypted nca header data) - * cnmtUpdateContentInfo (used to update content entry info in the raw cnmt copy after dumping each one) - * cnmtWriteNcaPatch (writes cnmt patch) * calls pfsWriteEntryPatchToMemoryBuffer * calls ncaWriteHierarchicalSha256PatchToMemoryBuffer @@ -41,16 +38,16 @@ list of top level functions designed to alter nca data in order of (possible) us * calls pfsWriteEntryPatchToMemoryBuffer * calls ncaWriteHierarchicalSha256PatchToMemoryBuffer - * pfsWriteEntryPatchToMemoryBuffer - * calls ncaWriteHierarchicalSha256PatchToMemoryBuffer + * nacpWriteNcaPatch (writes nacp patch) + * calls romfsWriteFileEntryPatchToMemoryBuffer + * calls ncaWriteHierarchicalSha256PatchToMemoryBuffer / ncaWriteHierarchicalIntegrityPatchToMemoryBuffer - * romfsWriteFileEntryPatchToMemoryBuffer - * calls ncaWriteHierarchicalSha256PatchToMemoryBuffer / ncaWriteHierarchicalIntegrityPatchToMemoryBuffer - * missing nacp wrapper + * cnmtUpdateContentInfo (used to update content entry info in the raw cnmt copy after dumping each one - ignores the current content if its a meta nca) minor steps to take into account: * check if rights_id_available == true and titlekey_retrieved == false (preload handling) + * actually, just inform the user about it - this is being handled