diff --git a/Makefile b/Makefile index 4075925..d303560 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,11 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs .PHONY: all clean all: $(OUTPUTDIR)/$(TARGET).bin + @echo -n "Payload size is " + $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) + @echo $(BIN_SIZE) + @echo "Max size is 126296 Bytes." + @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi clean: @rm -rf $(BUILDDIR) @@ -57,11 +62,6 @@ clean: $(OUTPUTDIR)/$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf @mkdir -p "$(@D)" $(OBJCOPY) -S -O binary $< $@ - @echo -n "Payload size is " - $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) - @echo $(BIN_SIZE) - @echo "Max size is 126296 Bytes." - @if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ diff --git a/bdk/memory_map.h b/bdk/memory_map.h index 6e92668..84f4a6d 100644 --- a/bdk/memory_map.h +++ b/bdk/memory_map.h @@ -79,6 +79,7 @@ #define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. #define DRAM_MEM_HOLE_ADR 0xF6A00000 +#define NX_BIS_LOOKUP_ADR DRAM_MEM_HOLE_ADR #define DRAM_MEM_HOLE_SZ 0x8140000 /* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */ #define DRAM_START2 0xFEB40000 diff --git a/source/gfx/tui.c b/source/gfx/tui.c index e96a466..79be716 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -86,7 +86,7 @@ void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) gfx_con_setpos(cx, cy); // Update status bar. - tui_sbar(false); + // tui_sbar(false); } void *tui_do_menu(menu_t *menu) @@ -94,7 +94,7 @@ void *tui_do_menu(menu_t *menu) int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF; gfx_clear_partial_grey(0x1B, 0, 1256); - tui_sbar(true); + // tui_sbar(true); while (true) { @@ -203,7 +203,7 @@ void *tui_do_menu(menu_t *menu) gfx_con.fntsz = 16; gfx_clear_partial_grey(0x1B, 0, 1256); } - tui_sbar(false); + // tui_sbar(false); } return NULL; diff --git a/source/keys/keys.c b/source/keys/keys.c index d911af8..3d7fd05 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -25,6 +25,7 @@ #include "../hos/pkg2.h" #include "../hos/sept.h" #include +#include #include #include #include @@ -46,7 +47,6 @@ #include #include "key_sources.inl" -#include "save.h" #include @@ -123,14 +123,12 @@ void dump_keys() { sd_mount(); display_backlight_brightness(h_cfg.backlight, 1000); - gfx_clear_partial_grey(0x1B, 0, 1256); + gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); - tui_sbar(true); - _key_count = 0; _titlekey_count = 0; color_idx = 0; @@ -150,8 +148,14 @@ void dump_keys() { // Read package1. u8 *pkg1 = (u8 *)malloc(0x40000); - emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0); - emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0)) { + EPRINTF("Unable to set partition."); + goto out_wait; + } + if (!emummc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1)) { + EPRINTF("Unable to read pkg1."); + goto out_wait; + } const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); if (!pkg1_id) { EPRINTF("Unknown pkg1 version.\n Make sure you have the latest Lockpick_RCM.\n If a new firmware version just came out,\n Lockpick_RCM must be updated.\n Check Github for new release."); @@ -326,7 +330,10 @@ get_tsec: ; } // verify keyblob is not corrupt - emummc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); + if (!emummc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block)) { + EPRINTFARGS("Unable to read keyblob %x.", i); + continue; + } se_aes_key_set(10, keyblob_mac_key[i], 0x10); se_aes_cmac(10, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); if (memcmp(keyblob_block, keyblob_mac, 0x10) != 0) { @@ -381,7 +388,10 @@ get_tsec: ; u8 *pkg2 = NULL; pkg2_kip1_info_t *ki = NULL; - emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP); + if (!emummc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP)) { + EPRINTF("Unable to set partition."); + goto out_wait; + } // Parse eMMC GPT. LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &emmc_storage); @@ -596,7 +606,6 @@ pkg2_done: } path[24] = '/'; - nx_emmc_bis_cache_lock(true); while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { minerva_periodic_training(); memcpy(path + 25, fno.fname, 36); @@ -659,7 +668,6 @@ pkg2_done: } f_closedir(&dir); free(dec_header); - nx_emmc_bis_cache_lock(false); // derive eticket_rsa_kek and ssl_rsa_kek if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { @@ -732,7 +740,10 @@ get_titlekeys: u8 keypair[0x230] = {0}; - emummc_storage_read(&emmc_storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); + if (!emummc_storage_read(&emmc_storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer)) { + EPRINTF("Unable to read PRODINFO."); + goto dismount; + } se_aes_xts_crypt(1, 0, 0, 0, buffer, buffer, 0x4000, 1); @@ -777,9 +788,9 @@ get_titlekeys: se_rsa_key_set(0, N, 0x100, D, 0x100); - u32 br = buf_size; + u64 br = buf_size; u32 file_tkey_count = 0; - u64 total_br = 0; + u64 offset = 0; rights_ids = (u8 *)(MIXD_BUF_ALIGNED + 0x40000); titlekeys = (u8 *)(MIXD_BUF_ALIGNED + 0x80000); save_ctx = calloc(1, sizeof(save_ctx_t)); @@ -792,48 +803,52 @@ get_titlekeys: u32 pct = 0, last_pct = 0; save_ctx->file = &fp; - save_ctx->tool_ctx.action = 0; + save_ctx->action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - nx_emmc_bis_cluster_cache_init(); save_process_success = save_process(save_ctx); + if (!save_process_success) { EPRINTF("Failed to process e1 save."); f_close(&fp); goto dismount; } - char ticket_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket.bin"; - char ticket_list_bin_path[SAVE_FS_LIST_MAX_NAME_LENGTH] = "/ticket_list.bin"; - allocation_table_storage_ctx_t fat_storage; - save_fs_list_entry_t entry = {0, "", {0}, 0}; - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { + char ticket_bin_path[0x40] = "/ticket.bin"; + char ticket_list_bin_path[0x40] = "/ticket_list.bin"; + save_data_file_ctx_t ticket_file; + + if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket_list.bin in e1."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; minerva_periodic_training(); for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) + break; file_tkey_count++; } } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { + + if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket.bin in e1 save."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - total_br = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + + offset = 0; + br = buf_size; + + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; for (u32 j = 0; j < buf_size; j += 0x400) { pct = _titlekey_count * 100 / file_tkey_count; if (pct > last_pct && pct <= 100) { @@ -855,7 +870,6 @@ get_titlekeys: save_free_contexts(save_ctx); save_process_success = false; memset(save_ctx, 0, sizeof(save_ctx_t)); - memset(&fat_storage, 0, sizeof(allocation_table_storage_ctx_t)); gfx_con_setpos(0, save_y); TPRINTFARGS("\n%kCommon... ", colors[(color_idx++) % 6]); @@ -870,10 +884,9 @@ get_titlekeys: } save_ctx->file = &fp; - save_ctx->tool_ctx.action = 0; + save_ctx->action = 0; memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); - nx_emmc_bis_cluster_cache_init(); save_process_success = save_process(save_ctx); if (!save_process_success) { EPRINTF("Failed to process e2 save."); @@ -881,40 +894,41 @@ get_titlekeys: goto dismount; } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { + if (!save_open_file(save_ctx, &ticket_file, ticket_list_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket_list.bin in e2 save."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - total_br = 0; + offset = 0; file_tkey_count = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + br = buf_size; + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; minerva_periodic_training(); for (u32 j = 0; j < buf_size; j += 0x20) { - if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) break; + if (buffer[j] == 0xff && buffer[j+1] == 0xff && buffer[j+2] == 0xff && buffer[j+3] == 0xff) + break; file_tkey_count++; } } - if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { + + if (!save_open_file(save_ctx, &ticket_file, ticket_bin_path, OPEN_MODE_READ)) { EPRINTF("Unable to locate ticket.bin in e2 save."); f_close(&fp); goto dismount; } - save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); - - total_br = 0; + offset = 0; pct = 0; last_pct = 0; - while (br == buf_size && total_br < entry.value.save_file_info.length) { - br = save_allocation_table_storage_read(&fat_storage, buffer, total_br, buf_size); - if (buffer[0] == 0) break; - total_br += br; + br = buf_size; + while (br == buf_size && offset < ticket_file.size) { + if (!save_data_file_read(&ticket_file, &br, offset, buffer, buf_size) || buffer[0] == 0) + break; + offset += br; for (u32 j = 0; j < buf_size; j += 0x400) { pct = (_titlekey_count - common_titlekey_count) * 100 / file_tkey_count; if (pct > last_pct && pct <= 100) { @@ -947,7 +961,7 @@ get_titlekeys: TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); -dismount:; +dismount: ; if (save_process_success) save_free_contexts(save_ctx); @@ -1068,9 +1082,11 @@ out_wait: emummc_load_cfg(); // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; + emu_cfg.enabled = !h_cfg.emummc_force_disable; emummc_storage_end(&emmc_storage); - gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); + gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); btn_wait(); + gfx_clear_grey(0x1B); } static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { diff --git a/source/main.c b/source/main.c index 47aac1a..d654fad 100644 --- a/source/main.c +++ b/source/main.c @@ -265,6 +265,7 @@ out: void dump_sysnand() { h_cfg.emummc_force_disable = true; + emu_cfg.enabled = false; b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; dump_keys(); } @@ -273,7 +274,7 @@ void dump_emunand() { if (h_cfg.emummc_force_disable) return; - emu_cfg.enabled = 1; + emu_cfg.enabled = true; b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; dump_keys(); } @@ -366,11 +367,14 @@ void ipl_main() emummc_load_cfg(); // Ignore whether emummc is enabled. h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; + emu_cfg.enabled = !h_cfg.emummc_force_disable; if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) { - if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) + if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) { h_cfg.emummc_force_disable = true; + emu_cfg.enabled = false; + } dump_keys(); } diff --git a/source/storage/emummc.c b/source/storage/emummc.c index 71d62b8..5253edc 100644 --- a/source/storage/emummc.c +++ b/source/storage/emummc.c @@ -276,7 +276,7 @@ int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) emu_cfg.active_part = partition; if (!emu_cfg.enabled || h_cfg.emummc_force_disable) - sdmmc_storage_set_mmc_partition(storage, partition); + return sdmmc_storage_set_mmc_partition(storage, partition); else if (emu_cfg.sector) return 1; else diff --git a/source/storage/nx_emmc_bis.c b/source/storage/nx_emmc_bis.c index 109b666..ae8454d 100644 --- a/source/storage/nx_emmc_bis.c +++ b/source/storage/nx_emmc_bis.c @@ -21,12 +21,13 @@ #include +#include #include #include "../storage/nx_emmc.h" #include #include -#define MAX_CLUSTER_CACHE_ENTRIES 128 +#define MAX_CLUSTER_CACHE_ENTRIES 32768 #define CLUSTER_LOOKUP_EMPTY_ENTRY 0xFFFFFFFF #define XTS_CLUSTER_SIZE 0x4000 #define SECTORS_PER_CLUSTER 0x20 @@ -46,7 +47,8 @@ static u32 cluster_cache_end_index = 0; static emmc_part_t *system_part = NULL; static u8 *emmc_buffer = (u8 *)NX_BIS_CACHE_ADDR; static cluster_cache_t *cluster_cache = (cluster_cache_t *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE); -static u32 *cluster_lookup = (u32 *)(NX_BIS_CACHE_ADDR + XTS_CLUSTER_SIZE + MAX_CLUSTER_CACHE_ENTRIES * sizeof(cluster_cache_t)); +static u32 *cluster_lookup_buf = NULL; +static u32 *cluster_lookup = NULL; static bool lock_cluster_cache = false; static void _gf256_mul_x_le(void *block) @@ -125,6 +127,7 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) static u32 prev_cluster = -1; static u32 prev_sector = 0; static u8 tweak[0x10]; + u8 cache_tweak[0x10]; u32 tweak_exp = 0; bool regen_tweak = true; @@ -144,10 +147,8 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) } // Only cache single-sector reads as these are most likely to be repeated, such as boot block and FAT directory tables. - if (count == 1 && - !lock_cluster_cache && - cluster_cache_end_index < MAX_CLUSTER_CACHE_ENTRIES && - cluster_lookup_index == CLUSTER_LOOKUP_EMPTY_ENTRY) + if (!lock_cluster_cache && + cluster_cache_end_index < MAX_CLUSTER_CACHE_ENTRIES) { cluster_cache[cluster_cache_end_index].cluster_num = cluster; cluster_cache[cluster_cache_end_index].visit_count = 1; @@ -157,14 +158,12 @@ static int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff) // Read and decrypt the whole cluster the sector resides in. if (!nx_emmc_part_read(&emmc_storage, system_part, aligned_sector, SECTORS_PER_CLUSTER, emmc_buffer)) return 1; // R/W error. - if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE)) + if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, emmc_buffer, emmc_buffer, XTS_CLUSTER_SIZE)) return 1; // R/W error. // Copy to cluster cache. memcpy(cluster_cache[cluster_cache_end_index].cluster, emmc_buffer, XTS_CLUSTER_SIZE); - memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE); - prev_cluster = -1; - prev_sector = 0; + memcpy(buff, emmc_buffer + sector_index_in_cluster * NX_EMMC_BLOCKSIZE, NX_EMMC_BLOCKSIZE * count); cluster_cache_end_index++; return 0; // Success. } @@ -218,8 +217,26 @@ int nx_emmc_bis_read(u32 sector, u32 count, void *buff) void nx_emmc_bis_cluster_cache_init() { + u32 cluster_lookup_size = (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup); + + if (cluster_lookup_buf) + free(cluster_lookup_buf); + + // Check if carveout protected, in case of old hwinit (pre 4.0.0) chainload. + *(vu32 *)NX_BIS_LOOKUP_ADR = 0; + if (*(vu32 *)NX_BIS_LOOKUP_ADR != 0) + { + cluster_lookup_buf = (u32 *)malloc(cluster_lookup_size + 0x2000); + cluster_lookup = (u32 *)ALIGN((u32)cluster_lookup_buf, 0x1000); + } + else + { + cluster_lookup_buf = NULL; + cluster_lookup = (u32 *)NX_BIS_LOOKUP_ADR; + } + // Clear cluster lookup table and reset end index. - memset(cluster_lookup, -1, (system_part->lba_end - system_part->lba_start + 1) / SECTORS_PER_CLUSTER * sizeof(*cluster_lookup)); + memset(cluster_lookup, -1, cluster_lookup_size); cluster_cache_end_index = 0; lock_cluster_cache = false; }