Skip to content

Commit

Permalink
Update to v1.1.12.
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkMatterCore committed Sep 26, 2020
1 parent 4932283 commit fc76571
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ include $(DEVKITPRO)/libnx/switch_rules

VERSION_MAJOR := 1
VERSION_MINOR := 1
VERSION_MICRO := 11
VERSION_MICRO := 12

APP_TITLE := nxdumptool
APP_AUTHOR := DarkMatterCore
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ Thanks to
Changelog
--------------

**v1.1.12:**

* Fixed RomFS dumping/browsing support for games with base Program NCAs without a RomFS section (e.g. Fortnite, World of Tanks Blitz, etc.). Big thanks to [bigkahuna666](https://github.com/bigkahuna666) for reporting the issue and providing with testing.

This is only a bugfix release. I don't expect to release any new versions until the rewrite is finished - the only exception being fixing some kind of feature-breaking bug. Please understand.

**v1.1.11:**

* Built using libnx `f01fb21`.
Expand Down
2 changes: 1 addition & 1 deletion source/dumper.c
Original file line number Diff line number Diff line change
Expand Up @@ -4641,7 +4641,7 @@ bool dumpRomFsSectionData(u32 titleIndex, selectedRomFsType curRomFsType, ncaFsO
}

// Retrieve RomFS from Program NCA
if (!readNcaRomFsSection(titleIndex, curRomFsType, -1))
if (readNcaRomFsSection(titleIndex, curRomFsType, -1) != 0)
{
free(dumpName);
breaks += 2;
Expand Down
47 changes: 27 additions & 20 deletions source/nca.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ bool bktrSectionPhysicalRead(void *outBuf, size_t bufSize)

bool readBktrSectionBlock(u64 offset, void *outBuf, size_t bufSize)
{
if (!bktrContext.section_offset || !bktrContext.section_size || !bktrContext.relocation_block || !bktrContext.subsection_block || !romFsContext.section_offset || !romFsContext.section_size || !outBuf || !bufSize)
if (!bktrContext.section_offset || !bktrContext.section_size || !bktrContext.relocation_block || (bktrContext.use_base_romfs && (!bktrContext.subsection_block || !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;
Expand All @@ -622,6 +622,13 @@ bool readBktrSectionBlock(u64 offset, void *outBuf, size_t bufSize)
{
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 unexistant base RomFS block(s)!", __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;
}
Expand Down Expand Up @@ -1686,12 +1693,12 @@ bool parseExeFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
return true;
}

bool parseRomFsEntryFromNca(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)
{
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;
return -1;
}

u8 romfs_index;
Expand Down Expand Up @@ -1733,7 +1740,7 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
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 false;
return -2;
}

section_offset = ((u64)dec_nca_header->section_entries[romfs_index].media_start_offset * (u64)MEDIA_UNIT_SIZE);
Expand All @@ -1742,7 +1749,7 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
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 false;
return -1;
}

// Generate initial CTR
Expand All @@ -1763,13 +1770,13 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
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 false;
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 false;
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);
Expand All @@ -1778,21 +1785,21 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
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 false;
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 false;
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 false;
return -1;
}

romfs_dirtable_offset = (romfs_offset + romFsHeader.dirTableOff);
Expand All @@ -1804,38 +1811,38 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
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 false;
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 false;
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 false;
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 false;
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 false;
return -1;
}

if (!processNcaCtrSectionBlock(ncmStorage, ncaId, &aes_ctx, romfs_filetable_offset, romfs_file_entries, romfs_filetable_size, false))
Expand All @@ -1844,7 +1851,7 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
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 false;
return -1;
}

// Save data to output struct
Expand All @@ -1864,12 +1871,12 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
romFsContext.romfs_file_entries = romfs_file_entries;
romFsContext.romfs_filedata_offset = romfs_filedata_offset;

