mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
NACP changes.
Fixed types for some NACP struct entries (thanks @0Liam !) + added functions to generate and write NACP patches.
This commit is contained in:
parent
2b8e80c283
commit
0229124173
11 changed files with 185 additions and 101 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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, \
|
||||
" <Rating>\n" \
|
||||
" <Organization>%s</Organization>\n" \
|
||||
" <Age>%u</Age>\n" \
|
||||
" <Age>%d</Age>\n" \
|
||||
" </Rating>\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;
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
27
todo.txt
27
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
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue