Improve emummc semantics and error checking

This commit is contained in:
shchmue 2020-07-02 09:42:49 -06:00
parent bd09f5418d
commit 5ed601dd4b
7 changed files with 114 additions and 76 deletions

View file

@ -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 $@

View file

@ -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

View file

@ -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;

View file

@ -25,6 +25,7 @@
#include "../hos/pkg2.h"
#include "../hos/sept.h"
#include <libs/fatfs/ff.h>
#include <libs/save/save.h>
#include <mem/heap.h>
#include <mem/mc.h>
#include <mem/minerva.h>
@ -46,7 +47,6 @@
#include <utils/util.h>
#include "key_sources.inl"
#include "save.h"
#include <string.h>
@ -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) {

View file

@ -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();
}

View file

@ -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

View file

@ -21,12 +21,13 @@
#include <memory_map.h>
#include <mem/heap.h>
#include <sec/se.h>
#include "../storage/nx_emmc.h"
#include <storage/sdmmc.h>
#include <utils/types.h>
#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;
}