From b40e4c73b2d84eb68811ea8d64dcb58088518349 Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Thu, 2 Jun 2016 16:13:37 -0400 Subject: [PATCH] Loader work Now loader doesn't care what bytecode it's running since it loads from cache files generated during the bootup stage. It's now back up to sane/tolerably slow speeds on boot. Still a few kinks to iron out, though. --- external/loader/source/interp.h | 2 +- external/loader/source/patcher.c | 11 +--- source/interp.c | 94 ++++++++++++++++---------------- source/patch/aadowngrade.c | 8 --- source/patch/memexec.c | 14 ----- source/patch/prot.c | 10 ---- source/patch/sig.c | 10 ---- source/patch/unitinfo.c | 13 ----- source/patch_format.h | 3 + source/patcher.c | 64 +++++++++++++--------- 10 files changed, 88 insertions(+), 141 deletions(-) delete mode 100644 source/patch/aadowngrade.c delete mode 100644 source/patch/memexec.c delete mode 100644 source/patch/prot.c delete mode 100644 source/patch/sig.c delete mode 100644 source/patch/unitinfo.c diff --git a/external/loader/source/interp.h b/external/loader/source/interp.h index 06849dd..c34412e 100644 --- a/external/loader/source/interp.h +++ b/external/loader/source/interp.h @@ -1,6 +1,6 @@ #ifndef __INTERP_H #define __INTERP_H -int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len); +int execb(uint64_t tid, uint8_t* search_mem, uint32_t search_len); #endif diff --git a/external/loader/source/patcher.c b/external/loader/source/patcher.c index 8a72b2b..55c7f45 100644 --- a/external/loader/source/patcher.c +++ b/external/loader/source/patcher.c @@ -356,16 +356,7 @@ patch_text(u64 progId, u8* text, u32 size, u32 orig_size) if (progId == 0x0004013000008002LL) adjust_cpu_settings(progId, text, orig_size); - execb(PATH_PATCHES "/block_nim_update.vco", progId, text, orig_size); - execb(PATH_PATCHES "/block_eshop_update.vco", progId, text, orig_size); - execb(PATH_PATCHES "/block_cart_update.vco", progId, text, orig_size); - execb(PATH_PATCHES "/errdisp.vco", progId, text, orig_size); - execb(PATH_PATCHES "/friends_ver.vco", progId, text, orig_size); - execb(PATH_PATCHES "/mset_str.vco", progId, text, orig_size); -// execb(PATH_PATCHES "/ns_force_menu.vco", progId, text, orig_size); - execb(PATH_PATCHES "/regionfree.vco", progId, text, orig_size); - execb(PATH_PATCHES "/secinfo_sigs.vco", progId, text, orig_size); - execb(PATH_PATCHES "/ro_sigs.vco", progId, text, orig_size); + execb(progId, text, orig_size); language_emu(progId, text, orig_size); } diff --git a/source/interp.c b/source/interp.c index 462d265..b20e0e9 100644 --- a/source/interp.c +++ b/source/interp.c @@ -248,8 +248,10 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { break; case OP_NEXT: bytecode = code + 1; +#ifndef LOADER set_mode = 3; current_mode = &modes[set_mode]; +#endif offset = 0; test_was_false = 0; code = bytecode; @@ -286,31 +288,37 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) { } #ifdef LOADER -int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len) { +int execb(uint64_t tid, uint8_t* search_mem, uint32_t search_len) { #else int execb(char* filename) { #endif uint32_t patch_len; - struct system_patch* patch; #ifdef LOADER - log(" check "); - log(filename); - log("\n"); + char cache_path[] = PATH_LOADER_CACHE "/0000000000000000"; + int len = strlen(cache_path) - 16; - uint8_t patch_dat2[MAX_PATCHSIZE]; - uint8_t *patch_dat = patch_dat2; + uint8_t* title_buf = (uint8_t*)&tid; - patch = (struct system_patch*)patch_dat; + for(int j = 0; j < 8; j++) { + cache_path[len+(j*2)] = ("0123456789ABCDEF")[(title_buf[j] >> 4) & 0x0f]; + cache_path[len+(j*2)+1] = ("0123456789ABCDEF")[ title_buf[j] & 0x0f]; + } + + static uint8_t patch_dat[MAX_PATCHSIZE]; Handle file; u32 total; // Open file. - if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, filename, FS_OPEN_READ))) { + if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, cache_path, FS_OPEN_READ))) { // Failed to open. - return 1; + return 0; // No patches. } + log(" patch: "); + log(cache_path); + log("\n"); + u64 file_size; if (!R_SUCCEEDED(FSFILE_GetSize(file, &file_size))) { @@ -341,45 +349,12 @@ int execb(char* filename) { modes[18].memory = search_mem; modes[18].size = search_len; - // Check magic. - if (memcmp(patch->magic, "AIDA", 4)) { - log(" magic wrong\n"); - - return 1; // Incorrect patch magic. - } - - // Check TID supported. - if (patch->titles == 0) { - return 0; // Not an error - this patch isn't meant for us. - } - - log(" checking tid\n"); - - uint8_t* title_buf = patch_dat + sizeof(struct system_patch); - - int apply = 0; - - for(uint32_t i=0; i < patch->titles; i++, title_buf += 8) { - if(!memcmp(title_buf, (uint8_t*)&tid, 8)) { - // Applicable patch found. - log(" applicable\n"); - apply = 1; - break; - } - } - - if (!apply) { - // Not meant for us. - return 0; - } - - // Patch is relevant to us, so we'll apply it. - log(" exec\n"); - uint8_t* patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8); - patch_len = patch->size; + uint8_t* patch_mem = (uint8_t*)patch_dat; + patch_len = file_size; #else + struct system_patch* patch; uint8_t* patch_mem; // Read patch to scrap memory. @@ -396,17 +371,40 @@ int execb(char* filename) { return 1; } + patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8); + patch_len = patch->size; + if (patch->titles != 0) { // Not an error, per se, but it means this patch is meant for loader, not us. // Patches intended for use during boot will always be applied to zero titles. // We should generate a cache for loader in a file intended for titleid. + uint8_t* title_buf = (uint8_t*)patch + sizeof(struct system_patch); + + for(uint32_t i=0; i < patch->titles; i++, title_buf += 8) { + // FIXME - This is outputting once per boot. We need to detect and nuke the cache. + char cache_path[] = PATH_LOADER_CACHE "/0000000000000000"; + int len = strlen(cache_path) - 16; + + for(int j = 0; j < 8; j++) { + cache_path[len+(j*2)] = ("0123456789ABCDEF")[(title_buf[j] >> 4) & 0x0f]; + cache_path[len+(j*2)+1] = ("0123456789ABCDEF")[ title_buf[j] & 0x0f]; + } + + char reset = 0xFF; + + FILE* cache = fopen(cache_path, "w"); + fseek(cache, 0, SEEK_END); + fwrite(patch_mem, 1, patch_len, cache); + fwrite(&reset, 1, 1, cache); + fclose(cache); + // Add to cache. + } + return 0; } fprintf(stderr, "Patch: %s\n", patch->name); - patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8); - patch_len = patch->size; #endif return exec_bytecode(patch_mem, patch_len, 0); } diff --git a/source/patch/aadowngrade.c b/source/patch/aadowngrade.c deleted file mode 100644 index f7aa638..0000000 --- a/source/patch/aadowngrade.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "patch_file.h" - -PATCH(aadowngrade) -{ - execb(PATH_PATCHES "/aadowngrade.vco"); - - return 0; -} diff --git a/source/patch/memexec.c b/source/patch/memexec.c deleted file mode 100644 index 4fc0b33..0000000 --- a/source/patch/memexec.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "patch_file.h" - -// This patch clears MPU settings which lock down memory -// execution from userland. You should NOT enable this -// unless you know you need it, because it makes an obvious -// behavioral change that can be used maliciously and/or to -// detect CFW use rather easily. - -PATCH(memexec) -{ - execb(PATH_PATCHES "/memexec.vco"); - - return 0; -} diff --git a/source/patch/prot.c b/source/patch/prot.c deleted file mode 100644 index 47ebcf3..0000000 --- a/source/patch/prot.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "patch_file.h" - -// This patch applies the FIRM protection code needed for safe a9lh usage. - -PATCH(firmprot) -{ - execb(PATH_PATCHES "/prot.vco"); - - return 0; -} diff --git a/source/patch/sig.c b/source/patch/sig.c deleted file mode 100644 index dbc46e5..0000000 --- a/source/patch/sig.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "patch_file.h" - -// This patch is responsible for fixing signature checks for the firmware. - -PATCH(signatures) -{ - execb(PATH_PATCHES "/sig.vco"); - - return 0; -} diff --git a/source/patch/unitinfo.c b/source/patch/unitinfo.c deleted file mode 100644 index 9649449..0000000 --- a/source/patch/unitinfo.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "patch_file.h" - -// This patch makes the console think it is a developer unit. -// Note that this is generally invasive and not useful to users; -// usually the ErrDisp patch in loader should be good enough for -// debugging crashes. - -PATCH(unitinfo) -{ - execb(PATH_PATCHES "/unitinfo.vco"); - - return 0; -} diff --git a/source/patch_format.h b/source/patch_format.h index 9c91864..e699071 100644 --- a/source/patch_format.h +++ b/source/patch_format.h @@ -42,6 +42,9 @@ #define PATH_FIRMWARES PATH_CFW "/lib/firmware" // Firmware folder. #define PATH_MODULES PATH_CFW "/lib/module" // Sysmodule location #define PATH_SERVICES PATH_CFW "/lib/service" // Service code location. + +#define PATH_LOADER_CACHE PATH_CFW "/lib/loader" // Cached patch bytecode for loader. + #define PATH_TEMP \ PATH_CFW "/tmp" // Files that are transient (user can delete them and they // will be regenerated) diff --git a/source/patcher.c b/source/patcher.c index a93332e..4f2d0ad 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -4,18 +4,14 @@ #include "firm/firm.h" #include "config.h" #include "common.h" +#include "interp.h" // TODO - Basically all this needs to move to patcher programs. uint32_t wait_key(); -extern int patch_signatures(); -extern int patch_firmprot(); extern int patch_services(); extern int patch_modules(); -extern int patch_aadowngrade(); -extern int patch_memexec(); -extern int patch_unitinfo(); extern int doing_autoboot; @@ -32,25 +28,21 @@ wait() int patch_firm_all() { - // Use builtin signature patcher? - - if (config.options[OPTION_SIGPATCH]) { - // TODO - Patch menu. This is okay-ish for now. - // if(execp(PATH_PATCHES "/signatures.vco")) { - if (patch_signatures()) { - abort("Fatal. Sigpatch has failed."); - } - - wait(); - } - - if (config.options[OPTION_FIRMPROT]) { - if (patch_firmprot()) { - abort("Fatal. Firmprot has failed."); - } - - wait(); - } + // Remove cache + f_unlink(PATH_LOADER_CACHE); + f_mkdir(PATH_LOADER_CACHE); + + // Loader only uses TID cache bytecode, so run through these. + execb(PATH_PATCHES "/block_nim_update.vco"); + execb(PATH_PATCHES "/block_eshop_update.vco"); + execb(PATH_PATCHES "/block_cart_update.vco"); + execb(PATH_PATCHES "/errdisp.vco"); + execb(PATH_PATCHES "/friends_ver.vco"); + execb(PATH_PATCHES "/mset_str.vco"); +// execb(PATH_PATCHES "/ns_force_menu.vco"); + execb(PATH_PATCHES "/regionfree.vco"); + execb(PATH_PATCHES "/secinfo_sigs.vco"); + execb(PATH_PATCHES "/ro_sigs.vco"); // Replace loader? if (config.options[OPTION_LOADER]) { @@ -77,8 +69,26 @@ patch_firm_all() wait(); } + // Use builtin signature patcher? + if (config.options[OPTION_SIGPATCH]) { + // TODO - Patch menu. This is okay-ish for now. + if(execb(PATH_PATCHES "/sig.vco")) { + abort("Fatal. Sigpatch has failed."); + } + + wait(); + } + + if (config.options[OPTION_FIRMPROT]) { + if(execb(PATH_PATCHES "/prot.vco")) { + abort("Fatal. Firmprot has failed."); + } + + wait(); + } + if (config.options[OPTION_AADOWNGRADE]) { - if (patch_aadowngrade()) { + if(execb(PATH_PATCHES "/aadowngrade.vco")) { abort("Anti-anti-downgrade patch failed."); } @@ -86,7 +96,7 @@ patch_firm_all() } if (config.options[OPTION_UNITINFO]) { - if (patch_unitinfo()) { + if(execb(PATH_PATCHES "/unitinfo.vco")) { abort("UNITINFO patch failed."); } @@ -94,7 +104,7 @@ patch_firm_all() } if (config.options[OPTION_MEMEXEC]) { - if (patch_memexec()) { + if(execb(PATH_PATCHES "/memexec.vco")) { abort("MPU execution patch failed."); } -- 2.39.5