return true;
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 || !romFsContext.section_offset || !romFsContext.section_size || !romFsContext.romfs_dir_entries || !romFsContext.romfs_file_entries)
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;
Expand Down Expand Up @@ -2941,7 +2948,7 @@ bool retrieveNacpDataFromNca(NcmContentStorage *ncmStorage, const NcmContentId *

bool availableSGC = false, availableRGC = false;

if (!parseRomFsEntryFromNca(ncmStorage, ncaId, dec_nca_header, decrypted_nca_keys)) return 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)
Expand Down Expand Up @@ -3413,7 +3420,7 @@ bool retrieveLegalInfoXmlFromNca(NcmContentStorage *ncmStorage, const NcmContent
u64 legalInfoXmlSize = 0;
char *legalInfoXml = NULL;

if (!parseRomFsEntryFromNca(ncmStorage, ncaId, dec_nca_header, decrypted_nca_keys)) return false;
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)
Expand Down
3 changes: 2 additions & 1 deletion source/nca.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ typedef struct {
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
Expand Down Expand Up @@ -748,7 +749,7 @@ bool patchCnmtNca(u8 *ncaBuf, u64 ncaBufSize, cnmt_xml_program_info *xml_program

bool parseExeFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys);

bool parseRomFsEntryFromNca(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);

Expand Down
2 changes: 1 addition & 1 deletion source/ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -5035,7 +5035,7 @@ UIResult uiProcess()

bool romfs_fail = false;

if (readNcaRomFsSection(curIndex, curRomFsType, -1))
if (readNcaRomFsSection(curIndex, curRomFsType, -1) == 0)
{
if (getRomFsFileList(0, (curRomFsType == ROMFS_TYPE_PATCH)))
{
Expand Down
28 changes: 19 additions & 9 deletions source/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,8 @@ void freeBktrContext()
free(bktrContext.romfs_file_entries);
bktrContext.romfs_file_entries = NULL;
}

bktrContext.use_base_romfs = false;
}

static void freeGameCardInfo()
Expand Down Expand Up @@ -2727,7 +2729,7 @@ bool readNcaExeFsSection(u32 titleIndex, bool usePatch)
return success;
}

bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int desiredIdOffset)
int readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int desiredIdOffset)
{
u32 i = 0;
Result result;
Expand Down Expand Up @@ -2755,7 +2757,7 @@ bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int des

u8 decrypted_nca_keys[NCA_KEY_AREA_SIZE];

bool success = false;
int ret = -1;

if (curRomFsType != ROMFS_TYPE_APP && curRomFsType != ROMFS_TYPE_PATCH && curRomFsType != ROMFS_TYPE_ADDON)
{
Expand Down Expand Up @@ -2879,8 +2881,8 @@ bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int des
if (curRomFsType != ROMFS_TYPE_PATCH)
{
// Read directory and file tables from the RomFS section
success = parseRomFsEntryFromNca(&ncmStorage, &ncaId, &dec_nca_header, decrypted_nca_keys);
if (success)
ret = parseRomFsEntryFromNca(&ncmStorage, &ncaId, &dec_nca_header, decrypted_nca_keys);
if (ret == 0)
{
romFsContext.storageId = curStorageId;
romFsContext.idOffset = titleContentInfos[contentIndex].id_offset;
Expand All @@ -2905,27 +2907,35 @@ bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int des
}

// Read directory and file tables from the RomFS section in the Program NCA from the base application
if (!readNcaRomFsSection(appIndex, ROMFS_TYPE_APP, (int)titleContentInfos[contentIndex].id_offset)) goto out;
// We'll proceed even if the Program NCA from the base application doesn't hold a RomFS section (ret == -2)
ret = readNcaRomFsSection(appIndex, ROMFS_TYPE_APP, (int)titleContentInfos[contentIndex].id_offset);
if (ret == -1) goto out;

// Remove missing base RomFS error message if needed
if (ret == -2) uiFill(0, STRING_Y_POS(breaks), FB_WIDTH, FB_HEIGHT - STRING_Y_POS(breaks), BG_COLOR_RGB);

// Update BKTR context to use the base RomFS if available
bktrContext.use_base_romfs = (ret == 0);

// Read BKTR entry data in the Program NCA from the update
success = parseBktrEntryFromNca(&ncmStorage, &ncaId, &dec_nca_header, decrypted_nca_keys);
if (success)
ret = (parseBktrEntryFromNca(&ncmStorage, &ncaId, &dec_nca_header, decrypted_nca_keys) ? 0 : -1);
if (ret == 0)
{
bktrContext.storageId = curStorageId;
bktrContext.idOffset = titleContentInfos[contentIndex].id_offset;
}
}

out:
if (!success)
if (ret != 0)
{
ncmContentStorageClose(&ncmStorage);
if (curStorageId == NcmStorageId_GameCard) closeGameCardStoragePartition();
}

if (titleContentInfos) free(titleContentInfos);

return success;
return ret;
}

bool getExeFsFileList()
Expand Down
2 changes: 1 addition & 1 deletion source/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ void removeConsoleDataFromTicket(title_rights_ctx *rights_info);

bool readNcaExeFsSection(u32 titleIndex, bool usePatch);

bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int desiredIdOffset);
int readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int desiredIdOffset);

bool getExeFsFileList();

Expand Down

0 comments on commit fc76571

Please sign in to comment.