diff --git a/Makefile b/Makefile index 91a039c..cf556bb 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ include $(DEVKITPRO)/libnx/switch_rules VERSION_MAJOR := 1 VERSION_MINOR := 1 -VERSION_MICRO := 9 +VERSION_MICRO := 10 APP_TITLE := nxdumptool APP_AUTHOR := DarkMatterCore diff --git a/README.md b/README.md index b0cb625..eb4d979 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,14 @@ If you like my work and you'd like to support me in any way, it's not necessary, Changelog -------------- +**v1.1.10:** + +* Built using libnx v3.1.0. +* Updated save.c/h to reflect changes made by shchmue in Lockpick_RCM. Fixes crashes under HOS 10.0.0. +* Fixed a nasty stack corruption issue caused by improper handling of FatFs objects. Fixes ES savefile mounting errors throughout the application (e.g. batch mode, ticket dumping). + +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.9:** * Built using libnx commit d7e6207. diff --git a/source/es.c b/source/es.c index cd05c05..b57d92d 100644 --- a/source/es.c +++ b/source/es.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/source/keys.c b/source/keys.c index fb71149..2d34294 100644 --- a/source/keys.c +++ b/source/keys.c @@ -134,7 +134,7 @@ bool retrieveProcessMemory(keyLocation *location) u64 pids[300]; u32 num_processes; - result = svcGetProcessList(&num_processes, pids, 300); + result = svcGetProcessList((s32*)&num_processes, pids, 300); if (R_FAILED(result)) { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: svcGetProcessList failed! (0x%08X)", __func__, result); @@ -763,59 +763,6 @@ void mgf1(const u8 *data, size_t data_length, u8 *mask, size_t mask_length) free(data_counter); } -void dumpSharedTikSavedata(void) -{ - FRESULT fr; - FIL save; - u32 size, blk, i, j; - u32 rd_b, wr_b; - - FILE *out; - - for(i = 0; i < 2; i++) - { - fr = FR_OK; - memset(&save, 0, sizeof(FIL)); - size = 0; - blk = DUMP_BUFFER_SIZE; - - out = NULL; - - fr = f_open(&save, (i == 0 ? "sys:/save/80000000000000e3" : "sys:/save/80000000000000e4"), FA_READ | FA_OPEN_EXISTING); - if (fr) continue; - - size = f_size(&save); - if (!size) - { - f_close(&save); - continue; - } - - out = fopen((i == 0 ? "sdmc:/80000000000000e3" : "sdmc:/80000000000000e4"), "wb"); - if (!out) - { - f_close(&save); - continue; - } - - for(j = 0; j < size; j += blk) - { - if ((size - j) < blk) blk = (size - j); - - rd_b = wr_b = 0; - - fr = f_read(&save, dumpBuf, blk, &rd_b); - if (fr || rd_b != blk) break; - - wr_b = fwrite(dumpBuf, 1, blk, out); - if (wr_b != blk) break; - } - - fclose(out); - f_close(&save); - } -} - int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_enc_key, u8 *out_dec_key) { int ret = -1; @@ -865,8 +812,8 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en u8 *D = NULL, *N = NULL, *E = NULL; - FRESULT fr; - FIL eTicketSave; + FRESULT fr = FR_OK; + FIL *eTicketSave = NULL; save_ctx_t *save_ctx = NULL; allocation_table_storage_ctx_t fat_storage; @@ -984,7 +931,6 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: NCA rights ID unavailable in this console!", __func__); ret = -2; - dumpSharedTikSavedata(); return ret; } @@ -1037,11 +983,19 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en setcal_eticket_retrieved = true; } + eTicketSave = calloc(1, sizeof(FIL)); + if (!eTicketSave) + { + uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to allocate memory for FatFs file descriptor!", __func__); + return ret; + } + // FatFs is used to mount the BIS System partition and read the ES savedata files to avoid 0xE02 (file already in use) errors - fr = f_open(&eTicketSave, (rightsIdType == 1 ? BIS_COMMON_TIK_SAVE_NAME : BIS_PERSONALIZED_TIK_SAVE_NAME), FA_READ | FA_OPEN_EXISTING); + fr = f_open(eTicketSave, (rightsIdType == 1 ? BIS_COMMON_TIK_SAVE_NAME : BIS_PERSONALIZED_TIK_SAVE_NAME), FA_READ | FA_OPEN_EXISTING); if (fr) { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to open ES %s eTicket save! (%u)", __func__, (rightsIdType == 1 ? "common" : "personalized"), fr); + free(eTicketSave); return ret; } @@ -1049,11 +1003,12 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en if (!save_ctx) { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to allocate memory for ticket savefile context!"); - f_close(&eTicketSave); + f_close(eTicketSave); + free(eTicketSave); return ret; } - save_ctx->file = &eTicketSave; + save_ctx->file = eTicketSave; save_ctx->tool_ctx.action = 0; if (!save_process(save_ctx)) @@ -1062,7 +1017,8 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en strcat(strbuf, tmp); uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, strbuf); free(save_ctx); - f_close(&eTicketSave); + f_close(eTicketSave); + free(eTicketSave); return ret; } @@ -1073,7 +1029,8 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, strbuf); save_free_contexts(save_ctx); free(save_ctx); - f_close(&eTicketSave); + f_close(eTicketSave); + free(eTicketSave); return ret; } @@ -1084,7 +1041,8 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, strbuf); save_free_contexts(save_ctx); free(save_ctx); - f_close(&eTicketSave); + f_close(eTicketSave); + free(eTicketSave); return ret; } @@ -1156,7 +1114,8 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en save_free_contexts(save_ctx); free(save_ctx); - f_close(&eTicketSave); + f_close(eTicketSave); + free(eTicketSave); if (!proceed) return ret; @@ -1164,7 +1123,6 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en { uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to find a matching eTicket entry for NCA rights ID!", __func__); ret = -2; - dumpSharedTikSavedata(); return ret; } diff --git a/source/save.c b/source/save.c index 5d43932..f12af34 100644 --- a/source/save.c +++ b/source/save.c @@ -152,7 +152,7 @@ remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entr return NULL; } - remap_segment_ctx_t *segments = calloc(sizeof(remap_segment_ctx_t), header->map_segment_count); + remap_segment_ctx_t *segments = calloc(header->map_segment_count, sizeof(remap_segment_ctx_t)); if (!segments) { snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: failed to allocate initial memory for remap segments!", __func__); @@ -164,39 +164,40 @@ remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entr for(i = 0; i < header->map_segment_count; i++) { - remap_segment_ctx_t *seg = &segments[i]; + remap_segment_ctx_t *seg = &(segments[i]); - seg->entries = calloc(1, sizeof(remap_entry_ctx_t)); + seg->entry_count = 0; + + seg->entries = calloc(1, sizeof(remap_entry_ctx_t*)); if (!seg->entries) { snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: failed to allocate memory for remap segment entry #%u!", __func__, entry_idx); goto out; } - memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); + seg->entries[seg->entry_count++] = &map_entries[entry_idx]; seg->offset = map_entries[entry_idx].virtual_offset; - map_entries[entry_idx].segment = seg; - seg->entry_count = 1; - entry_idx++; + map_entries[entry_idx++].segment = seg; while(entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) { map_entries[entry_idx].segment = seg; map_entries[entry_idx - 1].next = &map_entries[entry_idx]; - seg->entries = calloc(1, sizeof(remap_entry_ctx_t)); - if (!seg->entries) + remap_entry_ctx_t **ptr = calloc(sizeof(remap_entry_ctx_t*), seg->entry_count + 1); + if (!ptr) { snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: failed to allocate memory for remap segment entry #%u!", __func__, entry_idx); goto out; } - memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t)); - seg->entry_count++; - entry_idx++; + memcpy(ptr, seg->entries, sizeof(remap_entry_ctx_t*) * seg->entry_count); + free(seg->entries); + seg->entries = ptr; + seg->entries[seg->entry_count++] = &map_entries[entry_idx++]; } - seg->length = (seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset); + seg->length = (seg->entries[seg->entry_count - 1]->virtual_offset_end - seg->entries[0]->virtual_offset); } success = true; @@ -216,8 +217,7 @@ out: map_entries[entry_idx].segment->entries = NULL; } - map_entries[entry_idx].segment = NULL; - entry_idx++; + map_entries[entry_idx++].segment = NULL; while(entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) { @@ -231,8 +231,7 @@ out: map_entries[entry_idx].segment->entries = NULL; } - map_entries[entry_idx].segment = NULL; - entry_idx++; + map_entries[entry_idx++].segment = NULL; } } @@ -257,7 +256,7 @@ remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, u64 offset { for(unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) { - if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset) return (&ctx->segments[segment_idx].entries[i]); + if (ctx->segments[segment_idx].entries[i]->virtual_offset_end > offset) return ctx->segments[segment_idx].entries[i]; } } @@ -409,7 +408,7 @@ bool save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *c u32 length; }; - static struct salt_source_t salt_sources[6] = { + static const struct salt_source_t salt_sources[6] = { {"HierarchicalIntegrityVerificationStorage::Master", 48}, {"HierarchicalIntegrityVerificationStorage::L1", 44}, {"HierarchicalIntegrityVerificationStorage::L2", 44}, @@ -618,7 +617,7 @@ bool save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf } memcpy(data_buffer, ctx->salt, 0x20); - memcpy(data_buffer + 0x20, buffer, count); + memcpy(data_buffer + 0x20, buffer, ctx->sector_size); sha256CalculateHash(hash, data_buffer, ctx->sector_size + 0x20); hash[0x1F] |= 0x80; @@ -1336,9 +1335,7 @@ bool save_process(save_ctx_t *ctx) return success; } - if (!save_process_header(ctx)) return success; - - if (ctx->header_hash_validity == VALIDITY_INVALID) + if (!save_process_header(ctx) || ctx->header_hash_validity == VALIDITY_INVALID) { /* Try to parse Header B. */ fr = f_lseek(ctx->file, 0x4000); @@ -1355,9 +1352,7 @@ bool save_process(save_ctx_t *ctx) return success; } - if (!save_process_header(ctx)) return success; - - if (ctx->header_hash_validity == VALIDITY_INVALID) + if (!save_process_header(ctx) || ctx->header_hash_validity == VALIDITY_INVALID) { snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: savefile header is invalid!", __func__); return success; @@ -1717,10 +1712,7 @@ void save_free_contexts(save_ctx_t *ctx) { for(unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) { - for(unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) - { - if (&(ctx->data_remap_storage.segments[i].entries[j])) free(&(ctx->data_remap_storage.segments[i].entries[j])); - } + if (ctx->data_remap_storage.segments[i].entries) free(ctx->data_remap_storage.segments[i].entries); } } @@ -1740,10 +1732,7 @@ void save_free_contexts(save_ctx_t *ctx) { for(unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) { - for(unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) - { - if (&(ctx->meta_remap_storage.segments[i].entries[j])) free(&(ctx->meta_remap_storage.segments[i].entries[j])); - } + if (ctx->meta_remap_storage.segments[i].entries) free(ctx->meta_remap_storage.segments[i].entries); } } @@ -1846,14 +1835,14 @@ bool readCertsFromSystemSave() { if (loadedCerts) return true; - FRESULT fr; - FIL certSave; + FRESULT fr = FR_OK; + FIL *certSave = NULL; save_ctx_t *save_ctx = NULL; - allocation_table_storage_ctx_t fat_storage; - save_fs_list_entry_t entry; + allocation_table_storage_ctx_t fat_storage = {0}; + save_fs_list_entry_t entry = {0}; - u64 internalCertSize; + u64 internalCertSize = 0; u8 i, j; UINT br = 0; @@ -1863,7 +1852,14 @@ bool readCertsFromSystemSave() bool success = false, openSave = false, initSaveCtx = false; - fr = f_open(&certSave, BIS_CERT_SAVE_NAME, FA_READ | FA_OPEN_EXISTING); + certSave = calloc(1, sizeof(FIL)); + if (!certSave) + { + snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: unable to allocate memory for FatFs file descriptor!", __func__); + goto out; + } + + fr = f_open(certSave, BIS_CERT_SAVE_NAME, FA_READ | FA_OPEN_EXISTING); if (fr != FR_OK) { snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: failed to open \"%s\" savefile from BIS System partition! (%u)", __func__, BIS_CERT_SAVE_NAME, fr); @@ -1879,7 +1875,7 @@ bool readCertsFromSystemSave() goto out; } - save_ctx->file = &certSave; + save_ctx->file = certSave; save_ctx->tool_ctx.action = 0; initSaveCtx = save_process(save_ctx); @@ -1987,7 +1983,11 @@ out: free(save_ctx); } - if (openSave) f_close(&certSave); + if (certSave) + { + if (openSave) f_close(certSave); + free(certSave); + } return success; } diff --git a/source/save.h b/source/save.h index 102ca1c..23ae94c 100644 --- a/source/save.h +++ b/source/save.h @@ -161,7 +161,7 @@ struct remap_entry_ctx_t { struct remap_segment_ctx_t{ u64 offset; u64 length; - remap_entry_ctx_t *entries; + remap_entry_ctx_t **entries; u64 entry_count; }; diff --git a/source/ui.c b/source/ui.c index bc35e66..d314e39 100644 --- a/source/ui.c +++ b/source/ui.c @@ -4333,7 +4333,7 @@ UIResult uiProcess() { if (scrollAmount > 0) { - cursor = ((uiState == stateNspPatchDumpMenu && cursor == 3) ? 4 : 5); + cursor = ((uiState == stateNspPatchDumpMenu && cursor <= 3) ? 4 : 5); } else if (scrollAmount < 0) { diff --git a/source/util.c b/source/util.c index 6b8d2f2..ecc75ce 100644 --- a/source/util.c +++ b/source/util.c @@ -96,8 +96,8 @@ char strbuf[NAME_BUF_LEN] = {'\0'}; static const char *appLaunchPath = NULL; -FsStorage fatFsStorage; -static bool openBis = false, mountBisFatFs = false; +FsStorage fatFsStorage = {0}; +static FATFS *fatFsObj = NULL; u64 freeSpace = 0; char freeSpaceStr[32] = {'\0'}; @@ -353,33 +353,47 @@ static Result getGameCardStoragePartitionSize(u64 *out) bool mountSysEmmcPartition() { - FATFS fs; + Result result = 0; + FRESULT fr = FR_OK; - Result result = fsOpenBisStorage(&fatFsStorage, FsBisPartitionId_System); + result = fsOpenBisStorage(&fatFsStorage, FsBisPartitionId_System); if (R_FAILED(result)) { uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to open BIS System partition! (0x%08X)", __func__, result); return false; } - openBis = true; + fatFsObj = calloc(1, sizeof(FATFS)); + if (!fatFsObj) + { + uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to allocate memory for FatFs object!", __func__); + return false; + } - FRESULT fr = f_mount(&fs, BIS_MOUNT_NAME, 1); + fr = f_mount(fatFsObj, BIS_MOUNT_NAME, 1); if (fr != FR_OK) { uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to mount BIS System partition! (%u)", __func__, fr); return false; } - mountBisFatFs = true; - return true; } void unmountSysEmmcPartition() { - if (mountBisFatFs) f_unmount(BIS_MOUNT_NAME); - if (openBis) fsStorageClose(&fatFsStorage); + if (fatFsObj) + { + f_unmount(BIS_MOUNT_NAME); + free(fatFsObj); + fatFsObj = NULL; + } + + if (serviceIsActive(&(fatFsStorage.s))) + { + fsStorageClose(&fatFsStorage); + memset(&fatFsStorage, 0, sizeof(FsStorage)); + } } static bool isServiceRunning(const char *name)