diff --git a/code_templates/xml_generator.c b/code_templates/xml_generator.c index 9d0dd6c..18f05f5 100644 --- a/code_templates/xml_generator.c +++ b/code_templates/xml_generator.c @@ -23,6 +23,7 @@ #include "title.h" #include "cnmt.h" #include "nacp.h" +#include "legal_info.h" static void consolePrint(const char *text, ...) { @@ -64,6 +65,7 @@ int main(int argc, char *argv[]) ContentMetaContext cnmt_ctx = {0}; NacpContext nacp_ctx = {0}; + LegalInfoContext legal_info_ctx = {0}; FILE *xml_fd = NULL; char path[FS_MAX_PATH] = {0}; @@ -188,7 +190,7 @@ int main(int argc, char *argv[]) consolePrint("nca ctx calloc succeeded\n"); - u32 meta_idx = (user_app_data.app_info->content_count - 1), control_idx = 0; + u32 meta_idx = (user_app_data.app_info->content_count - 1), control_idx = 0, legal_idx = 0; for(u32 i = 0, j = 0; i < user_app_data.app_info->content_count; i++) { @@ -203,6 +205,8 @@ int main(int argc, char *argv[]) if (user_app_data.app_info->content_infos[i].content_type == NcmContentType_Control && user_app_data.app_info->content_infos[i].id_offset == 0) control_idx = j; + if (user_app_data.app_info->content_infos[i].content_type == NcmContentType_LegalInformation && user_app_data.app_info->content_infos[i].id_offset == 0) legal_idx = j; + consolePrint("%s nca initialize ctx succeeded\n", titleGetNcmContentTypeName(user_app_data.app_info->content_infos[i].content_type)); j++; } @@ -231,7 +235,7 @@ int main(int argc, char *argv[]) { consolePrint("cnmt xml succeeded\n"); - sprintf(path, "sdmc:/%016lX_xml/%s.cnmt", app_metadata[selected_idx]->title_id, nca_ctx[meta_idx].content_id_str); + sprintf(path, "sdmc:/%016lX_xml/%s.cnmt", app_metadata[selected_idx]->title_id, cnmt_ctx.nca_ctx->content_id_str); xml_fd = fopen(path, "wb"); if (xml_fd) @@ -241,7 +245,7 @@ int main(int argc, char *argv[]) xml_fd = NULL; } - sprintf(path, "sdmc:/%016lX_xml/%s.cnmt.xml", app_metadata[selected_idx]->title_id, nca_ctx[meta_idx].content_id_str); + sprintf(path, "sdmc:/%016lX_xml/%s.cnmt.xml", app_metadata[selected_idx]->title_id, cnmt_ctx.nca_ctx->content_id_str); xml_fd = fopen(path, "wb"); if (xml_fd) @@ -266,7 +270,7 @@ int main(int argc, char *argv[]) { consolePrint("nacp xml succeeded\n"); - sprintf(path, "sdmc:/%016lX_xml/%s.nacp", app_metadata[selected_idx]->title_id, nca_ctx[control_idx].content_id_str); + sprintf(path, "sdmc:/%016lX_xml/%s.nacp", app_metadata[selected_idx]->title_id, nacp_ctx.nca_ctx->content_id_str); xml_fd = fopen(path, "wb"); if (xml_fd) @@ -276,7 +280,7 @@ int main(int argc, char *argv[]) xml_fd = NULL; } - sprintf(path, "sdmc:/%016lX_xml/%s.nacp.xml", app_metadata[selected_idx]->title_id, nca_ctx[control_idx].content_id_str); + sprintf(path, "sdmc:/%016lX_xml/%s.nacp.xml", app_metadata[selected_idx]->title_id, nacp_ctx.nca_ctx->content_id_str); xml_fd = fopen(path, "wb"); if (xml_fd) @@ -290,7 +294,7 @@ int main(int argc, char *argv[]) { NacpIconContext *icon_ctx = &(nacp_ctx.icon_ctx[i]); - sprintf(path, "sdmc:/%016lX_xml/%s.nx.%s.jpg", app_metadata[selected_idx]->title_id, nca_ctx[control_idx].content_id_str, nacpGetLanguageString(icon_ctx->language)); + sprintf(path, "sdmc:/%016lX_xml/%s.nx.%s.jpg", app_metadata[selected_idx]->title_id, nacp_ctx.nca_ctx->content_id_str, nacpGetLanguageString(icon_ctx->language)); xml_fd = fopen(path, "wb"); if (xml_fd) @@ -304,6 +308,24 @@ int main(int argc, char *argv[]) consolePrint("nacp xml failed\n"); } + if (!legalInfoInitializeContext(&legal_info_ctx, &(nca_ctx[legal_idx]))) + { + consolePrint("legalinfo initialize ctx failed\n"); + goto out2; + } + + consolePrint("legalinfo initialize ctx succeeded\n"); + + sprintf(path, "sdmc:/%016lX_xml/%s.legalinfo.xml", app_metadata[selected_idx]->title_id, legal_info_ctx.nca_ctx->content_id_str); + + xml_fd = fopen(path, "wb"); + if (xml_fd) + { + fwrite(legal_info_ctx.authoring_tool_xml, 1, legal_info_ctx.authoring_tool_xml_size, xml_fd); + fclose(xml_fd); + xml_fd = NULL; + } + out2: if (exit_prompt) { @@ -311,6 +333,8 @@ out2: utilsWaitForButtonPress(KEY_NONE); } + legalInfoFreeContext(&legal_info_ctx); + nacpFreeContext(&nacp_ctx); cnmtFreeContext(&cnmt_ctx); diff --git a/legacy/main.c b/legacy/main.c deleted file mode 100644 index b907320..0000000 --- a/legacy/main.c +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include -#include - -#include "ui.h" -#include "util.h" - -int main(int argc, char *argv[]) -{ - int ret = 0; - bool exitMainLoop = false; - - /* Initialize application resources */ - if (!initApplicationResources(argc, argv)) - { - ret = -1; - goto out; - } - - /* Main application loop */ - while(appletMainLoop()) - { - UIResult result = uiProcess(); - switch(result) - { - case resultShowMainMenu: - uiSetState(stateMainMenu); - break; - case resultShowGameCardMenu: - uiSetState(stateGameCardMenu); - break; - case resultShowXciDumpMenu: - uiSetState(stateXciDumpMenu); - break; - case resultDumpXci: - uiSetState(stateDumpXci); - break; - case resultShowNspDumpMenu: - uiSetState(stateNspDumpMenu); - break; - case resultShowNspAppDumpMenu: - uiSetState(stateNspAppDumpMenu); - break; - case resultShowNspPatchDumpMenu: - uiSetState(stateNspPatchDumpMenu); - break; - case resultShowNspAddOnDumpMenu: - uiSetState(stateNspAddOnDumpMenu); - break; - case resultDumpNsp: - uiSetState(stateDumpNsp); - break; - case resultShowHfs0Menu: - uiSetState(stateHfs0Menu); - break; - case resultShowRawHfs0PartitionDumpMenu: - uiSetState(stateRawHfs0PartitionDumpMenu); - break; - case resultDumpRawHfs0Partition: - uiSetState(stateDumpRawHfs0Partition); - break; - case resultShowHfs0PartitionDataDumpMenu: - uiSetState(stateHfs0PartitionDataDumpMenu); - break; - case resultDumpHfs0PartitionData: - uiSetState(stateDumpHfs0PartitionData); - break; - case resultShowHfs0BrowserMenu: - uiSetState(stateHfs0BrowserMenu); - break; - case resultHfs0BrowserGetList: - uiSetState(stateHfs0BrowserGetList); - break; - case resultShowHfs0Browser: - uiSetState(stateHfs0Browser); - break; - case resultHfs0BrowserCopyFile: - uiSetState(stateHfs0BrowserCopyFile); - break; - case resultShowExeFsMenu: - uiSetState(stateExeFsMenu); - break; - case resultShowExeFsSectionDataDumpMenu: - uiSetState(stateExeFsSectionDataDumpMenu); - break; - case resultDumpExeFsSectionData: - uiSetState(stateDumpExeFsSectionData); - break; - case resultShowExeFsSectionBrowserMenu: - uiSetState(stateExeFsSectionBrowserMenu); - break; - case resultExeFsSectionBrowserGetList: - uiSetState(stateExeFsSectionBrowserGetList); - break; - case resultShowExeFsSectionBrowser: - uiSetState(stateExeFsSectionBrowser); - break; - case resultExeFsSectionBrowserCopyFile: - uiSetState(stateExeFsSectionBrowserCopyFile); - break; - case resultShowRomFsMenu: - uiSetState(stateRomFsMenu); - break; - case resultShowRomFsSectionDataDumpMenu: - uiSetState(stateRomFsSectionDataDumpMenu); - break; - case resultDumpRomFsSectionData: - uiSetState(stateDumpRomFsSectionData); - break; - case resultShowRomFsSectionBrowserMenu: - uiSetState(stateRomFsSectionBrowserMenu); - break; - case resultRomFsSectionBrowserGetEntries: - uiSetState(stateRomFsSectionBrowserGetEntries); - break; - case resultShowRomFsSectionBrowser: - uiSetState(stateRomFsSectionBrowser); - break; - case resultRomFsSectionBrowserChangeDir: - uiSetState(stateRomFsSectionBrowserChangeDir); - break; - case resultRomFsSectionBrowserCopyFile: - uiSetState(stateRomFsSectionBrowserCopyFile); - break; - case resultRomFsSectionBrowserCopyDir: - uiSetState(stateRomFsSectionBrowserCopyDir); - break; - case resultDumpGameCardCertificate: - uiSetState(stateDumpGameCardCertificate); - break; - case resultShowSdCardEmmcMenu: - uiSetState(stateSdCardEmmcMenu); - break; - case resultShowSdCardEmmcTitleMenu: - uiSetState(stateSdCardEmmcTitleMenu); - break; - case resultShowSdCardEmmcOrphanPatchAddOnMenu: - uiSetState(stateSdCardEmmcOrphanPatchAddOnMenu); - break; - case resultShowSdCardEmmcBatchModeMenu: - uiSetState(stateSdCardEmmcBatchModeMenu); - break; - case resultSdCardEmmcBatchDump: - uiSetState(stateSdCardEmmcBatchDump); - break; - case resultShowTicketMenu: - uiSetState(stateTicketMenu); - break; - case resultDumpTicket: - uiSetState(stateDumpTicket); - break; - case resultShowUpdateMenu: - uiSetState(stateUpdateMenu); - break; - case resultUpdateNSWDBXml: - uiSetState(stateUpdateNSWDBXml); - break; - case resultUpdateApplication: - uiSetState(stateUpdateApplication); - break; - case resultExit: - exitMainLoop = true; - break; - default: - break; - } - - if (exitMainLoop) break; - } - -out: - /* Deinitialize application resources */ - deinitApplicationResources(); - - return ret; -} diff --git a/legacy/nca.c b/legacy/nca.c index c31f89b..4e8d546 100644 --- a/legacy/nca.c +++ b/legacy/nca.c @@ -22,627 +22,6 @@ extern nca_keyset_t nca_keyset; extern u8 *ncaCtrBuf; -char *getTitleType(u8 type) -{ - char *out = NULL; - - switch(type) - { - case NcmContentMetaType_Application: - out = "Application"; - break; - case NcmContentMetaType_Patch: - out = "Patch"; - break; - case NcmContentMetaType_AddOnContent: - out = "AddOnContent"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getContentType(u8 type) -{ - char *out = NULL; - - switch(type) - { - case NcmContentType_Meta: - out = "Meta"; - break; - case NcmContentType_Program: - out = "Program"; - break; - case NcmContentType_Data: - out = "Data"; - break; - case NcmContentType_Control: - out = "Control"; - break; - case NcmContentType_HtmlDocument: - out = "HtmlDocument"; - break; - case NcmContentType_LegalInformation: - out = "LegalInformation"; - break; - case NcmContentType_DeltaFragment: - out = "DeltaFragment"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getRequiredMinTitleType(u8 type) -{ - char *out = NULL; - - switch(type) - { - case NcmContentMetaType_Application: - case NcmContentMetaType_Patch: - out = "RequiredSystemVersion"; - break; - case NcmContentMetaType_AddOnContent: - out = "RequiredApplicationVersion"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getReferenceTitleIDType(u8 type) -{ - char *out = NULL; - - switch(type) - { - case NcmContentMetaType_Application: - out = "PatchId"; - break; - case NcmContentMetaType_Patch: - out = "OriginalId"; - break; - case NcmContentMetaType_AddOnContent: - out = "ApplicationId"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -void generateCnmtXml(cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, char *out) -{ - if (!xml_program_info || !xml_content_info || !xml_program_info->nca_cnt || !out) return; - - u32 i; - char tmp[NAME_BUF_LEN] = {'\0'}; - - sprintf(out, "\n" \ - "\n" \ - " %s\n" \ - " 0x%016lx\n" \ - " %u\n" \ - " %u\n", \ - getTitleType(xml_program_info->type), \ - xml_program_info->title_id, \ - xml_program_info->version, \ - xml_program_info->required_dl_sysver); - - for(i = 0; i < xml_program_info->nca_cnt; i++) - { - sprintf(tmp, " \n" \ - " %s\n" \ - " %s\n" \ - " %lu\n" \ - " %s\n" \ - " %u\n" \ - " %u\n" \ - " \n", - getContentType(xml_content_info[i].type), \ - xml_content_info[i].nca_id_str, \ - xml_content_info[i].size, \ - xml_content_info[i].hash_str, \ - xml_content_info[i].keyblob, \ - xml_content_info[i].id_offset); - - strcat(out, tmp); - } - - sprintf(tmp, " %s\n" \ - " %u\n" \ - " <%s>%u\n" \ - " <%s>0x%016lx\n", \ - xml_program_info->digest_str, \ - xml_program_info->min_keyblob, \ - getRequiredMinTitleType(xml_program_info->type), \ - xml_program_info->min_sysver, \ - getRequiredMinTitleType(xml_program_info->type), \ - getReferenceTitleIDType(xml_program_info->type), \ - xml_program_info->patch_tid, \ - getReferenceTitleIDType(xml_program_info->type)); - - strcat(out, tmp); - - if (xml_program_info->type == NcmContentMetaType_Application) - { - sprintf(tmp, " %u\n", xml_program_info->min_appver); - strcat(out, tmp); - } - - strcat(out, ""); -} - -void convertNcaSizeToU64(const u8 size[0x6], u64 *out) -{ - if (!size || !out) return; - - u64 tmp = 0; - - tmp |= (((u64)size[5] << 40) & (u64)0xFF0000000000); - tmp |= (((u64)size[4] << 32) & (u64)0x00FF00000000); - tmp |= (((u64)size[3] << 24) & (u64)0x0000FF000000); - tmp |= (((u64)size[2] << 16) & (u64)0x000000FF0000); - tmp |= (((u64)size[1] << 8) & (u64)0x00000000FF00); - tmp |= ((u64)size[0] & (u64)0x0000000000FF); - - *out = tmp; -} - -void convertU64ToNcaSize(const u64 size, u8 out[0x6]) -{ - if (!size || !out) return; - - u8 tmp[0x6]; - - tmp[5] = (u8)(size >> 40); - tmp[4] = (u8)(size >> 32); - tmp[3] = (u8)(size >> 24); - tmp[2] = (u8)(size >> 16); - tmp[1] = (u8)(size >> 8); - tmp[0] = (u8)size; - - memcpy(out, tmp, 6); -} - -bool loadNcaKeyset() -{ - // Check if the keyset has been already loaded - if (nca_keyset.total_key_cnt > 0) return true; - - if (!(envIsSyscallHinted(0x60) && // svcDebugActiveProcess - envIsSyscallHinted(0x63) && // svcGetDebugEvent - envIsSyscallHinted(0x65) && // svcGetProcessList - envIsSyscallHinted(0x69) && // svcQueryDebugProcessMemory - envIsSyscallHinted(0x6a))) // svcReadDebugProcessMemory - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: please run the application with debug svc permissions!", __func__); - return false; - } - - return loadMemoryKeys(); -} - -size_t aes128XtsNintendoCrypt(Aes128XtsContext *ctx, void *dst, const void *src, size_t size, u32 sector, bool encrypt) -{ - if (!ctx || !dst || !src || !size || (size % NCA_AES_XTS_SECTOR_SIZE) != 0) return 0; - - size_t i, crypt_res = 0, out = 0; - u32 cur_sector = sector; - - for(i = 0; i < size; i += NCA_AES_XTS_SECTOR_SIZE, cur_sector++) - { - // We have to force a sector reset on each new sector to actually enable Nintendo AES-XTS cipher tweak - aes128XtsContextResetSector(ctx, cur_sector, true); - - if (encrypt) - { - crypt_res = aes128XtsEncrypt(ctx, (u8*)dst + i, (const u8*)src + i, NCA_AES_XTS_SECTOR_SIZE); - } else { - crypt_res = aes128XtsDecrypt(ctx, (u8*)dst + i, (const u8*)src + i, NCA_AES_XTS_SECTOR_SIZE); - } - - if (crypt_res != NCA_AES_XTS_SECTOR_SIZE) break; - - out += crypt_res; - } - - return out; -} - -/* Updates the CTR for an offset. */ -static void nca_update_ctr(unsigned char *ctr, u64 ofs) -{ - ofs >>= 4; - unsigned int i; - - for(i = 0; i < 0x8; i++) - { - ctr[0x10 - i - 1] = (unsigned char)(ofs & 0xFF); - ofs >>= 8; - } -} - -/* Updates the CTR for a bktr offset. */ -static void nca_update_bktr_ctr(unsigned char *ctr, u32 ctr_val, u64 ofs) -{ - ofs >>= 4; - unsigned int i; - - for(i = 0; i < 0x8; i++) - { - ctr[0x10 - i - 1] = (unsigned char)(ofs & 0xFF); - ofs >>= 8; - } - - for(i = 0; i < 0x4; i++) - { - ctr[0x8 - i - 1] = (unsigned char)(ctr_val & 0xFF); - ctr_val >>= 8; - } -} - -bool readNcaDataByContentId(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, u64 offset, void *outBuf, size_t bufSize) -{ - if (!ncmStorage || !ncaId || !outBuf || !bufSize) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to read data from NCA!", __func__); - return false; - } - - Result result = 0; - bool success = false; - - char nca_id[SHA256_HASH_SIZE + 1] = {'\0'}, nca_path[0x301] = {'\0'}; - convertDataToHexString(ncaId->c, SHA256_HASH_SIZE / 2, nca_id, SHA256_HASH_SIZE + 1); - - result = ncmContentStorageGetPath(ncmStorage, nca_path, MAX_CHARACTERS(nca_path), ncaId); - if (R_FAILED(result) || !strlen(nca_path)) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to retrieve content path for NCA \"%s\"! (0x%08X)", __func__, nca_id, result); - return false; - } - - // Check if we're dealing with a gamecard NCA - if (!strncmp(nca_path, "@Gc", 3)) - { - // Retrieve NCA data using raw IStorage reads - // Fixes NCA access problems with gamecards under low HOS versions when using ncmContentStorageReadContentIdFile() - success = readFileFromSecureHfs0PartitionByName(strchr(nca_path, '/') + 1, offset, outBuf, bufSize); - if (!success) breaks++; - } else { - // Retrieve NCA data normally - // This strips NAX0 encryption from SD card NCAs (not used with eMMC NCAs) - result = ncmContentStorageReadContentIdFile(ncmStorage, outBuf, bufSize, ncaId, offset); - success = R_SUCCEEDED(result); - } - - if (!success) uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read %lu bytes block at offset 0x%016lX from NCA \"%s\"! (0x%08X)", __func__, bufSize, offset, nca_id, result); - - return success; -} - -bool processNcaCtrSectionBlock(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *ctx, u64 offset, void *outBuf, size_t bufSize, bool encrypt) -{ - if (!ncmStorage || !ncaId || !outBuf || !bufSize || !ctx) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to process %s NCA section block!", __func__, (encrypt ? "decrypted" : "encrypted")); - return false; - } - - if (!loadNcaKeyset()) return false; - - unsigned char ctr[0x10]; - - char nca_id[SHA256_HASH_SIZE + 1] = {'\0'}; - convertDataToHexString(ncaId->c, SHA256_HASH_SIZE / 2, nca_id, SHA256_HASH_SIZE + 1); - - u64 block_start_offset = (offset - (offset % 0x10)); - u64 block_end_offset = (u64)round_up(offset + bufSize, 0x10); - u64 block_size = (block_end_offset - block_start_offset); - - u64 block_size_used = (block_size > NCA_CTR_BUFFER_SIZE ? NCA_CTR_BUFFER_SIZE : block_size); - u64 output_block_size = (block_size > NCA_CTR_BUFFER_SIZE ? (NCA_CTR_BUFFER_SIZE - (offset - block_start_offset)) : bufSize); - - if (!readNcaDataByContentId(ncmStorage, ncaId, block_start_offset, ncaCtrBuf, block_size_used)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read encrypted data block from NCA \"%s\"!", __func__, nca_id); - return false; - } - - // Update CTR - memcpy(ctr, ctx->ctr, 0x10); - nca_update_ctr(ctr, block_start_offset); - aes128CtrContextResetCtr(ctx, ctr); - - // Decrypt CTR block - aes128CtrCrypt(ctx, ncaCtrBuf, ncaCtrBuf, block_size_used); - - if (encrypt) - { - // Copy data to be encrypted - memcpy(ncaCtrBuf + (offset - block_start_offset), outBuf, output_block_size); - - // Reset CTR - aes128CtrContextResetCtr(ctx, ctr); - - // Encrypt CTR block - aes128CtrCrypt(ctx, ncaCtrBuf, ncaCtrBuf, block_size_used); - } - - memcpy(outBuf, ncaCtrBuf + (offset - block_start_offset), output_block_size); - - if (block_size > NCA_CTR_BUFFER_SIZE) return processNcaCtrSectionBlock(ncmStorage, ncaId, ctx, offset + output_block_size, outBuf + output_block_size, bufSize - output_block_size, encrypt); - - return true; -} - -bktr_relocation_bucket_t *bktr_get_relocation_bucket(bktr_relocation_block_t *block, u32 i) -{ - return (bktr_relocation_bucket_t*)((u8*)block->buckets + ((sizeof(bktr_relocation_bucket_t) + sizeof(bktr_relocation_entry_t)) * (u64)i)); -} - -// Get a relocation entry from offset and relocation block -bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, u64 offset) -{ - // Weak check for invalid offset - if (offset > block->total_size) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: too big offset looked up in BKTR relocation table!", __func__); - return NULL; - } - - u32 i, bucket_num = 0; - - for(i = 1; i < block->num_buckets; i++) - { - if (block->bucket_virtual_offsets[i] <= offset) bucket_num++; - } - - bktr_relocation_bucket_t *bucket = bktr_get_relocation_bucket(block, bucket_num); - - // Check for edge case, short circuit - if (bucket->num_entries == 1) return &(bucket->entries[0]); - - // Binary search - u32 low = 0, high = (bucket->num_entries - 1); - - while(low <= high) - { - u32 mid = ((low + high) / 2); - - if (bucket->entries[mid].virt_offset > offset) - { - // Too high - high = (mid - 1); - } else { - // block->entries[mid].offset <= offset - - // Check for success - if (mid == (bucket->num_entries - 1) || bucket->entries[mid + 1].virt_offset > offset) return &(bucket->entries[mid]); - - low = (mid + 1); - } - } - - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to find offset 0x%016lX in BKTR relocation table!", __func__, offset); - return NULL; -} - -bktr_subsection_bucket_t *bktr_get_subsection_bucket(bktr_subsection_block_t *block, u32 i) -{ - return (bktr_subsection_bucket_t*)((u8*)block->buckets + ((sizeof(bktr_subsection_bucket_t) + sizeof(bktr_subsection_entry_t)) * (u64)i)); -} - -// Get a subsection entry from offset and subsection block -bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, u64 offset) -{ - // If offset is past the virtual, we're reading from the BKTR_HEADER subsection - bktr_subsection_bucket_t *last_bucket = bktr_get_subsection_bucket(block, block->num_buckets - 1); - if (offset >= last_bucket->entries[last_bucket->num_entries].offset) return &(last_bucket->entries[last_bucket->num_entries]); - - u32 i, bucket_num = 0; - - for(i = 1; i < block->num_buckets; i++) - { - if (block->bucket_physical_offsets[i] <= offset) bucket_num++; - } - - bktr_subsection_bucket_t *bucket = bktr_get_subsection_bucket(block, bucket_num); - - // Check for edge case, short circuit - if (bucket->num_entries == 1) return &(bucket->entries[0]); - - // Binary search - u32 low = 0, high = (bucket->num_entries - 1); - - while (low <= high) - { - u32 mid = ((low + high) / 2); - - if (bucket->entries[mid].offset > offset) - { - // Too high - high = (mid - 1); - } else { - // block->entries[mid].offset <= offset - - // Check for success - if (mid == (bucket->num_entries - 1) || bucket->entries[mid + 1].offset > offset) return &(bucket->entries[mid]); - - low = (mid + 1); - } - } - - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to find offset 0x%016lX in BKTR subsection table!", __func__, offset); - return NULL; -} - -bool bktrSectionSeek(u64 offset) -{ - if (!bktrContext.section_offset || !bktrContext.section_size || !bktrContext.relocation_block || !bktrContext.subsection_block) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to seek within NCA BKTR section!", __func__); - return false; - } - - bktr_relocation_entry_t *reloc = bktr_get_relocation(bktrContext.relocation_block, offset); - if (!reloc) return false; - - // No better way to do this than to make all BKTR seeking virtual - bktrContext.virtual_seek = offset; - - u64 section_ofs = (offset - reloc->virt_offset + reloc->phys_offset); - - if (reloc->is_patch) - { - // Seeked within the patch RomFS - bktrContext.bktr_seek = section_ofs; - bktrContext.base_seek = 0; - } else { - // Seeked within the base RomFS - bktrContext.bktr_seek = 0; - bktrContext.base_seek = section_ofs; - } - - return true; -} - -bool bktrSectionPhysicalRead(void *outBuf, size_t bufSize) -{ - if (!bktrContext.section_offset || !bktrContext.section_size || !bktrContext.relocation_block || !bktrContext.subsection_block || !outBuf || !bufSize) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to perform physical block read from NCA BKTR section!", __func__); - return false; - } - - unsigned char ctr[0x10]; - - bktr_subsection_entry_t *subsec = bktr_get_subsection(bktrContext.subsection_block, bktrContext.bktr_seek); - if (!subsec) return false; - - bktr_subsection_entry_t *next_subsec = (subsec + 1); - - u64 base_offset = (bktrContext.section_offset + bktrContext.bktr_seek); - - u64 virt_seek = bktrContext.virtual_seek; - - if ((bktrContext.bktr_seek + bufSize) <= next_subsec->offset) - { - // Easy path, reading *only* within the subsection - u64 block_start_offset = (base_offset - (base_offset % 0x10)); - u64 block_end_offset = (u64)round_up(base_offset + bufSize, 0x10); - u64 block_size = (block_end_offset - block_start_offset); - - u64 output_offset = 0; - u64 ctr_buf_offset = (base_offset - block_start_offset); - u64 output_block_size = (block_size > NCA_CTR_BUFFER_SIZE ? (NCA_CTR_BUFFER_SIZE - (base_offset - block_start_offset)) : bufSize); - - while(block_size > 0) - { - u64 block_size_used = (block_size > NCA_CTR_BUFFER_SIZE ? NCA_CTR_BUFFER_SIZE : block_size); - - if (!readNcaDataByContentId(&(bktrContext.ncmStorage), &(bktrContext.ncaId), block_start_offset, ncaCtrBuf, block_size_used)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read encrypted %lu bytes block at offset 0x%016lX!", __func__, block_size_used, block_start_offset); - return false; - } - - // Update BKTR CTR - memcpy(ctr, bktrContext.aes_ctx.ctr, 0x10); - nca_update_bktr_ctr(ctr, subsec->ctr_val, block_start_offset); - aes128CtrContextResetCtr(&(bktrContext.aes_ctx), ctr); - - // Decrypt CTR block - aes128CtrCrypt(&(bktrContext.aes_ctx), ncaCtrBuf, ncaCtrBuf, block_size_used); - memcpy(outBuf + output_offset, ncaCtrBuf + ctr_buf_offset, output_block_size); - - block_start_offset += block_size_used; - block_size -= block_size_used; - - if (block_size) - { - output_offset += output_block_size; - ctr_buf_offset = 0; - output_block_size = (block_size > NCA_CTR_BUFFER_SIZE ? NCA_CTR_BUFFER_SIZE : ((base_offset + bufSize) - block_start_offset)); - } - } - } else { - // Sad path - u64 within_subsection = (next_subsec->offset - bktrContext.bktr_seek); - - if (!readBktrSectionBlock(virt_seek, outBuf, within_subsection)) return false; - - if (!readBktrSectionBlock(virt_seek + within_subsection, (u8*)outBuf + within_subsection, bufSize - within_subsection)) return false; - } - - return true; -} - -bool readBktrSectionBlock(u64 offset, void *outBuf, size_t bufSize) -{ - if (!bktrContext.section_offset || !bktrContext.section_size || !bktrContext.relocation_block || !bktrContext.subsection_block || (bktrContext.use_base_romfs && (!romFsContext.section_offset || !romFsContext.section_size)) || !outBuf || !bufSize) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to read block from NCA BKTR section!", __func__); - return false; - } - - if (!loadNcaKeyset()) return false; - - if (!bktrSectionSeek(offset)) return false; - - bktr_relocation_entry_t *reloc = bktr_get_relocation(bktrContext.relocation_block, bktrContext.virtual_seek); - if (!reloc) return false; - - bktr_relocation_entry_t *next_reloc = (reloc + 1); - - u64 virt_seek = bktrContext.virtual_seek; - - // Perform read operation - if ((bktrContext.virtual_seek + bufSize) <= next_reloc->virt_offset) - { - // Easy path: We're reading *only* within the current relocation - - if (reloc->is_patch) - { - if (!bktrSectionPhysicalRead(outBuf, bufSize)) return false; - } else { - if (!bktrContext.use_base_romfs) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: BKTR references non-existent base RomFS section!", __func__); - return false; - } - - // Nice and easy read from the base RomFS - if (!processNcaCtrSectionBlock(&(romFsContext.ncmStorage), &(romFsContext.ncaId), &(romFsContext.aes_ctx), romFsContext.section_offset + bktrContext.base_seek, outBuf, bufSize, false)) return false; - } - } else { - u64 within_relocation = (next_reloc->virt_offset - bktrContext.virtual_seek); - - if (!readBktrSectionBlock(virt_seek, outBuf, within_relocation)) return false; - - if (!readBktrSectionBlock(virt_seek + within_relocation, (u8*)outBuf + within_relocation, bufSize - within_relocation)) return false; - } - - return true; -} - bool encryptNcaHeader(nca_header_t *input, u8 *outBuf, u64 outBufSize) { if (!input || !outBuf || !outBufSize || outBufSize < NCA_FULL_HEADER_LENGTH || (__builtin_bswap32(input->magic) != NCA3_MAGIC && __builtin_bswap32(input->magic) != NCA2_MAGIC)) @@ -1553,595 +932,6 @@ bool patchCnmtNca(u8 *ncaBuf, u64 ncaBufSize, cnmt_xml_program_info *xml_program return true; } -bool parseExeFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys) -{ - if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to read RomFS section from NCA!", __func__); - return false; - } - - u8 exefs_index; - bool found_exefs = false; - - u32 i; - - u64 section_offset; - u64 section_size; - - unsigned char ctr[0x10]; - memset(ctr, 0, 0x10); - - u64 ofs; - - u8 ctr_key[NCA_KEY_AREA_KEY_SIZE]; - memcpy(ctr_key, decrypted_nca_keys + (NCA_KEY_AREA_KEY_SIZE * 2), NCA_KEY_AREA_KEY_SIZE); - - Aes128CtrContext aes_ctx; - aes128CtrContextCreate(&aes_ctx, ctr_key, ctr); - - u64 nca_pfs0_offset; - pfs0_header nca_pfs0_header; - - u64 nca_pfs0_entries_offset; - pfs0_file_entry *nca_pfs0_entries = NULL; - - u64 nca_pfs0_str_table_offset; - char *nca_pfs0_str_table = NULL; - - u64 nca_pfs0_data_offset; - - initExeFsContext(); - - for(exefs_index = 0; exefs_index < 4; exefs_index++) - { - if (dec_nca_header->fs_headers[exefs_index].partition_type != NCA_FS_HEADER_PARTITION_PFS0 || dec_nca_header->fs_headers[exefs_index].fs_type != NCA_FS_HEADER_FSTYPE_PFS0 || !dec_nca_header->fs_headers[exefs_index].pfs0_superblock.pfs0_size || dec_nca_header->fs_headers[exefs_index].crypt_type != NCA_FS_HEADER_CRYPT_CTR) continue; - - section_offset = ((u64)dec_nca_header->section_entries[exefs_index].media_start_offset * (u64)MEDIA_UNIT_SIZE); - section_size = (((u64)dec_nca_header->section_entries[exefs_index].media_end_offset * (u64)MEDIA_UNIT_SIZE) - section_offset); - - if (!section_offset || section_offset < NCA_FULL_HEADER_LENGTH || !section_size) continue; - - // Generate initial CTR - ofs = (section_offset >> 4); - - for(i = 0; i < 0x8; i++) - { - ctr[i] = dec_nca_header->fs_headers[exefs_index].section_ctr[0x08 - i - 1]; - ctr[0x10 - i - 1] = (unsigned char)(ofs & 0xFF); - ofs >>= 8; - } - - aes128CtrContextResetCtr(&aes_ctx, ctr); - - nca_pfs0_offset = (section_offset + dec_nca_header->fs_headers[exefs_index].pfs0_superblock.pfs0_offset); - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_offset, &nca_pfs0_header, sizeof(pfs0_header), false)) return false; - - if (__builtin_bswap32(nca_pfs0_header.magic) != PFS0_MAGIC || !nca_pfs0_header.file_cnt || !nca_pfs0_header.str_table_size) continue; - - nca_pfs0_entries_offset = (nca_pfs0_offset + sizeof(pfs0_header)); - - nca_pfs0_entries = calloc(nca_pfs0_header.file_cnt, sizeof(pfs0_file_entry)); - if (!nca_pfs0_entries) continue; - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_entries_offset, nca_pfs0_entries, (u64)nca_pfs0_header.file_cnt * sizeof(pfs0_file_entry), false)) - { - free(nca_pfs0_entries); - return false; - } - - nca_pfs0_str_table_offset = (nca_pfs0_entries_offset + ((u64)nca_pfs0_header.file_cnt * sizeof(pfs0_file_entry))); - - nca_pfs0_str_table = calloc(nca_pfs0_header.str_table_size, sizeof(char)); - if (!nca_pfs0_str_table) - { - free(nca_pfs0_entries); - nca_pfs0_entries = NULL; - continue; - } - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, nca_pfs0_str_table_offset, nca_pfs0_str_table, (u64)nca_pfs0_header.str_table_size, false)) - { - free(nca_pfs0_str_table); - free(nca_pfs0_entries); - return false; - } - - for(i = 0; i < nca_pfs0_header.file_cnt; i++) - { - char *cur_filename = (nca_pfs0_str_table + nca_pfs0_entries[i].filename_offset); - - if (!strncasecmp(cur_filename, "main.npdm", 9)) - { - found_exefs = true; - break; - } - } - - if (found_exefs) break; - - free(nca_pfs0_str_table); - nca_pfs0_str_table = NULL; - - free(nca_pfs0_entries); - nca_pfs0_entries = NULL; - } - - if (!found_exefs) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: NCA doesn't hold an ExeFS section! Wrong keys?\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__); - return false; - } - - nca_pfs0_data_offset = (nca_pfs0_str_table_offset + (u64)nca_pfs0_header.str_table_size); - - // Save data to output struct - // The caller function must free these data pointers - memcpy(&(exeFsContext.ncmStorage), ncmStorage, sizeof(NcmContentStorage)); - memcpy(&(exeFsContext.ncaId), ncaId, sizeof(NcmContentId)); - memcpy(&(exeFsContext.aes_ctx), &aes_ctx, sizeof(Aes128CtrContext)); - exeFsContext.exefs_offset = nca_pfs0_offset; - exeFsContext.exefs_size = dec_nca_header->fs_headers[exefs_index].pfs0_superblock.pfs0_size; - memcpy(&(exeFsContext.exefs_header), &nca_pfs0_header, sizeof(pfs0_header)); - exeFsContext.exefs_entries_offset = nca_pfs0_entries_offset; - exeFsContext.exefs_entries = nca_pfs0_entries; - exeFsContext.exefs_str_table_offset = nca_pfs0_str_table_offset; - exeFsContext.exefs_str_table = nca_pfs0_str_table; - exeFsContext.exefs_data_offset = nca_pfs0_data_offset; - - return true; -} - -int parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys) -{ - if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to read RomFS section from NCA!", __func__); - return -1; - } - - u8 romfs_index; - bool found_romfs = false; - - u32 i; - - u64 section_offset; - u64 section_size; - - Aes128CtrContext aes_ctx; - - u64 romfs_offset; - u64 romfs_size; - romfs_header romFsHeader; - - u64 romfs_dirtable_offset; - u64 romfs_dirtable_size; - - u64 romfs_filetable_offset; - u64 romfs_filetable_size; - - u64 romfs_filedata_offset; - - romfs_dir *romfs_dir_entries = NULL; - romfs_file *romfs_file_entries = NULL; - - initRomFsContext(); - - for(romfs_index = 0; romfs_index < 4; romfs_index++) - { - if (dec_nca_header->fs_headers[romfs_index].partition_type == NCA_FS_HEADER_PARTITION_ROMFS && dec_nca_header->fs_headers[romfs_index].fs_type == NCA_FS_HEADER_FSTYPE_ROMFS) - { - found_romfs = true; - break; - } - } - - if (!found_romfs) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: NCA doesn't hold a RomFS section!", __func__); - return -2; - } - - section_offset = ((u64)dec_nca_header->section_entries[romfs_index].media_start_offset * (u64)MEDIA_UNIT_SIZE); - section_size = (((u64)dec_nca_header->section_entries[romfs_index].media_end_offset * (u64)MEDIA_UNIT_SIZE) - section_offset); - - if (!section_offset || section_offset < NCA_FULL_HEADER_LENGTH || !section_size) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid offset/size for NCA RomFS section! (#%u)", __func__, romfs_index); - return -1; - } - - // Generate initial CTR - unsigned char ctr[0x10]; - u64 ofs = (section_offset >> 4); - - for(i = 0; i < 0x8; i++) - { - ctr[i] = dec_nca_header->fs_headers[romfs_index].section_ctr[0x08 - i - 1]; - ctr[0x10 - i - 1] = (unsigned char)(ofs & 0xFF); - ofs >>= 8; - } - - u8 ctr_key[NCA_KEY_AREA_KEY_SIZE]; - memcpy(ctr_key, decrypted_nca_keys + (NCA_KEY_AREA_KEY_SIZE * 2), NCA_KEY_AREA_KEY_SIZE); - aes128CtrContextCreate(&aes_ctx, ctr_key, ctr); - - if (__builtin_bswap32(dec_nca_header->fs_headers[romfs_index].romfs_superblock.ivfc_header.magic) != IVFC_MAGIC) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid IVFC magic word for NCA RomFS section! Wrong KAEK? (0x%08X)\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__, __builtin_bswap32(dec_nca_header->fs_headers[romfs_index].romfs_superblock.ivfc_header.magic)); - return -1; - } - - if (dec_nca_header->fs_headers[romfs_index].crypt_type != NCA_FS_HEADER_CRYPT_CTR) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid AES crypt type for NCA RomFS section! (0x%02X)", __func__, dec_nca_header->fs_headers[romfs_index].crypt_type); - return -1; - } - - romfs_offset = (section_offset + dec_nca_header->fs_headers[romfs_index].romfs_superblock.ivfc_header.level_headers[IVFC_MAX_LEVEL - 1].logical_offset); - romfs_size = dec_nca_header->fs_headers[romfs_index].romfs_superblock.ivfc_header.level_headers[IVFC_MAX_LEVEL - 1].hash_data_size; - - if (romfs_offset < section_offset || romfs_offset >= (section_offset + section_size) || romfs_size < ROMFS_HEADER_SIZE || (romfs_offset + romfs_size) > (section_offset + section_size)) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid offset/size for NCA RomFS section!", __func__); - return -1; - } - - // First read the RomFS header - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, romfs_offset, &romFsHeader, sizeof(romfs_header), false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA RomFS section header!", __func__); - return -1; - } - - if (romFsHeader.headerSize != ROMFS_HEADER_SIZE) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid header size for NCA RomFS section! (0x%016lX at 0x%016lX)", __func__, romFsHeader.headerSize, romfs_offset); - return -1; - } - - romfs_dirtable_offset = (romfs_offset + romFsHeader.dirTableOff); - romfs_dirtable_size = romFsHeader.dirTableSize; - - romfs_filetable_offset = (romfs_offset + romFsHeader.fileTableOff); - romfs_filetable_size = romFsHeader.fileTableSize; - - if (romfs_dirtable_offset >= (section_offset + section_size) || !romfs_dirtable_size || (romfs_dirtable_offset + romfs_dirtable_size) > (section_offset + section_size) || romfs_filetable_offset >= (section_offset + section_size) || !romfs_filetable_size || (romfs_filetable_offset + romfs_filetable_size) > (section_offset + section_size)) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid directory/file table for NCA RomFS section!", __func__); - return -1; - } - - romfs_filedata_offset = (romfs_offset + romFsHeader.fileDataOff); - - if (romfs_filedata_offset >= (section_offset + section_size)) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid file data block offset for NCA RomFS section!", __func__); - return -1; - } - - romfs_dir_entries = calloc(1, romfs_dirtable_size); - if (!romfs_dir_entries) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for NCA RomFS section directory entries!", __func__); - return -1; - } - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, romfs_dirtable_offset, romfs_dir_entries, romfs_dirtable_size, false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA RomFS section directory entries!", __func__); - free(romfs_dir_entries); - return -1; - } - - romfs_file_entries = calloc(1, romfs_filetable_size); - if (!romfs_file_entries) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for NCA RomFS section file entries!", __func__); - free(romfs_dir_entries); - return -1; - } - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, romfs_filetable_offset, romfs_file_entries, romfs_filetable_size, false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA RomFS section file entries!", __func__); - free(romfs_file_entries); - free(romfs_dir_entries); - return -1; - } - - // Save data to output struct - // The caller function must free these data pointers - memcpy(&(romFsContext.ncmStorage), ncmStorage, sizeof(NcmContentStorage)); - memcpy(&(romFsContext.ncaId), ncaId, sizeof(NcmContentId)); - memcpy(&(romFsContext.aes_ctx), &aes_ctx, sizeof(Aes128CtrContext)); - romFsContext.section_offset = section_offset; - romFsContext.section_size = section_size; - romFsContext.romfs_offset = romfs_offset; - romFsContext.romfs_size = romfs_size; - romFsContext.romfs_dirtable_offset = romfs_dirtable_offset; - romFsContext.romfs_dirtable_size = romfs_dirtable_size; - romFsContext.romfs_dir_entries = romfs_dir_entries; - romFsContext.romfs_filetable_offset = romfs_filetable_offset; - romFsContext.romfs_filetable_size = romfs_filetable_size; - romFsContext.romfs_file_entries = romfs_file_entries; - romFsContext.romfs_filedata_offset = romfs_filedata_offset; - - return 0; -} - -bool parseBktrEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys) -{ - if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys || (bktrContext.use_base_romfs && (!romFsContext.section_offset || !romFsContext.section_size || !romFsContext.romfs_dir_entries || !romFsContext.romfs_file_entries))) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to read BKTR section from NCA!", __func__); - return false; - } - - u32 i; - - u8 bktr_index; - bool found_bktr = false, success = false; - - romfs_header romFsHeader; - - initBktrContext(); - - memcpy(&(bktrContext.ncmStorage), ncmStorage, sizeof(NcmContentStorage)); - memcpy(&(bktrContext.ncaId), ncaId, sizeof(NcmContentId)); - - for(bktr_index = 0; bktr_index < 4; bktr_index++) - { - if (dec_nca_header->fs_headers[bktr_index].partition_type == NCA_FS_HEADER_PARTITION_ROMFS && dec_nca_header->fs_headers[bktr_index].fs_type == NCA_FS_HEADER_FSTYPE_ROMFS) - { - found_bktr = true; - break; - } - } - - if (!found_bktr) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: NCA doesn't hold a BKTR section!", __func__); - return false; - } - - bktrContext.section_offset = ((u64)dec_nca_header->section_entries[bktr_index].media_start_offset * (u64)MEDIA_UNIT_SIZE); - bktrContext.section_size = (((u64)dec_nca_header->section_entries[bktr_index].media_end_offset * (u64)MEDIA_UNIT_SIZE) - bktrContext.section_offset); - - if (!bktrContext.section_offset || bktrContext.section_offset < NCA_FULL_HEADER_LENGTH || !bktrContext.section_size) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid offset/size for NCA BKTR section! (#%u)", __func__, bktr_index); - return false; - } - - // Generate initial CTR - unsigned char ctr[0x10]; - u64 ofs = (bktrContext.section_offset >> 4); - - for(i = 0; i < 0x8; i++) - { - ctr[i] = dec_nca_header->fs_headers[bktr_index].section_ctr[0x08 - i - 1]; - ctr[0x10 - i - 1] = (unsigned char)(ofs & 0xFF); - ofs >>= 8; - } - - u8 ctr_key[NCA_KEY_AREA_KEY_SIZE]; - memcpy(ctr_key, decrypted_nca_keys + (NCA_KEY_AREA_KEY_SIZE * 2), NCA_KEY_AREA_KEY_SIZE); - aes128CtrContextCreate(&(bktrContext.aes_ctx), ctr_key, ctr); - - memcpy(&(bktrContext.superblock), &(dec_nca_header->fs_headers[bktr_index].bktr_superblock), sizeof(bktr_superblock_t)); - - if (__builtin_bswap32(bktrContext.superblock.ivfc_header.magic) != IVFC_MAGIC) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid IVFC magic word for NCA BKTR section! Wrong KAEK? (0x%08X)\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__, __builtin_bswap32(bktrContext.superblock.ivfc_header.magic)); - return false; - } - - if (dec_nca_header->fs_headers[bktr_index].crypt_type != NCA_FS_HEADER_CRYPT_BKTR) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid AES crypt type for NCA BKTR section! (0x%02X)", __func__, dec_nca_header->fs_headers[bktr_index].crypt_type); - return false; - } - - if (__builtin_bswap32(bktrContext.superblock.relocation_header.magic) != BKTR_MAGIC || __builtin_bswap32(bktrContext.superblock.subsection_header.magic) != BKTR_MAGIC) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid BKTR magic word for NCA BKTR relocation/subsection header! Wrong KAEK? (0x%02X | 0x%02X)\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__, __builtin_bswap32(bktrContext.superblock.relocation_header.magic), __builtin_bswap32(bktrContext.superblock.subsection_header.magic)); - return false; - } - - if ((bktrContext.superblock.relocation_header.offset + bktrContext.superblock.relocation_header.size) != bktrContext.superblock.subsection_header.offset || (bktrContext.superblock.subsection_header.offset + bktrContext.superblock.subsection_header.size) != bktrContext.section_size) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid layout for NCA BKTR section!", __func__); - return false; - } - - // Allocate space for an extra (fake) relocation entry, to simplify our logic - bktrContext.relocation_block = calloc(1, bktrContext.superblock.relocation_header.size + ((0x3FF0 / sizeof(u64)) * sizeof(bktr_relocation_entry_t))); - if (!bktrContext.relocation_block) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for NCA BKTR relocation header!", __func__); - return false; - } - - // Allocate space for an extra (fake) subsection entry, to simplify our logic - bktrContext.subsection_block = calloc(1, bktrContext.superblock.subsection_header.size + ((0x3FF0 / sizeof(u64)) * sizeof(bktr_subsection_entry_t)) + sizeof(bktr_subsection_entry_t)); - if (!bktrContext.subsection_block) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for NCA BKTR subsection header!", __func__); - goto out; - } - - // Read the relocation header - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &(bktrContext.aes_ctx), bktrContext.section_offset + bktrContext.superblock.relocation_header.offset, bktrContext.relocation_block, bktrContext.superblock.relocation_header.size, false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA BKTR relocation header!", __func__); - goto out; - } - - // Read the subsection header - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &(bktrContext.aes_ctx), bktrContext.section_offset + bktrContext.superblock.subsection_header.offset, bktrContext.subsection_block, bktrContext.superblock.subsection_header.size, false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA BKTR subsection header!", __func__); - goto out; - } - - if (bktrContext.subsection_block->total_size != bktrContext.superblock.subsection_header.offset) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid NCA BKTR subsection header size!", __func__); - goto out; - } - - // This simplifies logic greatly... - for(i = (bktrContext.relocation_block->num_buckets - 1); i > 0; i--) - { - bktr_relocation_bucket_t tmp_bucket; - memcpy(&tmp_bucket, &(bktrContext.relocation_block->buckets[i]), sizeof(bktr_relocation_bucket_t)); - memcpy(bktr_get_relocation_bucket(bktrContext.relocation_block, i), &tmp_bucket, sizeof(bktr_relocation_bucket_t)); - } - - for(i = 0; (i + 1) < bktrContext.relocation_block->num_buckets; i++) - { - bktr_relocation_bucket_t *cur_bucket = bktr_get_relocation_bucket(bktrContext.relocation_block, i); - cur_bucket->entries[cur_bucket->num_entries].virt_offset = bktrContext.relocation_block->bucket_virtual_offsets[i + 1]; - } - - for(i = (bktrContext.subsection_block->num_buckets - 1); i > 0; i--) - { - bktr_subsection_bucket_t tmp_bucket; - memcpy(&tmp_bucket, &(bktrContext.subsection_block->buckets[i]), sizeof(bktr_subsection_bucket_t)); - memcpy(bktr_get_subsection_bucket(bktrContext.subsection_block, i), &tmp_bucket, sizeof(bktr_subsection_bucket_t)); - } - - for(i = 0; (i + 1) < bktrContext.subsection_block->num_buckets; i++) - { - bktr_subsection_bucket_t *cur_bucket = bktr_get_subsection_bucket(bktrContext.subsection_block, i); - bktr_subsection_bucket_t *next_bucket = bktr_get_subsection_bucket(bktrContext.subsection_block, i + 1); - cur_bucket->entries[cur_bucket->num_entries].offset = next_bucket->entries[0].offset; - cur_bucket->entries[cur_bucket->num_entries].ctr_val = next_bucket->entries[0].ctr_val; - } - - bktr_relocation_bucket_t *last_reloc_bucket = bktr_get_relocation_bucket(bktrContext.relocation_block, bktrContext.relocation_block->num_buckets - 1); - bktr_subsection_bucket_t *last_subsec_bucket = bktr_get_subsection_bucket(bktrContext.subsection_block, bktrContext.subsection_block->num_buckets - 1); - last_reloc_bucket->entries[last_reloc_bucket->num_entries].virt_offset = bktrContext.relocation_block->total_size; - last_subsec_bucket->entries[last_subsec_bucket->num_entries].offset = bktrContext.superblock.relocation_header.offset; - last_subsec_bucket->entries[last_subsec_bucket->num_entries].ctr_val = dec_nca_header->fs_headers[bktr_index].section_ctr_low; - last_subsec_bucket->entries[last_subsec_bucket->num_entries + 1].offset = bktrContext.section_size; - last_subsec_bucket->entries[last_subsec_bucket->num_entries + 1].ctr_val = 0; - - // Parse RomFS section - bktrContext.romfs_offset = dec_nca_header->fs_headers[bktr_index].bktr_superblock.ivfc_header.level_headers[IVFC_MAX_LEVEL - 1].logical_offset; - bktrContext.romfs_size = dec_nca_header->fs_headers[bktr_index].bktr_superblock.ivfc_header.level_headers[IVFC_MAX_LEVEL - 1].hash_data_size; - - // Do not check the RomFS offset/size, because it reflects the full patched RomFS image - if (!bktrContext.romfs_offset || bktrContext.romfs_size < ROMFS_HEADER_SIZE) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid offset/size for NCA BKTR RomFS section!", __func__); - goto out; - } - - if (!readBktrSectionBlock(bktrContext.romfs_offset, &romFsHeader, sizeof(romfs_header))) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA BKTR RomFS section header!", __func__); - goto out; - } - - if (romFsHeader.headerSize != ROMFS_HEADER_SIZE) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid header size for NCA BKTR RomFS section! (0x%016lX at 0x%016lX)", __func__, romFsHeader.headerSize, bktrContext.section_offset + bktrContext.romfs_offset); - goto out; - } - - bktrContext.romfs_dirtable_offset = (bktrContext.romfs_offset + romFsHeader.dirTableOff); - bktrContext.romfs_dirtable_size = romFsHeader.dirTableSize; - - bktrContext.romfs_filetable_offset = (bktrContext.romfs_offset + romFsHeader.fileTableOff); - bktrContext.romfs_filetable_size = romFsHeader.fileTableSize; - - // Then again, do not check these offsets/sizes, because they reflect the patched RomFS image - if (!bktrContext.romfs_dirtable_offset || !bktrContext.romfs_dirtable_size || !bktrContext.romfs_filetable_offset || !bktrContext.romfs_filetable_size) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid directory/file table for NCA BKTR RomFS section!", __func__); - goto out; - } - - bktrContext.romfs_filedata_offset = (bktrContext.romfs_offset + romFsHeader.fileDataOff); - - if (!bktrContext.romfs_filedata_offset) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid file data block offset for NCA BKTR RomFS section!", __func__); - goto out; - } - - bktrContext.romfs_dir_entries = calloc(1, bktrContext.romfs_dirtable_size); - if (!bktrContext.romfs_dir_entries) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for NCA BKTR RomFS section directory entries!", __func__); - goto out; - } - - if (!readBktrSectionBlock(bktrContext.romfs_dirtable_offset, bktrContext.romfs_dir_entries, bktrContext.romfs_dirtable_size)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA BKTR RomFS section directory entries!", __func__); - goto out; - } - - bktrContext.romfs_file_entries = calloc(1, bktrContext.romfs_filetable_size); - if (!bktrContext.romfs_file_entries) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for NCA BKTR RomFS section file entries!", __func__); - goto out; - } - - if (!readBktrSectionBlock(bktrContext.romfs_filetable_offset, bktrContext.romfs_file_entries, bktrContext.romfs_filetable_size)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read NCA RomFS section file entries!", __func__); - goto out; - } - - success = true; - -out: - if (!success) - { - if (bktrContext.romfs_file_entries != NULL) - { - free(bktrContext.romfs_file_entries); - bktrContext.romfs_file_entries = NULL; - } - - if (bktrContext.romfs_dir_entries != NULL) - { - free(bktrContext.romfs_dir_entries); - bktrContext.romfs_dir_entries = NULL; - } - - if (bktrContext.subsection_block != NULL) - { - free(bktrContext.subsection_block); - bktrContext.subsection_block = NULL; - } - - if (bktrContext.relocation_block != NULL) - { - free(bktrContext.relocation_block); - bktrContext.relocation_block = NULL; - } - } - - // The caller function must free the data pointers from the bktrContext struct - - return success; -} - bool generateProgramInfoXml(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, bool useCustomAcidRsaPubKey, char **outBuf, u64 *outBufSize) { if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys || !outBuf || !outBufSize) @@ -2470,1009 +1260,3 @@ out: return success; } - -char *getNacpLangName(Language val) -{ - char *out = NULL; - - switch(val) - { - case Language_AmericanEnglish: - out = "AmericanEnglish"; - break; - case Language_BritishEnglish: - out = "BritishEnglish"; - break; - case Language_Japanese: - out = "Japanese"; - break; - case Language_French: - out = "French"; - break; - case Language_German: - out = "German"; - break; - case Language_LatinAmericanSpanish: - out = "LatinAmericanSpanish"; - break; - case Language_Spanish: - out = "Spanish"; - break; - case Language_Italian: - out = "Italian"; - break; - case Language_Dutch: - out = "Dutch"; - break; - case Language_CanadianFrench: - out = "CanadianFrench"; - break; - case Language_Portuguese: - out = "Portuguese"; - break; - case Language_Russian: - out = "Russian"; - break; - case Language_Korean: - out = "Korean"; - break; - case Language_TraditionalChinese: - out = "TraditionalChinese"; - break; - case Language_SimplifiedChinese: - out = "SimplifiedChinese"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpStartupUserAccount(u8 val) -{ - char *out = NULL; - - switch(val) - { - case StartupUserAccount_None: - out = "None"; - break; - case StartupUserAccount_Required: - out = "Required"; - break; - case StartupUserAccount_RequiredWithNetworkServiceAccountAvailable: - out = "RequiredWithNetworkServiceAccountAvailable"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpUserAccountSwitchLock(u8 val) -{ - char *out = NULL; - - switch(val) - { - case UserAccountSwitchLock_Disable: - out = "Disable"; - break; - case UserAccountSwitchLock_Enable: - out = "Enable"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpSupportedLanguageFlag(SupportedLanguageFlag *data, u8 idx) -{ - if (!data || idx >= 0x10) return NULL; - - u32 flag; - memcpy(&flag, data, sizeof(u32)); - flag = ((flag >> idx) & 0x1); - - return (flag ? getNacpLangName((Language)flag) : NULL); -} - -char *getNacpScreenshot(u8 val) -{ - char *out = NULL; - - switch(val) - { - case Screenshot_Allow: - out = "Allow"; - break; - case Screenshot_Deny: - out = "Deny"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpVideoCapture(u8 val) -{ - char *out = NULL; - - switch(val) - { - case VideoCapture_Disable: - out = "Disable"; - break; - case VideoCapture_Manual: - out = "Manual"; - break; - case VideoCapture_Enable: - out = "Enable"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpRatingAgeOrganization(RatingAgeOrganization val) -{ - char *out = NULL; - - switch(val) - { - case RatingAgeOrganization_CERO: - out = "CERO"; - break; - case RatingAgeOrganization_GRACGCRB: - out = "GRACGCRB"; - break; - case RatingAgeOrganization_GSRMR: - out = "GSRMR"; - break; - case RatingAgeOrganization_ESRB: - out = "ESRB"; - break; - case RatingAgeOrganization_ClassInd: - out = "ClassInd"; - break; - case RatingAgeOrganization_USK: - out = "USK"; - break; - case RatingAgeOrganization_PEGI: - out = "PEGI"; - break; - case RatingAgeOrganization_PEGIPortugal: - out = "PEGIPortugal"; - break; - case RatingAgeOrganization_PEGIBBFC: - out = "PEGIBBFC"; - break; - case RatingAgeOrganization_Russian: - out = "Russian"; - break; - case RatingAgeOrganization_ACB: - out = "ACB"; - break; - case RatingAgeOrganization_OFLC: - out = "OFLC"; - break; - case RatingAgeOrganization_IARCGeneric: - out = "IARCGeneric"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpDataLossConfirmation(u8 val) -{ - char *out = NULL; - - switch(val) - { - case DataLossConfirmation_None: - out = "None"; - break; - case DataLossConfirmation_Required: - out = "Required"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpPlayLogPolicy(u8 val) -{ - char *out = NULL; - - switch(val) - { - case PlayLogPolicy_All: - out = "All"; - break; - case PlayLogPolicy_LogOnly: - out = "LogOnly"; - break; - case PlayLogPolicy_None: - out = "None"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpLogoType(u8 val) -{ - char *out = NULL; - - switch(val) - { - case LogoType_LicensedByNintendo: - out = "LicensedByNintendo"; - break; - case LogoType_DistributedByNintendo: - out = "DistributedByNintendo"; - break; - case LogoType_Nintendo: - out = "Nintendo"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpLogoHandling(u8 val) -{ - char *out = NULL; - - switch(val) - { - case LogoHandling_Auto: - out = "Auto"; - break; - case LogoHandling_Manual: - out = "Manual"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpAddOnContentRegistrationType(u8 val) -{ - char *out = NULL; - - switch(val) - { - case AddOnContentRegistrationType_AllOnLaunch: - out = "AllOnLaunch"; - break; - case AddOnContentRegistrationType_OnDemand: - out = "OnDemand"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpHdcp(u8 val) -{ - char *out = NULL; - - switch(val) - { - case Hdcp_None: - out = "None"; - break; - case Hdcp_Required: - out = "Required"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpCrashReport(u8 val) -{ - char *out = NULL; - - switch(val) - { - case CrashReport_Deny: - out = "Deny"; - break; - case CrashReport_Allow: - out = "Allow"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpRuntimeAddOnContentInstall(u8 val) -{ - char *out = NULL; - - switch(val) - { - case RuntimeAddOnContentInstall_Deny: - out = "Deny"; - break; - case RuntimeAddOnContentInstall_AllowAppend: - out = "AllowAppend"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpRuntimeParameterDelivery(u8 val) -{ - char *out = NULL; - - switch(val) - { - case RuntimeParameterDelivery_Always: - out = "Always"; - break; - case RuntimeParameterDelivery_AlwaysIfUserStateMatched: - out = "AlwaysIfUserStateMatched"; - break; - case RuntimeParameterDelivery_OnRestart: - out = "OnRestart"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpPlayLogQueryCapability(u8 val) -{ - char *out = NULL; - - switch(val) - { - case PlayLogQueryCapability_None: - out = "None"; - break; - case PlayLogQueryCapability_WhiteList: - out = "WhiteList"; - break; - case PlayLogQueryCapability_All: - out = "All"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -char *getNacpJitConfigurationFlag(u64 val) -{ - char *out = NULL; - - switch(val) - { - case JitConfigurationFlag_None: - out = "None"; - break; - case JitConfigurationFlag_Enabled: - out = "Enabled"; - break; - default: - out = "Unknown"; - break; - } - - return out; -} - -bool retrieveNacpDataFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, char **out_nacp_xml, u64 *out_nacp_xml_size, nacp_icons_ctx **out_nacp_icons_ctx, u8 *out_nacp_icons_ctx_cnt) -{ - if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys || !out_nacp_xml || !out_nacp_xml_size || !out_nacp_icons_ctx || !out_nacp_icons_ctx_cnt) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to generate NACP XML!", __func__); - return false; - } - - u64 entryOffset = 0; - romfs_file *entry = NULL; - bool found_nacp = false, success = false; - - nacp_t controlNacp; - char *nacpXml = NULL; - - u8 i = 0, j = 0; - char tmp[NAME_BUF_LEN] = {'\0'}; - u32 flag; - - u8 nacpIconCnt = 0; - nacp_icons_ctx *nacpIcons = NULL; - - bool found_icon = false; - u8 languageIconHash[SHA256_HASH_SIZE]; - char languageIconHashStr[SHA256_HASH_SIZE + 1] = {'\0'}; - - char ncaIdStr[SHA256_HASH_SIZE + 1] = {'\0'}; - convertDataToHexString(ncaId->c, 0x10, ncaIdStr, 0x21); - - char dataStr[100] = {'\0'}; - - u8 null_key[0x10]; - memset(null_key, 0, 0x10); - - bool availableSGC = false, availableRGC = false; - - if (parseRomFsEntryFromNca(ncmStorage, ncaId, dec_nca_header, decrypted_nca_keys) != 0) return false; - - // Look for the control.nacp file - while(entryOffset < romFsContext.romfs_filetable_size) - { - entry = (romfs_file*)((u8*)romFsContext.romfs_file_entries + entryOffset); - - if (entry->parent == 0 && entry->nameLen == 12 && !strncasecmp((char*)entry->name, "control.nacp", 12)) - { - found_nacp = true; - break; - } - - entryOffset += round_up(ROMFS_NONAME_FILEENTRY_SIZE + entry->nameLen, 4); - } - - if (!found_nacp) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to find \"control.nacp\" file in Control NCA RomFS section!", __func__); - goto out; - } - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff, &controlNacp, sizeof(nacp_t), false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read \"control.nacp\" from RomFS section in Control NCA!", __func__); - goto out; - } - - // Make sure that the output buffer for our NACP XML is big enough - nacpXml = calloc(NSP_XML_BUFFER_SIZE, sizeof(char)); - if (!nacpXml) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the NACP XML!", __func__); - goto out; - } - - sprintf(nacpXml, "\n" \ - "\n"); - - for(i = 0; i < 0x10; i++) - { - if (strlen(controlNacp.titles[i].name) || strlen(controlNacp.titles[i].publisher)) - { - sprintf(tmp, " \n" \ - " <Language>%s</Language>\n" \ - " <Name>%s</Name>\n" \ - " <Publisher>%s</Publisher>\n" \ - " \n", \ - getNacpLangName(i), \ - controlNacp.titles[i].name, \ - controlNacp.titles[i].publisher); - - strcat(nacpXml, tmp); - } - } - - if (strlen(controlNacp.isbn)) - { - sprintf(tmp, " %s\n", controlNacp.isbn); - strcat(nacpXml, tmp); - } else { - strcat(nacpXml, " \n"); - } - - sprintf(tmp, " %s\n", getNacpStartupUserAccount(controlNacp.startup_user_account)); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpUserAccountSwitchLock(controlNacp.user_account_switch_lock)); - strcat(nacpXml, tmp); - - strcat(nacpXml, " "); - - memcpy(&flag, &(controlNacp.parental_control_flag), sizeof(u32)); - if (flag != 0) - { - if (controlNacp.parental_control_flag.ParentalControlFlag_FreeCommunication) strcat(nacpXml, "FreeCommunication"); - } else { - strcat(nacpXml, "None"); - } - - strcat(nacpXml, "\n"); - - for(i = 0; i < 0x10; i++) - { - char *str = getNacpSupportedLanguageFlag(&(controlNacp.supported_language_flag), i); - if (!str) continue; - - sprintf(tmp, " %s\n", str); - strcat(nacpXml, tmp); - - nacpIconCnt++; - } - - sprintf(tmp, " %s\n", getNacpScreenshot(controlNacp.screenshot)); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpVideoCapture(controlNacp.video_capture)); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.presence_group_id); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", controlNacp.display_version); - strcat(nacpXml, tmp); - - for(i = 0; i < 0x20; i++) - { - u8 *ptr = ((u8*)(&(controlNacp.rating_ages)) + i); - if (*ptr == 0xFF) continue; - - sprintf(tmp, " \n" \ - " %s\n" \ - " %u\n" \ - " \n", \ - getNacpRatingAgeOrganization(i), \ - *ptr); - - strcat(nacpXml, tmp); - } - - sprintf(tmp, " %s\n", getNacpDataLossConfirmation(controlNacp.data_loss_confirmation)); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpPlayLogPolicy(controlNacp.play_log_policy)); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.save_data_owner_id); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.user_account_save_data_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.user_account_save_data_journal_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.device_save_data_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.device_save_data_journal_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.bcat_delivery_cache_storage_size); - strcat(nacpXml, tmp); - - if (strlen(controlNacp.application_error_code_category)) - { - sprintf(tmp, " %s\n", controlNacp.application_error_code_category); - strcat(nacpXml, tmp); - } else { - strcat(nacpXml, " \n"); - } - - sprintf(tmp, " 0x%016lx\n", controlNacp.add_on_content_base_id); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpLogoType(controlNacp.logo_type)); - strcat(nacpXml, tmp); - - for(i = 0; i < 0x8; i++) - { - if (controlNacp.local_communication_ids[i] != 0) - { - sprintf(tmp, " 0x%016lx\n", controlNacp.local_communication_ids[i]); - strcat(nacpXml, tmp); - } - } - - sprintf(tmp, " %s\n", getNacpLogoHandling(controlNacp.logo_handling)); - strcat(nacpXml, tmp); - - if (nacpIconCnt) - { - nacpIcons = calloc(nacpIconCnt, sizeof(nacp_icons_ctx)); - if (!nacpIcons) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the NACP icons!", __func__); - goto out; - } - - for(i = 0; i < 0x10; i++) - { - char *str = getNacpSupportedLanguageFlag(&(controlNacp.supported_language_flag), i); - if (!str) continue; - - // Retrieve the icon file for this language and calculate its SHA-256 checksum - found_icon = false; - - memset(languageIconHash, 0, SHA256_HASH_SIZE); - memset(languageIconHashStr, 0, SHA256_HASH_SIZE + 1); - - entryOffset = 0; - sprintf(tmp, "icon_%s.dat", getNacpLangName(i)); - - while(entryOffset < romFsContext.romfs_filetable_size) - { - entry = (romfs_file*)((u8*)romFsContext.romfs_file_entries + entryOffset); - - if (entry->parent == 0 && entry->nameLen == strlen(tmp) && !strncasecmp((char*)entry->name, tmp, strlen(tmp)) && entry->dataSize <= 0x20000) - { - found_icon = true; - break; - } - - entryOffset += round_up(ROMFS_NONAME_FILEENTRY_SIZE + entry->nameLen, 4); - } - - if (!found_icon) - { - nacpIconCnt--; - continue; - } - - strcat(nacpXml, " \n"); - - sprintf(tmp, " %s\n", getNacpLangName(i)); - strcat(nacpXml, tmp); - - // Fill details for our NACP icon context - sprintf(nacpIcons[j].filename, "%s.nx.%s.jpg", ncaIdStr, getNacpLangName(i)); // Temporary, the NCA ID is subject to change - nacpIcons[j].icon_size = entry->dataSize; - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff, nacpIcons[j].icon_data, nacpIcons[j].icon_size, false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read \"%s\" from RomFS section in Control NCA!", __func__, tmp); - goto out; - } - - sha256CalculateHash(languageIconHash, nacpIcons[j].icon_data, nacpIcons[j].icon_size); - - // Only retrieve the first half from the SHA-256 checksum - convertDataToHexString(languageIconHash, SHA256_HASH_SIZE / 2, languageIconHashStr, SHA256_HASH_SIZE + 1); - - // Now print the hash - sprintf(tmp, " %s\n", languageIconHashStr); - strcat(nacpXml, tmp); - - strcat(nacpXml, " \n"); - - j++; - } - } - - sprintf(tmp, " 0x%016lx\n", controlNacp.seed_for_pseudo_device_id); - strcat(nacpXml, tmp); - - if (strlen(controlNacp.bcat_passphrase)) - { - sprintf(tmp, " %s\n", controlNacp.bcat_passphrase); - strcat(nacpXml, tmp); - } else { - strcat(nacpXml, " \n"); - } - - strcat(nacpXml, " "); - - if (*((u8*)&(controlNacp.startup_user_account_option)) != 0) - { - if (controlNacp.startup_user_account_option.StartupUserAccountOptionFlag_IsOptional) strcat(nacpXml, "IsOptional"); - } else { - strcat(nacpXml, "None"); - } - - strcat(nacpXml, "\n"); - - sprintf(tmp, " %s\n", getNacpAddOnContentRegistrationType(controlNacp.add_on_content_registration_type)); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.user_account_save_data_size_max); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.user_account_save_data_journal_size_max); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.device_save_data_size_max); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.device_save_data_journal_size_max); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.temporary_storage_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.cache_storage_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.cache_storage_journal_size); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%016lx\n", controlNacp.cache_storage_data_and_journal_size_max); - strcat(nacpXml, tmp); - - sprintf(tmp, " 0x%04x\n", controlNacp.cache_storage_index_max); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpHdcp(controlNacp.hdcp)); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpCrashReport(controlNacp.crash_report)); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpRuntimeAddOnContentInstall(controlNacp.runtime_add_on_content_install)); - strcat(nacpXml, tmp); - - sprintf(tmp, " %s\n", getNacpRuntimeParameterDelivery(controlNacp.runtime_parameter_delivery)); - strcat(nacpXml, tmp); - - for(i = 0; i < 0x10; i++) - { - if (controlNacp.play_log_queryable_application_ids[i] != 0) - { - sprintf(tmp, " 0x%016lx\n", controlNacp.play_log_queryable_application_ids[i]); - strcat(nacpXml, tmp); - } - } - - sprintf(tmp, " %s\n", getNacpPlayLogQueryCapability(controlNacp.play_log_query_capability)); - strcat(nacpXml, tmp); - - strcat(nacpXml, " "); - - if (*((u8*)&(controlNacp.repair_flag)) != 0) - { - if (controlNacp.repair_flag.RepairFlag_SuppressGameCardAccess) strcat(nacpXml, "SuppressGameCardAccess"); - } else { - strcat(nacpXml, "None"); - } - - strcat(nacpXml, "\n"); - - strcat(nacpXml, " "); - - memcpy(&flag, &(controlNacp.attribute_flag), sizeof(u32)); - if (flag != 0) - { - if (controlNacp.attribute_flag.AttributeFlag_Demo) strcat(nacpXml, "Demo"); - - if (controlNacp.attribute_flag.AttributeFlag_RetailInteractiveDisplay) - { - if (controlNacp.attribute_flag.AttributeFlag_Demo) strcat(nacpXml, ","); - strcat(nacpXml, "RetailInteractiveDisplay"); - } - } else { - strcat(nacpXml, "None"); - } - - strcat(nacpXml, "\n"); - - sprintf(tmp, " %u\n", controlNacp.program_index); - strcat(nacpXml, tmp); - - strcat(nacpXml, " "); - - if (*((u8*)&(controlNacp.required_network_service_license_on_launch_flag)) != 0) - { - if (controlNacp.required_network_service_license_on_launch_flag.RequiredNetworkServiceLicenseOnLaunchFlag_Common) strcat(nacpXml, "Common"); - } else { - strcat(nacpXml, "None"); - } - - strcat(nacpXml, "\n"); - - // Check if we actually have valid NeighborDetectionClientConfiguration values - availableSGC = (controlNacp.neighbor_detection_client_configuration.send_group_configuration.group_id != 0 && memcmp(controlNacp.neighbor_detection_client_configuration.send_group_configuration.key, null_key, 0x10) != 0); - - for(i = 0; i < 0x10; i++) - { - if (controlNacp.neighbor_detection_client_configuration.receivable_group_configurations[i].group_id != 0 && memcmp(controlNacp.neighbor_detection_client_configuration.receivable_group_configurations[i].key, null_key, 0x10) != 0) - { - availableRGC = true; - break; - } - } - - if (availableSGC || availableRGC) - { - strcat(nacpXml, " \n"); - - if (availableSGC) - { - convertDataToHexString(controlNacp.neighbor_detection_client_configuration.send_group_configuration.key, 0x10, dataStr, 100); - - sprintf(tmp, " \n" \ - " 0x%016lx\n" \ - " %s\n" \ - " \n", \ - controlNacp.neighbor_detection_client_configuration.send_group_configuration.group_id, \ - dataStr); - - strcat(nacpXml, tmp); - } - - if (availableRGC) - { - for(i = 0; i < 0x10; i++) - { - if (controlNacp.neighbor_detection_client_configuration.receivable_group_configurations[i].group_id != 0 && memcmp(controlNacp.neighbor_detection_client_configuration.receivable_group_configurations[i].key, null_key, 0x10) != 0) - { - convertDataToHexString(controlNacp.neighbor_detection_client_configuration.receivable_group_configurations[i].key, 0x10, dataStr, 100); - - sprintf(tmp, " \n" \ - " 0x%016lx\n" \ - " %s\n" \ - " \n", \ - controlNacp.neighbor_detection_client_configuration.receivable_group_configurations[i].group_id, \ - dataStr); - - strcat(nacpXml, tmp); - } - } - } - - strcat(nacpXml, " \n"); - } - - sprintf(tmp, " \n" \ - " %s\n" \ - " 0x%016lx\n" \ - " \n", \ - getNacpJitConfigurationFlag(controlNacp.jit_configuration.jit_configuration_flag), \ - controlNacp.jit_configuration.memory_size); - - strcat(nacpXml, tmp); - - strcat(nacpXml, ""); - - *out_nacp_xml = nacpXml; - *out_nacp_xml_size = strlen(nacpXml); - - if (nacpIconCnt) - { - *out_nacp_icons_ctx = nacpIcons; - *out_nacp_icons_ctx_cnt = nacpIconCnt; - } - - success = true; - -out: - if (!success) - { - if (nacpIcons != NULL) free(nacpIcons); - - if (nacpXml != NULL) free(nacpXml); - } - - // Manually free these pointers - // Calling freeRomFsContext() would also close the ncmStorage handle - free(romFsContext.romfs_dir_entries); - romFsContext.romfs_dir_entries = NULL; - - free(romFsContext.romfs_file_entries); - romFsContext.romfs_file_entries = NULL; - - return success; -} - -bool retrieveLegalInfoXmlFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, char **outBuf, u64 *outBufSize) -{ - if (!ncmStorage || !ncaId || !dec_nca_header || !decrypted_nca_keys || !outBuf) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to retrieve \"legalinfo.xml\"!", __func__); - return false; - } - - u64 entryOffset = 0; - romfs_file *entry = NULL; - bool found_legalinfo = false, success = false; - - u64 legalInfoXmlSize = 0; - char *legalInfoXml = NULL; - - if (parseRomFsEntryFromNca(ncmStorage, ncaId, dec_nca_header, decrypted_nca_keys) != 0) return false; - - // Look for the legalinfo.xml file - while(entryOffset < romFsContext.romfs_filetable_size) - { - entry = (romfs_file*)((u8*)romFsContext.romfs_file_entries + entryOffset); - - if (entry->parent == 0 && entry->nameLen == 13 && !strncasecmp((char*)entry->name, "legalinfo.xml", 13)) - { - found_legalinfo = true; - break; - } - - entryOffset += round_up(ROMFS_NONAME_FILEENTRY_SIZE + entry->nameLen, 4); - } - - if (!found_legalinfo) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to find \"legalinfo.xml\" file in Manual NCA RomFS section!", __func__); - goto out; - } - - // Allocate memory for the legalinfo.xml contents - legalInfoXmlSize = entry->dataSize; - legalInfoXml = calloc(legalInfoXmlSize, sizeof(char)); - if (!legalInfoXml) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for the \"legalinfo.xml\" contents!", __func__); - goto out; - } - - if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff, legalInfoXml, legalInfoXmlSize, false)) - { - breaks++; - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read \"legalinfo.xml\" from RomFS section in Manual NCA!", __func__); - goto out; - } - - *outBuf = legalInfoXml; - *outBufSize = legalInfoXmlSize; - - success = true; - -out: - if (!success && legalInfoXml != NULL) free(legalInfoXml); - - // Manually free these pointers - // Calling freeRomFsContext() would also close the ncmStorage handle - free(romFsContext.romfs_dir_entries); - romFsContext.romfs_dir_entries = NULL; - - free(romFsContext.romfs_file_entries); - romFsContext.romfs_file_entries = NULL; - - return success; -} diff --git a/legacy/nca.h b/legacy/nca.h index a633724..51010f6 100644 --- a/legacy/nca.h +++ b/legacy/nca.h @@ -289,12 +289,6 @@ typedef struct { u64 block_size[2]; } nca_program_mod_data; -typedef struct { - char filename[100]; - u64 icon_size; - u8 icon_data[0x20000]; -} nacp_icons_ctx; - typedef struct { u32 nca_index; u64 xml_size; @@ -347,110 +341,6 @@ typedef struct { bool missing_tik; } title_rights_ctx; -typedef struct { - NcmStorageId storageId; - NcmContentStorage ncmStorage; - NcmContentId ncaId; - u8 idOffset; - Aes128CtrContext aes_ctx; - u64 exefs_offset; // Relative to NCA start - u64 exefs_size; - pfs0_header exefs_header; - u64 exefs_entries_offset; // Relative to NCA start - pfs0_file_entry *exefs_entries; - u64 exefs_str_table_offset; // Relative to NCA start - char *exefs_str_table; - u64 exefs_data_offset; // Relative to NCA start -} exefs_ctx_t; - -typedef struct { - NcmStorageId storageId; - NcmContentStorage ncmStorage; - NcmContentId ncaId; - u8 idOffset; - Aes128CtrContext aes_ctx; - u64 section_offset; // Relative to NCA start - u64 section_size; - u64 romfs_offset; // Relative to NCA start - u64 romfs_size; - u64 romfs_dirtable_offset; // Relative to NCA start - u64 romfs_dirtable_size; - romfs_dir *romfs_dir_entries; - u64 romfs_filetable_offset; // Relative to NCA start - u64 romfs_filetable_size; - romfs_file *romfs_file_entries; - u64 romfs_filedata_offset; // Relative to NCA start -} romfs_ctx_t; - -typedef struct { - u64 virt_offset; - u64 phys_offset; - u32 is_patch; -} PACKED bktr_relocation_entry_t; - -typedef struct { - u32 _0x0; - u32 num_entries; - u64 virtual_offset_end; - bktr_relocation_entry_t entries[0x3FF0 / sizeof(bktr_relocation_entry_t)]; - u8 padding[0x3FF0 % sizeof(bktr_relocation_entry_t)]; -} PACKED bktr_relocation_bucket_t; - -typedef struct { - u32 _0x0; - u32 num_buckets; - u64 total_size; - u64 bucket_virtual_offsets[0x3FF0 / sizeof(u64)]; - bktr_relocation_bucket_t buckets[]; -} PACKED bktr_relocation_block_t; - -typedef struct { - u64 offset; - u32 _0x8; - u32 ctr_val; -} PACKED bktr_subsection_entry_t; - -typedef struct { - u32 _0x0; - u32 num_entries; - u64 physical_offset_end; - bktr_subsection_entry_t entries[0x3FF]; -} PACKED bktr_subsection_bucket_t; - -typedef struct { - u32 _0x0; - u32 num_buckets; - u64 total_size; - u64 bucket_physical_offsets[0x3FF0 / sizeof(u64)]; - bktr_subsection_bucket_t buckets[]; -} PACKED bktr_subsection_block_t; - -typedef struct { - NcmStorageId storageId; - NcmContentStorage ncmStorage; - NcmContentId ncaId; - u8 idOffset; - Aes128CtrContext aes_ctx; - u64 section_offset; // Relative to NCA start - u64 section_size; - bktr_superblock_t superblock; - bktr_relocation_block_t *relocation_block; - bktr_subsection_block_t *subsection_block; - u64 virtual_seek; // Relative to section start - u64 bktr_seek; // Relative to section start (patch BKTR section) - u64 base_seek; // Relative to section start (base application RomFS section) - u64 romfs_offset; // Relative to section start - u64 romfs_size; - u64 romfs_dirtable_offset; // Relative to section start - u64 romfs_dirtable_size; - romfs_dir *romfs_dir_entries; - u64 romfs_filetable_offset; // Relative to section start - u64 romfs_filetable_size; - romfs_file *romfs_file_entries; - u64 romfs_filedata_offset; // Relative to section start - bool use_base_romfs; -} bktr_ctx_t; - // Used in HFS0 / ExeFS / RomFS browsers typedef struct { u64 size; @@ -463,278 +353,6 @@ typedef struct { browser_entry_size_info sizeInfo; // Only used if type == 2 } romfs_browser_entry; -typedef struct { - char name[0x200]; - char publisher[0x100]; -} Title; - -typedef enum { - Language_AmericanEnglish = 0, - Language_BritishEnglish = 1, - Language_Japanese = 2, - Language_French = 3, - Language_German = 4, - Language_LatinAmericanSpanish = 5, - Language_Spanish = 6, - Language_Italian = 7, - Language_Dutch = 8, - Language_CanadianFrench = 9, - Language_Portuguese = 10, - Language_Russian = 11, - Language_Korean = 12, - Language_TraditionalChinese = 13, - Language_SimplifiedChinese = 14 -} Language; - -typedef enum { - StartupUserAccount_None = 0, - StartupUserAccount_Required = 1, - StartupUserAccount_RequiredWithNetworkServiceAccountAvailable = 2 -} StartupUserAccount; - -/* Introduced as of SDK 6.4.0 */ -typedef enum { - UserAccountSwitchLock_Disable = 0, - UserAccountSwitchLock_Enable = 1 -} UserAccountSwitchLock; - -/* Introduced as of SDK 3.4.0 */ -typedef enum { - AddOnContentRegistrationType_AllOnLaunch = 0, - AddOnContentRegistrationType_OnDemand = 1 -} AddOnContentRegistrationType; - -typedef struct { - u32 AttributeFlag_Demo : 1; - u32 AttributeFlag_RetailInteractiveDisplay : 1; /* Introduced as of SDK 3.4.0 */ -} AttributeFlag; - -typedef struct { - u32 SupportedLanguageFlag_AmericanEnglish : 1; - u32 SupportedLanguageFlag_BritishEnglish : 1; - u32 SupportedLanguageFlag_Japanese : 1; - u32 SupportedLanguageFlag_French : 1; - u32 SupportedLanguageFlag_German : 1; - u32 SupportedLanguageFlag_LatinAmericanSpanish : 1; - u32 SupportedLanguageFlag_Spanish : 1; - u32 SupportedLanguageFlag_Italian : 1; - u32 SupportedLanguageFlag_Dutch : 1; - u32 SupportedLanguageFlag_CanadianFrench : 1; - u32 SupportedLanguageFlag_Portuguese : 1; - u32 SupportedLanguageFlag_Russian : 1; - u32 SupportedLanguageFlag_Korean : 1; - u32 SupportedLanguageFlag_TraditionalChinese : 1; - u32 SupportedLanguageFlag_SimplifiedChinese : 1; -} SupportedLanguageFlag; - -typedef struct { - u32 ParentalControlFlag_FreeCommunication : 1; -} ParentalControlFlag; - -typedef enum { - Screenshot_Allow = 0, - Screenshot_Deny = 1 -} Screenshot; - -typedef enum { - VideoCapture_Disable = 0, - VideoCapture_Manual = 1, - VideoCapture_Enable = 2 -} VideoCapture; - -typedef enum { - DataLossConfirmation_None = 0, - DataLossConfirmation_Required = 1 -} DataLossConfirmation; - -typedef enum { - PlayLogPolicy_All = 0, - PlayLogPolicy_LogOnly = 1, - PlayLogPolicy_None = 2 -} PlayLogPolicy; - -typedef enum { - RatingAgeOrganization_CERO = 0, - RatingAgeOrganization_GRACGCRB = 1, - RatingAgeOrganization_GSRMR = 2, - RatingAgeOrganization_ESRB = 3, - RatingAgeOrganization_ClassInd = 4, - RatingAgeOrganization_USK = 5, - RatingAgeOrganization_PEGI = 6, - RatingAgeOrganization_PEGIPortugal = 7, - RatingAgeOrganization_PEGIBBFC = 8, - RatingAgeOrganization_Russian = 9, - RatingAgeOrganization_ACB = 10, - RatingAgeOrganization_OFLC = 11, - RatingAgeOrganization_IARCGeneric = 12 /* Introduced as of SDK 9.3.1 */ -} RatingAgeOrganization; - -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_1[0x13]; -} RatingAge; - -typedef enum { - LogoType_LicensedByNintendo = 0, - LogoType_DistributedByNintendo = 1, /* Removed in SDK 3.5.2 */ - LogoType_Nintendo = 2 -} LogoType; - -typedef enum { - LogoHandling_Auto = 0, - LogoHandling_Manual = 1 -} LogoHandling; - -/* Introduced as of SDK 4.5.0 */ -typedef enum { - RuntimeAddOnContentInstall_Deny = 0, - RuntimeAddOnContentInstall_AllowAppend = 1 -} RuntimeAddOnContentInstall; - -/* Introduced as of SDK 9.3.1 */ -typedef enum { - RuntimeParameterDelivery_Always = 0, - RuntimeParameterDelivery_AlwaysIfUserStateMatched = 1, - RuntimeParameterDelivery_OnRestart = 2 -} RuntimeParameterDelivery; - -/* Introduced as of SDK 3.5.2 */ -typedef enum { - CrashReport_Deny = 0, - CrashReport_Allow = 1 -} CrashReport; - -typedef enum { - Hdcp_None = 0, - Hdcp_Required = 1 -} Hdcp; - -/* Introduced as of SDK 7.6.0 */ -typedef struct { - u8 StartupUserAccountOptionFlag_IsOptional : 1; -} StartupUserAccountOptionFlag; - -/* Introduced as of SDK 5.3.0 */ -typedef enum { - PlayLogQueryCapability_None = 0, - PlayLogQueryCapability_WhiteList = 1, - PlayLogQueryCapability_All = 2 -} PlayLogQueryCapability; - -/* Introduced as of SDK 5.3.0 */ -typedef struct { - u8 RepairFlag_SuppressGameCardAccess : 1; -} RepairFlag; - -/* Introduced as of SDK 6.4.0 */ -typedef struct { - u8 RequiredNetworkServiceLicenseOnLaunchFlag_Common : 1; -} RequiredNetworkServiceLicenseOnLaunchFlag; - -typedef struct { - u64 group_id; - u8 key[0x10]; -} NeighborDetectionGroupConfiguration; - -typedef struct { - NeighborDetectionGroupConfiguration send_group_configuration; - NeighborDetectionGroupConfiguration receivable_group_configurations[0x10]; -} NeighborDetectionClientConfiguration; - -/* Introduced as of SDK 7.6.0 */ -typedef enum { - JitConfigurationFlag_None = 0, - JitConfigurationFlag_Enabled = 1 -} JitConfigurationFlag; - -typedef struct { - u64 jit_configuration_flag; - u64 memory_size; -} JitConfiguration; - -typedef struct { - Title titles[0x10]; - char isbn[0x25]; - u8 startup_user_account; - u8 user_account_switch_lock; /* Old: touch_screen_usage (None, Supported, Required) */ - u8 add_on_content_registration_type; - AttributeFlag attribute_flag; - SupportedLanguageFlag supported_language_flag; - ParentalControlFlag parental_control_flag; - u8 screenshot; - u8 video_capture; - u8 data_loss_confirmation; - u8 play_log_policy; - u64 presence_group_id; - RatingAge rating_ages; - 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; - char application_error_code_category[0x8]; - u64 local_communication_ids[0x8]; - u8 logo_type; - u8 logo_handling; - u8 runtime_add_on_content_install; - u8 runtime_parameter_delivery; - u8 reserved_1[0x2]; - u8 crash_report; - u8 hdcp; - u64 seed_for_pseudo_device_id; - char bcat_passphrase[0x41]; - StartupUserAccountOptionFlag startup_user_account_option; - 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; - u16 cache_storage_index_max; - u8 reserved_3[0x6]; - u64 play_log_queryable_application_ids[0x10]; - u8 play_log_query_capability; - RepairFlag repair_flag; - u8 program_index; - RequiredNetworkServiceLicenseOnLaunchFlag required_network_service_license_on_launch_flag; - u8 reserved_4[0x4]; - NeighborDetectionClientConfiguration neighbor_detection_client_configuration; - JitConfiguration jit_configuration; - u8 reserved_5[0xC40]; -} nacp_t; - -char *getContentType(u8 type); - -void generateCnmtXml(cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, char *out); - -void convertNcaSizeToU64(const u8 size[0x6], u64 *out); - -void convertU64ToNcaSize(const u64 size, u8 out[0x6]); - -bool readNcaDataByContentId(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, u64 offset, void *outBuf, size_t bufSize); - -bool processNcaCtrSectionBlock(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, Aes128CtrContext *ctx, u64 offset, void *outBuf, size_t bufSize, bool encrypt); - -bool readBktrSectionBlock(u64 offset, void *outBuf, size_t bufSize); - bool encryptNcaHeader(nca_header_t *input, u8 *outBuf, u64 outBufSize); bool decryptNcaHeader(const u8 *ncaBuf, u64 ncaBufSize, nca_header_t *out, title_rights_ctx *rights_info, u8 *decrypted_nca_keys, bool retrieveTitleKeyData); @@ -747,16 +365,6 @@ bool retrieveCnmtNcaData(NcmStorageId curStorageId, u8 *ncaBuf, cnmt_xml_program bool patchCnmtNca(u8 *ncaBuf, u64 ncaBufSize, cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, nca_cnmt_mod_data *cnmt_mod); -bool parseExeFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys); - -int parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys); - -bool parseBktrEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys); - bool generateProgramInfoXml(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, bool useCustomAcidRsaPubKey, char **outBuf, u64 *outBufSize); -bool retrieveNacpDataFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, char **out_nacp_xml, u64 *out_nacp_xml_size, nacp_icons_ctx **out_nacp_icons_ctx, u8 *out_nacp_icons_ctx_cnt); - -bool retrieveLegalInfoXmlFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, char **outBuf, u64 *outBufSize); - #endif diff --git a/source/bktr.h b/source/bktr.h index 38a7431..30b2eab 100644 --- a/source/bktr.h +++ b/source/bktr.h @@ -29,13 +29,15 @@ typedef enum { BktrIndirectStorageIndex_Original = 0, BktrIndirectStorageIndex_Patch = 1 -} PACKED BktrIndirectStorageIndex; +} BktrIndirectStorageIndex; +#pragma pack(push, 1) typedef struct { u64 virtual_offset; u64 physical_offset; u32 indirect_storage_index; ///< BktrIndirectStorageIndex. -} PACKED BktrIndirectStorageEntry; +} BktrIndirectStorageEntry; +#pragma pack(pop) typedef struct { u32 index; @@ -43,7 +45,7 @@ typedef struct { u64 end_offset; BktrIndirectStorageEntry indirect_storage_entries[0x3FF0 / sizeof(BktrIndirectStorageEntry)]; u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)]; -} PACKED BktrIndirectStorageBucket; +} BktrIndirectStorageBucket; typedef struct { u32 index; @@ -51,20 +53,20 @@ typedef struct { u64 virtual_size; u64 virtual_offsets[0x3FF0 / sizeof(u64)]; BktrIndirectStorageBucket indirect_storage_buckets[]; -} PACKED BktrIndirectStorageBlock; +} BktrIndirectStorageBlock; typedef struct { u64 offset; u32 size; u32 generation; -} PACKED BktrAesCtrExStorageEntry; +} BktrAesCtrExStorageEntry; typedef struct { u32 index; u32 entry_count; u64 end_offset; BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF]; -} PACKED BktrAesCtrExStorageBucket; +} BktrAesCtrExStorageBucket; typedef struct { u32 index; @@ -72,7 +74,7 @@ typedef struct { u64 physical_size; u64 physical_offsets[0x3FF0 / sizeof(u64)]; BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[]; -} PACKED BktrAesCtrExStorageBlock; +} BktrAesCtrExStorageBlock; typedef struct { RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context. diff --git a/source/cnmt.c b/source/cnmt.c index 9ec0b3c..d36d5f4 100644 --- a/source/cnmt.c +++ b/source/cnmt.c @@ -59,7 +59,7 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx) goto end; } - /* Get Partition FS entry count. */ + /* Get Partition FS entry count. Edge case, we should never trigger this. */ if (!(pfs_entry_count = pfsGetEntryCount(&(out->pfs_ctx)))) { LOGFILE("Partition FS has no file entries!"); @@ -100,8 +100,7 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx) /* Allocate memory for the raw CNMT data. */ out->raw_data_size = out->pfs_entry->size; - out->raw_data = malloc(out->raw_data_size); - if (!out->raw_data) + if (!(out->raw_data = malloc(out->raw_data_size))) { LOGFILE("Failed to allocate memory for the raw CNMT data!"); goto end; diff --git a/source/legal_info.c b/source/legal_info.c new file mode 100644 index 0000000..f7863fa --- /dev/null +++ b/source/legal_info.c @@ -0,0 +1,89 @@ +/* + * legal_info.c + * + * Copyright (c) 2020, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * nxdumptool is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "utils.h" +#include "legal_info.h" +#include "romfs.h" + +bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx) +{ + if (!out || !nca_ctx || !strlen(nca_ctx->content_id_str) || nca_ctx->content_type != NcmContentType_LegalInformation || nca_ctx->content_size < NCA_FULL_HEADER_LENGTH || \ + (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \ + nca_ctx->header.content_type != NcaContentType_Manual || !out) + { + LOGFILE("Invalid parameters!"); + return false; + } + + RomFileSystemContext romfs_ctx = {0}; + RomFileSystemFileEntry *xml_entry = NULL; + + bool success = false; + + /* Free output context beforehand. */ + legalInfoFreeContext(out); + + /* Initialize RomFS context. */ + if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_contexts[0]))) + { + LOGFILE("Failed to initialize RomFS context!"); + goto end; + } + + /* Retrieve RomFS file entry for 'legalinfo.xml'. */ + if (!(xml_entry = romfsGetFileEntryByPath(&romfs_ctx, "/legalinfo.xml"))) + { + LOGFILE("Failed to retrieve file entry for \"legalinfo.xml\" from RomFS!"); + goto end; + } + + //LOGFILE("Found 'legalinfo.xml' entry in LegalInformation NCA \"%s\".", nca_ctx->content_id_str); + + /* Verify XML size. */ + if (!xml_entry->size) + { + LOGFILE("Invalid XML size!"); + goto end; + } + + /* Allocate memory for the XML. */ + out->authoring_tool_xml_size = xml_entry->size; + if (!(out->authoring_tool_xml = malloc(out->authoring_tool_xml_size))) + { + LOGFILE("Failed to allocate memory for the XML!"); + goto end; + } + + /* Read NACP data into memory buffer. */ + if (!romfsReadFileEntryData(&romfs_ctx, xml_entry, out->authoring_tool_xml, out->authoring_tool_xml_size, 0)) + { + LOGFILE("Failed to read XML!"); + goto end; + } + + success = true; + +end: + romfsFreeContext(&romfs_ctx); + + if (!success) legalInfoFreeContext(out); + + return success; +} diff --git a/source/legal_info.h b/source/legal_info.h new file mode 100644 index 0000000..b97e50b --- /dev/null +++ b/source/legal_info.h @@ -0,0 +1,46 @@ +/* + * legal_info.h + * + * Copyright (c) 2020, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * nxdumptool is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __LEGAL_INFO_H__ +#define __LEGAL_INFO_H__ + +#include "nca.h" + +typedef struct { + NcaContext *nca_ctx; ///< Pointer to the NCA context for the LegalInformation NCA from which XML data is retrieved. + char *authoring_tool_xml; ///< Pointer to a dynamically allocated, NULL-terminated buffer that holds AuthoringTool-like XML data. + u64 authoring_tool_xml_size; ///< Size for the AuthoringTool-like XML. This is essentially the same as using strlen() on 'authoring_tool_xml'. +} LegalInfoContext; + +/// Initializes a LegalInfoContext using a previously initialized NcaContext (which must belong to a LegalInformation NCA). +bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx); + +/// Helper inline functions. + +NX_INLINE void legalInfoFreeContext(LegalInfoContext *legal_info_ctx) +{ + if (!legal_info_ctx) return; + if (legal_info_ctx->authoring_tool_xml) free(legal_info_ctx->authoring_tool_xml); + memset(legal_info_ctx, 0, sizeof(LegalInfoContext)); +} + +#endif /* __LEGAL_INFO_H__ */ diff --git a/source/nacp.c b/source/nacp.c index fbb355c..c40d58d 100644 --- a/source/nacp.c +++ b/source/nacp.c @@ -239,8 +239,7 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx) } /* Allocate memory for the NACP data. */ - out->data = malloc(sizeof(_NacpStruct)); - if (!out->data) + if (!(out->data = malloc(sizeof(_NacpStruct)))) { LOGFILE("Failed to allocate memory for the NACP data!"); goto end; diff --git a/source/npdm.h b/source/npdm.h index ed57029..2b5e406 100644 --- a/source/npdm.h +++ b/source/npdm.h @@ -41,11 +41,6 @@ typedef struct { u8 reserved : 3; } NpdmMetaFlags; -typedef struct { - u32 offset; - u32 size; -} NpdmSectionHeader; - /// This is the start of every NPDM file. /// This is followed by ACID and ACI0 sections, both with variable offsets and sizes. typedef struct { @@ -63,15 +58,21 @@ typedef struct { char name[0x10]; ///< Usually set to "Application". char product_code[0x10]; ///< Usually zeroed out. u8 reserved_4[0x30]; - NpdmSectionHeader aci_section_header; ///< Offset value relative to the start of this header. - NpdmSectionHeader acid_section_header; ///< Offset value relative to the start of this header. + u32 aci_offset; ///< Offset value relative to the start of this header. + u32 aci_size; + u32 acid_offset; ///< Offset value relative to the start of this header. + u32 acid_size; } NpdmMetaHeader; typedef enum { NpdmMemoryRegion_Application = 0, NpdmMemoryRegion_Applet = 1, - NpdmMemoryRegion_SecureSystem = 2, - NpdmMemoryRegion_NonSecureSystem = 3 + NpdmMemoryRegion_SystemSecure = 2, + NpdmMemoryRegion_SystemNonSecure = 3, + + /// Old. + NpdmMemoryRegion_NonSecure = NpdmMemoryRegion_Application, + NpdmMemoryRegion_Secure = NpdmMemoryRegion_Applet } NpdmMemoryRegion; typedef struct { @@ -92,9 +93,12 @@ typedef struct { NpdmAcidFlags flags; u64 program_id_min; u64 program_id_max; - NpdmSectionHeader fs_access_control_section_header; ///< Offset value relative to the start of this header. - NpdmSectionHeader srv_access_control_section_header; ///< Offset value relative to the start of this header. - NpdmSectionHeader kernel_capability_section_header; ///< Offset value relative to the start of this header. + u32 fs_access_control_offset; ///< Offset value relative to the start of this header. + u32 fs_access_control_size; + u32 srv_access_control_offset; ///< Offset value relative to the start of this header. + u32 srv_access_control_size; + u32 kernel_capability_offset; ///< Offset value relative to the start of this header. + u32 kernel_capability_size; u8 reserved_2[0x8]; } NpdmAcidHeader; @@ -105,9 +109,12 @@ typedef struct { u8 reserved_1[0xC]; u64 program_id; u8 reserved_2[0x8]; - NpdmSectionHeader fs_access_control_section_header; ///< Offset value relative to the start of this header. - NpdmSectionHeader srv_access_control_section_header; ///< Offset value relative to the start of this header. - NpdmSectionHeader kernel_capability_section_header; ///< Offset value relative to the start of this header. + u32 fs_access_control_offset; ///< Offset value relative to the start of this header. + u32 fs_access_control_size; + u32 srv_access_control_offset; ///< Offset value relative to the start of this header. + u32 srv_access_control_size; + u32 kernel_capability_offset; ///< Offset value relative to the start of this header. + u32 kernel_capability_size; u8 reserved_3[0x8]; } NpdmAciHeader; @@ -195,9 +202,8 @@ typedef struct { } NpdmAciFsAccessControlDescriptorContentOwnerBlock; typedef enum { - NpdmAccessibility_Read = 1, - NpdmAccessibility_Write = 2, - NpdmAccessibility_ReadWrite = 3 + NpdmAccessibility_Read = BIT(0), + NpdmAccessibility_Write = BIT(1) } NpdmAccessibility; /// Placed after NpdmAciFsAccessControlDescriptor / NpdmAciFsAccessControlDescriptorContentOwnerBlock if the 'content_owner_info_size' member from NpdmAciFsAccessControlDescriptor is greater than zero. @@ -207,24 +213,46 @@ typedef struct { u8 accessibility[]; ///< 'save_data_owner_id_count' NpdmAccessibility fields. } NpdmAciFsAccessControlDescriptorSaveDataOwnerBlock; +/// SrvAccessControl descriptor. Part of the ACID and ACI0 section bodies. +/// This descriptor is composed of a variable number of NpdmSrvAccessControlDescriptorEntry elements, each one with a variable size. +/// Since the total number of services isn't stored anywhere, this descriptor must be parsed until its total size is reached. typedef struct { u8 name_length : 3; ///< Service name length minus 1. u8 reserved : 4; u8 is_server : 1; ///< Indicates if the service is allowed to be registered. -} NpdmSrvAccessControlEntryDescriptor; + char name[]; ///< Service name, stored without a NULL terminator. Supports the "*" wildcard character. +} NpdmSrvAccessControlDescriptorEntry; -/// SrvAccessControl descriptor. Part of the ACID and ACI0 section bodies. -/// This descriptor is composed of a variable number of NpdmSrvAccessControlEntry elements, each one with a variable size. -/// Since the total number of services isn't stored anywhere, this descriptor must be parsed until its total size is reached. -typedef struct { - NpdmSrvAccessControlEntryDescriptor descriptor; - char name[]; ///< Service name, stored without a NULL terminator. Supports the "*" wildcard character. -} NpdmSrvAccessControlEntry; +typedef enum { + NpdmKernelCapabilityEntryNumber_ThreadInfo = 3, + NpdmKernelCapabilityEntryNumber_EnableSystemCalls = 4, + NpdmKernelCapabilityEntryNumber_MemoryMap = 6, + NpdmKernelCapabilityEntryNumber_IoMemoryMap = 7, + NpdmKernelCapabilityEntryNumber_MemoryRegionMap = 10, + NpdmKernelCapabilityEntryNumber_EnableInterrupts = 11, + NpdmKernelCapabilityEntryNumber_MiscParams = 13, + NpdmKernelCapabilityEntryNumber_KernelVersion = 14, + NpdmKernelCapabilityEntryNumber_HandleTableSize = 15, + NpdmKernelCapabilityEntryNumber_MiscFlags = 16 +} NpdmKernelCapabilityEntryNumber; + +typedef enum { + NpdmKernelCapabilityEntryValue_ThreadInfo = BIT(NpdmKernelCapabilityEntryNumber_ThreadInfo) - 1, + NpdmKernelCapabilityEntryValue_EnableSystemCalls = BIT(NpdmKernelCapabilityEntryNumber_EnableSystemCalls) - 1, + NpdmKernelCapabilityEntryValue_MemoryMap = BIT(NpdmKernelCapabilityEntryNumber_MemoryMap) - 1, + NpdmKernelCapabilityEntryValue_IoMemoryMap = BIT(NpdmKernelCapabilityEntryNumber_IoMemoryMap) - 1, + NpdmKernelCapabilityEntryValue_MemoryRegionMap = BIT(NpdmKernelCapabilityEntryNumber_MemoryRegionMap) - 1, + NpdmKernelCapabilityEntryValue_EnableInterrupts = BIT(NpdmKernelCapabilityEntryNumber_EnableInterrupts) - 1, + NpdmKernelCapabilityEntryValue_MiscParams = BIT(NpdmKernelCapabilityEntryNumber_MiscParams) - 1, + NpdmKernelCapabilityEntryValue_KernelVersion = BIT(NpdmKernelCapabilityEntryNumber_KernelVersion) - 1, + NpdmKernelCapabilityEntryValue_HandleTableSize = BIT(NpdmKernelCapabilityEntryNumber_HandleTableSize) - 1, + NpdmKernelCapabilityEntryValue_MiscFlags = BIT(NpdmKernelCapabilityEntryNumber_MiscFlags) - 1 +} NpdmKernelCapabilityEntryValue; /// ThreadInfo entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 3; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. + u32 entry_value : NpdmKernelCapabilityEntryNumber_ThreadInfo; ///< Always set to NpdmKernelCapabilityEntryValue_ThreadInfo. + u32 padding : 1; ///< Always set to zero. u32 lowest_priority : 6; u32 highest_priority : 6; u32 min_core_number : 8; @@ -234,153 +262,153 @@ typedef struct { /// System call table. typedef enum { ///< System calls for index 0. - NpdmSystemCallIds_Unknown1 = BIT(0), - NpdmSystemCallIds_SetHeapSize = BIT(1), - NpdmSystemCallIds_SetMemoryPermission = BIT(2), - NpdmSystemCallIds_SetMemoryAttribute = BIT(3), - NpdmSystemCallIds_MapMemory = BIT(4), - NpdmSystemCallIds_UnmapMemory = BIT(5), - NpdmSystemCallIds_QueryMemory = BIT(6), - NpdmSystemCallIds_ExitProcess = BIT(7), - NpdmSystemCallIds_CreateThread = BIT(8), - NpdmSystemCallIds_StartThread = BIT(9), - NpdmSystemCallIds_ExitThread = BIT(10), - NpdmSystemCallIds_SleepThread = BIT(11), - NpdmSystemCallIds_GetThreadPriority = BIT(12), - NpdmSystemCallIds_SetThreadPriority = BIT(13), - NpdmSystemCallIds_GetThreadCoreMask = BIT(14), - NpdmSystemCallIds_SetThreadCoreMask = BIT(15), - NpdmSystemCallIds_GetCurrentProcessorNumber = BIT(16), - NpdmSystemCallIds_SignalEvent = BIT(17), - NpdmSystemCallIds_ClearEvent = BIT(18), - NpdmSystemCallIds_MapSharedMemory = BIT(19), - NpdmSystemCallIds_UnmapSharedMemory = BIT(20), - NpdmSystemCallIds_CreateTransferMemory = BIT(21), - NpdmSystemCallIds_CloseHandle = BIT(22), - NpdmSystemCallIds_ResetSignal = BIT(23), + NpdmSystemCallId_Reserved1 = BIT(0), + NpdmSystemCallId_SetHeapSize = BIT(1), + NpdmSystemCallId_SetMemoryPermission = BIT(2), + NpdmSystemCallId_SetMemoryAttribute = BIT(3), + NpdmSystemCallId_MapMemory = BIT(4), + NpdmSystemCallId_UnmapMemory = BIT(5), + NpdmSystemCallId_QueryMemory = BIT(6), + NpdmSystemCallId_ExitProcess = BIT(7), + NpdmSystemCallId_CreateThread = BIT(8), + NpdmSystemCallId_StartThread = BIT(9), + NpdmSystemCallId_ExitThread = BIT(10), + NpdmSystemCallId_SleepThread = BIT(11), + NpdmSystemCallId_GetThreadPriority = BIT(12), + NpdmSystemCallId_SetThreadPriority = BIT(13), + NpdmSystemCallId_GetThreadCoreMask = BIT(14), + NpdmSystemCallId_SetThreadCoreMask = BIT(15), + NpdmSystemCallId_GetCurrentProcessorNumber = BIT(16), + NpdmSystemCallId_SignalEvent = BIT(17), + NpdmSystemCallId_ClearEvent = BIT(18), + NpdmSystemCallId_MapSharedMemory = BIT(19), + NpdmSystemCallId_UnmapSharedMemory = BIT(20), + NpdmSystemCallId_CreateTransferMemory = BIT(21), + NpdmSystemCallId_CloseHandle = BIT(22), + NpdmSystemCallId_ResetSignal = BIT(23), ///< System calls for index 1. - NpdmSystemCallIds_WaitSynchronization = BIT(0), - NpdmSystemCallIds_CancelSynchronization = BIT(1), - NpdmSystemCallIds_ArbitrateLock = BIT(2), - NpdmSystemCallIds_ArbitrateUnlock = BIT(3), - NpdmSystemCallIds_WaitProcessWideKeyAtomic = BIT(4), - NpdmSystemCallIds_SignalProcessWideKey = BIT(5), - NpdmSystemCallIds_GetSystemTick = BIT(6), - NpdmSystemCallIds_ConnectToNamedPort = BIT(7), - NpdmSystemCallIds_SendSyncRequestLight = BIT(8), - NpdmSystemCallIds_SendSyncRequest = BIT(9), - NpdmSystemCallIds_SendSyncRequestWithUserBuffer = BIT(10), - NpdmSystemCallIds_SendAsyncRequestWithUserBuffer = BIT(11), - NpdmSystemCallIds_GetProcessId = BIT(12), - NpdmSystemCallIds_GetThreadId = BIT(13), - NpdmSystemCallIds_Break = BIT(14), - NpdmSystemCallIds_OutputDebugString = BIT(15), - NpdmSystemCallIds_ReturnFromException = BIT(16), - NpdmSystemCallIds_GetInfo = BIT(17), - NpdmSystemCallIds_FlushEntireDataCache = BIT(18), - NpdmSystemCallIds_FlushDataCache = BIT(19), - NpdmSystemCallIds_MapPhysicalMemory = BIT(20), - NpdmSystemCallIds_UnmapPhysicalMemory = BIT(21), - NpdmSystemCallIds_GetDebugFutureThreadInfo = BIT(22), - NpdmSystemCallIds_GetLastThreadInfo = BIT(23), + NpdmSystemCallId_WaitSynchronization = BIT(0), + NpdmSystemCallId_CancelSynchronization = BIT(1), + NpdmSystemCallId_ArbitrateLock = BIT(2), + NpdmSystemCallId_ArbitrateUnlock = BIT(3), + NpdmSystemCallId_WaitProcessWideKeyAtomic = BIT(4), + NpdmSystemCallId_SignalProcessWideKey = BIT(5), + NpdmSystemCallId_GetSystemTick = BIT(6), + NpdmSystemCallId_ConnectToNamedPort = BIT(7), + NpdmSystemCallId_SendSyncRequestLight = BIT(8), + NpdmSystemCallId_SendSyncRequest = BIT(9), + NpdmSystemCallId_SendSyncRequestWithUserBuffer = BIT(10), + NpdmSystemCallId_SendAsyncRequestWithUserBuffer = BIT(11), + NpdmSystemCallId_GetProcessId = BIT(12), + NpdmSystemCallId_GetThreadId = BIT(13), + NpdmSystemCallId_Break = BIT(14), + NpdmSystemCallId_OutputDebugString = BIT(15), + NpdmSystemCallId_ReturnFromException = BIT(16), + NpdmSystemCallId_GetInfo = BIT(17), + NpdmSystemCallId_FlushEntireDataCache = BIT(18), + NpdmSystemCallId_FlushDataCache = BIT(19), + NpdmSystemCallId_MapPhysicalMemory = BIT(20), + NpdmSystemCallId_UnmapPhysicalMemory = BIT(21), + NpdmSystemCallId_GetDebugFutureThreadInfo = BIT(22), ///< Old: SystemCallId_GetFutureThreadInfo. + NpdmSystemCallId_GetLastThreadInfo = BIT(23), ///< System calls for index 2. - NpdmSystemCallIds_GetResourceLimitLimitValue = BIT(0), - NpdmSystemCallIds_GetResourceLimitCurrentValue = BIT(1), - NpdmSystemCallIds_SetThreadActivity = BIT(2), - NpdmSystemCallIds_GetThreadContext3 = BIT(3), - NpdmSystemCallIds_WaitForAddress = BIT(4), - NpdmSystemCallIds_SignalToAddress = BIT(5), - NpdmSystemCallIds_SynchronizePreemptionState = BIT(6), - NpdmSystemCallIds_Unknown2 = BIT(7), - NpdmSystemCallIds_Unknown3 = BIT(8), - NpdmSystemCallIds_Unknown4 = BIT(9), - NpdmSystemCallIds_Unknown5 = BIT(10), - NpdmSystemCallIds_Unknown6 = BIT(11), - NpdmSystemCallIds_KernelDebug = BIT(12), - NpdmSystemCallIds_ChangeKernelTraceState = BIT(13), - NpdmSystemCallIds_Unknown7 = BIT(14), - NpdmSystemCallIds_Unknown8 = BIT(15), - NpdmSystemCallIds_CreateSession = BIT(16), - NpdmSystemCallIds_AcceptSession = BIT(17), - NpdmSystemCallIds_ReplyAndReceiveLight = BIT(18), - NpdmSystemCallIds_ReplyAndReceive = BIT(19), - NpdmSystemCallIds_ReplyAndReceiveWithUserBuffer = BIT(20), - NpdmSystemCallIds_CreateEvent = BIT(21), - NpdmSystemCallIds_Unknown9 = BIT(22), - NpdmSystemCallIds_Unknown10 = BIT(23), + NpdmSystemCallId_GetResourceLimitLimitValue = BIT(0), + NpdmSystemCallId_GetResourceLimitCurrentValue = BIT(1), + NpdmSystemCallId_SetThreadActivity = BIT(2), + NpdmSystemCallId_GetThreadContext3 = BIT(3), + NpdmSystemCallId_WaitForAddress = BIT(4), + NpdmSystemCallId_SignalToAddress = BIT(5), + NpdmSystemCallId_SynchronizePreemptionState = BIT(6), + NpdmSystemCallId_Reserved2 = BIT(7), + NpdmSystemCallId_Reserved3 = BIT(8), + NpdmSystemCallId_Reserved4 = BIT(9), + NpdmSystemCallId_Reserved5 = BIT(10), + NpdmSystemCallId_Reserved6 = BIT(11), + NpdmSystemCallId_KernelDebug = BIT(12), + NpdmSystemCallId_ChangeKernelTraceState = BIT(13), + NpdmSystemCallId_Reserved7 = BIT(14), + NpdmSystemCallId_Reserved8 = BIT(15), + NpdmSystemCallId_CreateSession = BIT(16), + NpdmSystemCallId_AcceptSession = BIT(17), + NpdmSystemCallId_ReplyAndReceiveLight = BIT(18), + NpdmSystemCallId_ReplyAndReceive = BIT(19), + NpdmSystemCallId_ReplyAndReceiveWithUserBuffer = BIT(20), + NpdmSystemCallId_CreateEvent = BIT(21), + NpdmSystemCallId_Reserved9 = BIT(22), + NpdmSystemCallId_Reserved10 = BIT(23), ///< System calls for index 3. - NpdmSystemCallIds_MapPhysicalMemoryUnsafe = BIT(0), - NpdmSystemCallIds_UnmapPhysicalMemoryUnsafe = BIT(1), - NpdmSystemCallIds_SetUnsafeLimit = BIT(2), - NpdmSystemCallIds_CreateCodeMemory = BIT(3), - NpdmSystemCallIds_ControlCodeMemory = BIT(4), - NpdmSystemCallIds_SleepSystem = BIT(5), - NpdmSystemCallIds_ReadWriteRegister = BIT(6), - NpdmSystemCallIds_SetProcessActivity = BIT(7), - NpdmSystemCallIds_CreateSharedMemory = BIT(8), - NpdmSystemCallIds_MapTransferMemory = BIT(9), - NpdmSystemCallIds_UnmapTransferMemory = BIT(10), - NpdmSystemCallIds_CreateInterruptEvent = BIT(11), - NpdmSystemCallIds_QueryPhysicalAddress = BIT(12), - NpdmSystemCallIds_QueryIoMapping = BIT(13), - NpdmSystemCallIds_CreateDeviceAddressSpace = BIT(14), - NpdmSystemCallIds_AttachDeviceAddressSpace = BIT(15), - NpdmSystemCallIds_DetachDeviceAddressSpace = BIT(16), - NpdmSystemCallIds_MapDeviceAddressSpaceByForce = BIT(17), - NpdmSystemCallIds_MapDeviceAddressSpaceAligned = BIT(18), - NpdmSystemCallIds_MapDeviceAddressSpace = BIT(19), - NpdmSystemCallIds_UnmapDeviceAddressSpace = BIT(20), - NpdmSystemCallIds_InvalidateProcessDataCache = BIT(21), - NpdmSystemCallIds_StoreProcessDataCache = BIT(22), - NpdmSystemCallIds_FlushProcessDataCache = BIT(23), + NpdmSystemCallId_MapPhysicalMemoryUnsafe = BIT(0), + NpdmSystemCallId_UnmapPhysicalMemoryUnsafe = BIT(1), + NpdmSystemCallId_SetUnsafeLimit = BIT(2), + NpdmSystemCallId_CreateCodeMemory = BIT(3), + NpdmSystemCallId_ControlCodeMemory = BIT(4), + NpdmSystemCallId_SleepSystem = BIT(5), + NpdmSystemCallId_ReadWriteRegister = BIT(6), + NpdmSystemCallId_SetProcessActivity = BIT(7), + NpdmSystemCallId_CreateSharedMemory = BIT(8), + NpdmSystemCallId_MapTransferMemory = BIT(9), + NpdmSystemCallId_UnmapTransferMemory = BIT(10), + NpdmSystemCallId_CreateInterruptEvent = BIT(11), + NpdmSystemCallId_QueryPhysicalAddress = BIT(12), + NpdmSystemCallId_QueryIoMapping = BIT(13), + NpdmSystemCallId_CreateDeviceAddressSpace = BIT(14), + NpdmSystemCallId_AttachDeviceAddressSpace = BIT(15), + NpdmSystemCallId_DetachDeviceAddressSpace = BIT(16), + NpdmSystemCallId_MapDeviceAddressSpaceByForce = BIT(17), + NpdmSystemCallId_MapDeviceAddressSpaceAligned = BIT(18), + NpdmSystemCallId_MapDeviceAddressSpace = BIT(19), + NpdmSystemCallId_UnmapDeviceAddressSpace = BIT(20), + NpdmSystemCallId_InvalidateProcessDataCache = BIT(21), + NpdmSystemCallId_StoreProcessDataCache = BIT(22), + NpdmSystemCallId_FlushProcessDataCache = BIT(23), ///< System calls for index 4. - NpdmSystemCallIds_DebugActiveProcess = BIT(0), - NpdmSystemCallIds_BreakDebugProcess = BIT(1), - NpdmSystemCallIds_TerminateDebugProcess = BIT(2), - NpdmSystemCallIds_GetDebugEvent = BIT(3), - NpdmSystemCallIds_ContinueDebugEvent = BIT(4), - NpdmSystemCallIds_GetProcessList = BIT(5), - NpdmSystemCallIds_GetThreadList = BIT(6), - NpdmSystemCallIds_GetDebugThreadContext = BIT(7), - NpdmSystemCallIds_SetDebugThreadContext = BIT(8), - NpdmSystemCallIds_QueryDebugProcessMemory = BIT(9), - NpdmSystemCallIds_ReadDebugProcessMemory = BIT(10), - NpdmSystemCallIds_WriteDebugProcessMemory = BIT(11), - NpdmSystemCallIds_SetHardwareBreakPoint = BIT(12), - NpdmSystemCallIds_GetDebugThreadParam = BIT(13), - NpdmSystemCallIds_Unknown11 = BIT(14), - NpdmSystemCallIds_GetSystemInfo = BIT(15), - NpdmSystemCallIds_CreatePort = BIT(16), - NpdmSystemCallIds_ManageNamedPort = BIT(17), - NpdmSystemCallIds_ConnectToPort = BIT(18), - NpdmSystemCallIds_SetProcessMemoryPermission = BIT(19), - NpdmSystemCallIds_MapProcessMemory = BIT(20), - NpdmSystemCallIds_UnmapProcessMemory = BIT(21), - NpdmSystemCallIds_QueryProcessMemory = BIT(22), - NpdmSystemCallIds_MapProcessCodeMemory = BIT(23), + NpdmSystemCallId_DebugActiveProcess = BIT(0), + NpdmSystemCallId_BreakDebugProcess = BIT(1), + NpdmSystemCallId_TerminateDebugProcess = BIT(2), + NpdmSystemCallId_GetDebugEvent = BIT(3), + NpdmSystemCallId_ContinueDebugEvent = BIT(4), + NpdmSystemCallId_GetProcessList = BIT(5), + NpdmSystemCallId_GetThreadList = BIT(6), + NpdmSystemCallId_GetDebugThreadContext = BIT(7), + NpdmSystemCallId_SetDebugThreadContext = BIT(8), + NpdmSystemCallId_QueryDebugProcessMemory = BIT(9), + NpdmSystemCallId_ReadDebugProcessMemory = BIT(10), + NpdmSystemCallId_WriteDebugProcessMemory = BIT(11), + NpdmSystemCallId_SetHardwareBreakPoint = BIT(12), + NpdmSystemCallId_GetDebugThreadParam = BIT(13), + NpdmSystemCallId_Reserved11 = BIT(14), + NpdmSystemCallId_GetSystemInfo = BIT(15), + NpdmSystemCallId_CreatePort = BIT(16), + NpdmSystemCallId_ManageNamedPort = BIT(17), + NpdmSystemCallId_ConnectToPort = BIT(18), + NpdmSystemCallId_SetProcessMemoryPermission = BIT(19), + NpdmSystemCallId_MapProcessMemory = BIT(20), + NpdmSystemCallId_UnmapProcessMemory = BIT(21), + NpdmSystemCallId_QueryProcessMemory = BIT(22), + NpdmSystemCallId_MapProcessCodeMemory = BIT(23), ///< System calls for index 5. - NpdmSystemCallIds_UnmapProcessCodeMemory = BIT(0), - NpdmSystemCallIds_CreateProcess = BIT(1), - NpdmSystemCallIds_StartProcess = BIT(2), - NpdmSystemCallIds_TerminateProcess = BIT(3), - NpdmSystemCallIds_GetProcessInfo = BIT(4), - NpdmSystemCallIds_CreateResourceLimit = BIT(5), - NpdmSystemCallIds_SetResourceLimitLimitValue = BIT(6), - NpdmSystemCallIds_CallSecureMonitor = BIT(7), - NpdmSystemCallIds_Count = 0x80 ///< Total values supported by this enum. -} NpdmSystemCallIds; + NpdmSystemCallId_UnmapProcessCodeMemory = BIT(0), + NpdmSystemCallId_CreateProcess = BIT(1), + NpdmSystemCallId_StartProcess = BIT(2), + NpdmSystemCallId_TerminateProcess = BIT(3), + NpdmSystemCallId_GetProcessInfo = BIT(4), + NpdmSystemCallId_CreateResourceLimit = BIT(5), + NpdmSystemCallId_SetResourceLimitLimitValue = BIT(6), + NpdmSystemCallId_CallSecureMonitor = BIT(7), + NpdmSystemCallId_Count = 0x80 ///< Total values supported by this enum. +} NpdmSystemCallId; /// EnableSystemCalls entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 4; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. - u32 system_call_ids : 24; ///< NpdmSystemCallIds. - u32 index : 3; ///< System calls index. + u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableSystemCalls; ///< Always set to NpdmKernelCapabilityEntryValue_EnableSystemCalls. + u32 padding : 1; ///< Always set to zero. + u32 system_call_ids : 24; ///< NpdmSystemCallId. + u32 index : 3; ///< System calls index. } NpdmEnableSystemCalls; typedef enum { @@ -389,34 +417,39 @@ typedef enum { } NpdmPermissionType; typedef enum { - NpdmMapType_Io = 0, - NpdmMapType_Static = 1 -} NpdmMapType; + NpdmMappingType_Io = 0, + NpdmMappingType_Static = 1 +} NpdmMappingType; -/// MemoryMapType1 entry for the KernelCapability descriptor. -/// Always followed by a MemoryMapType2 entry. typedef struct { - u32 entry_number : 6; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. - u32 begin_address : 24; ///< begin_address << 12. - u32 permission_type : 1; ///< NpdmPermissionType. + u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap. + u32 padding : 1; ///< Always set to zero. + u32 begin_address : 24; ///< begin_address << 12. + u32 permission_type : 1; ///< NpdmPermissionType. } NpdmMemoryMapType1; -/// MemoryMapType2 entry for the KernelCapability descriptor. -/// Always preceded by a MemoryMapType1 entry. typedef struct { - u32 entry_number : 6; ///< All bits set to one. - u32 reserved_1 : 1; ///< Always set to zero. - u32 size : 20; ///< size << 12. - u32 reserved_2 : 4; - u32 map_type : 1; ///< NpdmMapType. + u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap. + u32 padding : 1; ///< Always set to zero. + u32 size : 20; ///< size << 12. + u32 reserved : 4; + u32 mapping_type : 1; ///< NpdmMappingType. } NpdmMemoryMapType2; +/// MemoryMap entry for the KernelCapability descriptor. +/// These are always stored in pairs of MemoryMapType1 + MemoryMapType2 entries. +typedef struct { + union { + NpdmMemoryMapType1 type1; + NpdmMemoryMapType2 type2; + }; +} NpdmMemoryMap; + /// IoMemoryMap entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 7; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. - u32 begin_address : 24; ///< begin_address << 12. + u32 entry_value : NpdmKernelCapabilityEntryNumber_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_IoMemoryMap. + u32 padding : 1; ///< Always set to zero. + u32 begin_address : 24; ///< begin_address << 12. } NpdmIoMemoryMap; typedef enum { @@ -428,22 +461,22 @@ typedef enum { /// MemoryRegionMap entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 10; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. - u32 region_type_1 : 6; ///< NpdmRegionType. - u32 permission_type_1 : 1; ///< NpdmPermissionType. - u32 region_type_2 : 6; ///< NpdmRegionType. - u32 permission_type_2 : 1; ///< NpdmPermissionType. - u32 region_type_3 : 6; ///< NpdmRegionType. - u32 permission_type_3 : 1; ///< NpdmPermissionType. + u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryRegionMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryRegionMap. + u32 padding : 1; ///< Always set to zero. + u32 region_type_1 : 6; ///< NpdmRegionType. + u32 permission_type_1 : 1; ///< NpdmPermissionType. + u32 region_type_2 : 6; ///< NpdmRegionType. + u32 permission_type_2 : 1; ///< NpdmPermissionType. + u32 region_type_3 : 6; ///< NpdmRegionType. + u32 permission_type_3 : 1; ///< NpdmPermissionType. } NpdmMemoryRegionMap; /// EnableInterrupts entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 11; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. - u32 interrupt_number_1 : 10; ///< 0x3FF means empty. - u32 interrupt_number_2 : 10; ///< 0x3FF means empty. + u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryValue_EnableInterrupts. + u32 padding : 1; ///< Always set to zero. + u32 interrupt_number_1 : 10; ///< 0x3FF means empty. + u32 interrupt_number_2 : 10; ///< 0x3FF means empty. } NpdmEnableInterrupts; typedef enum { @@ -455,35 +488,35 @@ typedef enum { /// MiscParams entry for the KernelCapability descriptor. /// Defaults to 0 if this entry doesn't exist. typedef struct { - u32 entry_number : 13; ///< All bits set to one. - u32 reserved_1 : 1; ///< Always set to zero. - u32 program_type : 3; ///< NpdmProgramType. - u32 reserved_2 : 15; + u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscParams; ///< Always set to NpdmKernelCapabilityEntryValue_MiscParams. + u32 padding : 1; ///< Always set to zero. + u32 program_type : 3; ///< NpdmProgramType. + u32 reserved : 15; } NpdmMiscParams; /// KernelVersion entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 14; ///< All bits set to one. - u32 reserved : 1; ///< Always set to zero. + u32 entry_value : NpdmKernelCapabilityEntryNumber_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryValue_KernelVersion. + u32 padding : 1; ///< Always set to zero. u32 minor_version : 4; u32 major_version : 13; } NpdmKernelVersion; /// HandleTableSize entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 15; ///< All bits set to one. - u32 reserved_1 : 1; ///< Always set to zero. + u32 entry_value : NpdmKernelCapabilityEntryNumber_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryValue_HandleTableSize. + u32 padding : 1; ///< Always set to zero. u32 handle_table_size : 10; - u32 reserved_2 : 6; + u32 reserved : 6; } NpdmHandleTableSize; /// MiscFlags entry for the KernelCapability descriptor. typedef struct { - u32 entry_number : 16; ///< All bits set to one. - u32 reserved_1 : 1; ///< Always set to zero. + u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryValue_MiscFlags. + u32 padding : 1; ///< Always set to zero. u32 enable_debug : 1; u32 force_debug : 1; - u32 reserved_2 : 13; + u32 reserved : 13; } NpdmMiscFlags; /// KernelCapability descriptor. Part of the ACID and ACI0 section bodies. @@ -491,6 +524,12 @@ typedef struct { /// The entry type is identified by a pattern of "01...11" (zero followed by ones) in the low u16, counting from the LSB. The variable number of ones must never exceed 16 (entirety of the low u16). typedef struct { u32 value; -} NpdmKernelCapabilityEntry; +} NpdmKernelCapabilityDescriptorEntry; + +/// Returns a value that can be compared to values from the NpdmKernelCapabilityEntryValue enum. +NX_INLINE u32 npdmGetKernelCapabilityDescriptorEntryValue(NpdmKernelCapabilityDescriptorEntry *entry) +{ + return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0); +} #endif /* __NPDM_H__ */ diff --git a/source/romfs.c b/source/romfs.c index c0f9650..fa862fe 100644 --- a/source/romfs.c +++ b/source/romfs.c @@ -314,16 +314,19 @@ end: RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const char *path) { size_t path_len = 0; + u8 content_type = 0; char *path_dup = NULL, *filename = NULL; RomFileSystemFileEntry *file_entry = NULL; RomFileSystemDirectoryEntry *dir_entry = NULL; - if (!ctx || !ctx->file_table || !ctx->file_table_size || !path || *path != '/' || (path_len = strlen(path)) <= 1) + if (!ctx || !ctx->file_table || !ctx->file_table_size || !ctx->nca_fs_ctx || !ctx->nca_fs_ctx->nca_ctx || !path || *path != '/' || (path_len = strlen(path)) <= 1) { LOGFILE("Invalid parameters!"); return NULL; } + content_type = ((NcaContext*)ctx->nca_fs_ctx->nca_ctx)->content_type; + /* Duplicate path. */ if (!(path_dup = strdup(path))) { @@ -359,10 +362,9 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const /* Retrieve file entry. */ if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename))) { - /* Only log error if we're not dealing with NACP icons. */ - int res = strncmp("/icon_", path, 6); - if (res != 0 || (res == 0 && ((NcaContext*)ctx->nca_fs_ctx->nca_ctx)->content_type != NcmContentType_Control)) - LOGFILE("Failed to retrieve file entry by name for \"%s\"! (\"%s\").", filename, path); + /* Only log error if we're not dealing with NACP icons or a LegalInformation XML. */ + bool skip_log = ((!strncmp(path, "/icon_", 6) && content_type == NcmContentType_Control) || (!strncmp(path, "/legalinfo.xml", 14) && content_type == NcmContentType_LegalInformation)); + if (!skip_log) LOGFILE("Failed to retrieve file entry by name for \"%s\"! (\"%s\").", filename, path); } end: diff --git a/todo.txt b/todo.txt index c6bfafe..1142495 100644 --- a/todo.txt +++ b/todo.txt @@ -3,19 +3,21 @@ todo: nca: functions for fs section lookup? (could just let the user choose...) nca: function to write re-encrypted nca headers / nca fs headers (don't forget nca0 please) nca: function to patch the private npdm acid signature from a program nca + patch the acid signature from the nca header + nca: add encrypted header to nca context, avoid re-encrypting the plaintext header in place + nca: use hash instead of dirty_header flag? tik: option to wipe elicense property mask tik: automatically dump tickets to the SD card? tik: use dumped tickets when the original ones can't be found in the ES savefile? - gamecard: hfs0 filelist generation functions + gamecard: hfs0 functions to display filelist - pfs0: filelist generation functions + pfs0: functions to display filelist pfs0: full header aligned to 0x20 (nsp) - romfs: filelist generation functions + romfs: functions to display filelist - bktr: filelist generation functions (wrappers for romfs filelist generation functions) + bktr: functions to display filelist (wrappers for romfs functions tbh) title: more functions for title lookup (filters, patches / aoc, etc.) title: more functions for content lookup (based on id?)