From: chaoskagami Date: Mon, 5 Sep 2016 15:37:30 +0000 (-0400) Subject: Correct interpreter for refactor X-Git-Tag: v0.3.0~18 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=7b2a30ddb4ca7fb812a3df79d3feb95210b1755e;p=corbenik%2Fcorbenik.git Correct interpreter for refactor --- diff --git a/contrib/2x-firmprot.pco b/contrib/2x-firmprot.pco index 23d0c06..ebe2057 100644 --- a/contrib/2x-firmprot.pco +++ b/contrib/2x-firmprot.pco @@ -1,5 +1,6 @@ # $name FIRM Protection (2.x) # $desc Patches FIRM writes in 2.x FIRMs. +# $title 0004013800000002 0004013800000003 0004013820000003 # $ver 01 # $uuid 0004 @@ -12,7 +13,7 @@ # This is also identical to the safemode patch for FIRM protection # if you're astute. Corbenik doesn't support that, though. -rel native_p9 +rel section2 find 041E1DDB abortnf diff --git a/contrib/svc_permission_chk_dis.pco b/contrib/svc_permission_chk_dis.pco index 7a60f53..de2767f 100644 --- a/contrib/svc_permission_chk_dis.pco +++ b/contrib/svc_permission_chk_dis.pco @@ -1,5 +1,6 @@ # $name Disable SVC Permission Checks # $desc Disables permission checks on SVC calls, so all titles have permission to use all SVC calls. This is a potential security hazard, especially with svcBackdoor Fixup. +# $title 0004013800000002 0004013820000002 # $ver 01 # $uuid 0002 @@ -7,7 +8,7 @@ # Original patch by Subv. Conversion by @Wolfvak. -rel native_s1 +rel section1 find EAFFFF0A abortnf diff --git a/host/bytecode_asm.py b/host/bytecode_asm.py index d623aee..efcb2ca 100755 --- a/host/bytecode_asm.py +++ b/host/bytecode_asm.py @@ -26,32 +26,16 @@ def syn_err(x): def rel_name(x): return { - 'native' : "00", - 'agb' : "01", - 'twl' : "02", - - 'native_p9': "03", - 'agb_p9' : "04", - 'twl_p9' : "05", - - 'native_s0': "06", - 'native_s1': "07", - 'native_s2': "08", - 'native_s3': "09", - - 'agb_s0' : "0A", - 'agb_s1' : "0B", - 'agb_s2' : "0C", - 'agb_s3' : "0D", - - 'twl_s0' : "0E", - 'twl_s1' : "0F", - 'twl_s2' : "10", - 'twl_s3' : "11", - - 'exe_text' : "12", - 'exe_data' : "13", - 'exe_ro' : "14", + 'firm' : "00", + + 'section0' : "01", + 'section1' : "02", + 'section2' : "03", + 'section3' : "04", + + 'exe_text' : "00", + 'exe_data' : "01", + 'exe_ro' : "02", }.get(x, "-1") name = "NO NAME" diff --git a/include/interp.h b/include/interp.h index 88ade2d..b14059d 100644 --- a/include/interp.h +++ b/include/interp.h @@ -1,14 +1,22 @@ #ifndef __INTERP_H #define __INTERP_H -/* Loads and prepares/executes/caches a bytecode patch. +/* Loads and caches a bytecode patch. * - * \param filename Filename of patch to load and parse. - * \param build_cache If zero, execute the file. Otherwise, cache the file for later. + * \param filename Filename of patch to load and cache * \return Zero on success. */ -int execb(const char *filename, int build_cache); +int cache_patch(const char *filename); + +/* Loads and executes cached bytecode. + * + * \param tid Title ID to patch. + * \param firm Firmware structure. + * \return Zero on success. + */ + +int execb(uint64_t tid, firm_h *firm); /* Low level function to actually execute the bytecode. Do not call directly. * @@ -19,6 +27,6 @@ int execb(const char *filename, int build_cache); * \param ver Version of Exefs being patched. Only used in loader (subject to change) * \param debug Whether to output debug information from each step of the VM to stderr */ -int exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_size, uint16_t ver, int debug); +int exec_bytecode(uint8_t *bytecode, uint32_t len, uint16_t ver, int debug); #endif diff --git a/include/patcher.h b/include/patcher.h index f79e531..40e09d8 100644 --- a/include/patcher.h +++ b/include/patcher.h @@ -5,7 +5,7 @@ * * \return zero on success */ -int patch_firm_all(); +int patch_firm_all(uint64_t tid, firm_h* firm); /* Generates patch cache for boot/loader for the current configuration. * diff --git a/patch/aadowngrade.pco b/patch/aadowngrade.pco index 4d86975..6a15d3b 100644 --- a/patch/aadowngrade.pco +++ b/patch/aadowngrade.pco @@ -1,5 +1,6 @@ # $name Title Downgrade Fix (11.0 NFIRM) # $desc Removes added checks to prevent downgrade of system titles (in 11.0 NATIVE_FIRM.) Do not use on any other native_firm. +# $title 0004013800000002 0004013820000002 # $ver 09 # $uuid 00 # $flags require @@ -8,8 +9,8 @@ # Anti-anti-downgrade fix. -# Relative to process9. -rel native_p9 +# Relative to arm9 segment +rel section2 # We want to patch the fifth byte of this pattern. find 890a814202D2 diff --git a/patch/agb_biosscreen.pco b/patch/agb_biosscreen.pco index 9136487..d6cf2fd 100644 --- a/patch/agb_biosscreen.pco +++ b/patch/agb_biosscreen.pco @@ -1,5 +1,6 @@ # $name AGB Bootscreen # $desc Force usage of GBA bios in AGB_FIRM. Games must pass the Nintendo logo check. If you see garbage instead of Nintendo, turn this off. +# $title 0004013800000202 0004013820000202 # $ver 09 # $uuid 35 @@ -9,7 +10,7 @@ # so games have to pass the Nintendo logo check. If # they don't, they'll fail like on a real GBA. -rel agb +rel firm # ############################# diff --git a/patch/agb_sig.pco b/patch/agb_sig.pco index 49ea99d..5fcdb6d 100644 --- a/patch/agb_sig.pco +++ b/patch/agb_sig.pco @@ -1,11 +1,12 @@ # $name AGB Signature Fix # $desc Patches signatures in AGB_FIRM. This allows booting unsigned GBA games. +# $title 0004013800000202 0004013820000202 # $ver 09 # $uuid 39 # TODO - Use proper section. -rel agb +rel firm # ############################# diff --git a/patch/memexec.pco b/patch/memexec.pco index 76702bb..28df477 100644 --- a/patch/memexec.pco +++ b/patch/memexec.pco @@ -1,11 +1,12 @@ # $name ARM11 XN Disable # $desc Disables the XN bit on the ARM11 kernel to allow executing code from memory. May be a security hazard. +# $title 0004013800000002 0004013820000002 # $ver 09 # $uuid 06 # $flags devmode # 0: Relative to NATIVE_FIRM, section index [1] -rel native_s1 +rel section1 # 1: Find this byte string. find 9705000015E40000 diff --git a/patch/prot.pco b/patch/prot.pco index 707fa15..c84e157 100644 --- a/patch/prot.pco +++ b/patch/prot.pco @@ -1,12 +1,13 @@ # $name FIRM Protection # $desc Prevents writing FIRM to the NAND during updates. Enable this if booting sysNAND. +# $title 0004013800000002 0004013820000002 # $ver 09 # $uuid 08 # $flags require # Status: Untested, but theoretically fine (Next system update I'll either brick or I won't.) -rel native_p9 +rel section2 # String: 'exe:' find 6578653a abortnf diff --git a/patch/sig.pco b/patch/sig.pco index 929fc17..37c5090 100644 --- a/patch/sig.pco +++ b/patch/sig.pco @@ -1,5 +1,6 @@ # $name Signature Fix # $desc Disables signature checks on all content. +# $title 0004013800000002 0004013820000002 # $ver 09 # $uuid 0c # $flags require @@ -9,7 +10,7 @@ # Signature patch. # Relative to exefs. -rel native_p9 +rel section2 # Pattern one. find c01c76e7 diff --git a/patch/twl_fix.pco b/patch/twl_fix.pco index ff66f5e..952e9c6 100644 --- a/patch/twl_fix.pco +++ b/patch/twl_fix.pco @@ -1,5 +1,6 @@ -# $name TWL Patches +# $name TWL Patches (2/2 - o3ds) # $desc Disables a large number of validity checks on DS, DSi and DSiware titles. +# $title 0004013800000102 # $ver 09 # $uuid 34 @@ -8,53 +9,11 @@ # pastebin # Relative to twl_firm (0) -rel twl - -########################################### -# New3ds - -n3ds -jmpne old - -# Disable main signature checks (1) -seek 00165D64 -set 00204EB070BD - -# Patch RSA function to not report invalid signatures (5) -seek 0017474A -set 0120 - -# Disable header Nintendo logo check (not generally needed) (7) -seek 0017553E -set 00200000 - -# Disable whitelist check (9) -seek 001756A0 -set 00200000 - -# Disable cartridge blacklist check (mostly, if not entirely, demo carts) (11) -seek 00175A8E -set 01200000 - -# Disable save type check (13) -seek 00175A9A -set 01200000 - -# Disable DSi cartridge save exploit check (15) -seek 00175AA6 -set 01200000 - -# Stub function commonly used to compare SHA hashes to always succeed (17) -seek 00175B92 -set 01207047 - -jmp end +rel firm ########################################### # Old3ds -old: - # Disable main signature checks (20) seek 001650C0 set 00204EB070BD @@ -87,4 +46,3 @@ set 01200000 seek 00174E56 set 01207047 -end: diff --git a/patch/twl_fix_o3ds.pco b/patch/twl_fix_o3ds.pco new file mode 100644 index 0000000..a65a920 --- /dev/null +++ b/patch/twl_fix_o3ds.pco @@ -0,0 +1,48 @@ +# $name TWL Patches (1/2 - new3ds) +# $desc Disables a large number of validity checks on DS, DSi and DSiware titles. +# $title 0004013820000102 +# $ver 09 +# $uuid 34 + +# TODO - Make dynamic. Not that hard, but some +# fixes need more context bytes than on Steveice10's +# pastebin + +# Relative to twl_firm (0) +rel firm + +########################################### +# New3ds + +# Disable main signature checks (1) +seek 00165D64 +set 00204EB070BD + +# Patch RSA function to not report invalid signatures (5) +seek 0017474A +set 0120 + +# Disable header Nintendo logo check (not generally needed) (7) +seek 0017553E +set 00200000 + +# Disable whitelist check (9) +seek 001756A0 +set 00200000 + +# Disable cartridge blacklist check (mostly, if not entirely, demo carts) (11) +seek 00175A8E +set 01200000 + +# Disable save type check (13) +seek 00175A9A +set 01200000 + +# Disable DSi cartridge save exploit check (15) +seek 00175AA6 +set 01200000 + +# Stub function commonly used to compare SHA hashes to always succeed (17) +seek 00175B92 +set 01207047 + diff --git a/patch/unitinfo.pco b/patch/unitinfo.pco index e5cb189..04a1714 100644 --- a/patch/unitinfo.pco +++ b/patch/unitinfo.pco @@ -1,12 +1,13 @@ # $name Developer UNITINFO # $desc Pretend to be a developer console. For the average user, loader ErrDisp is enough. This will break eShop/online access as long as it is enabled. +# $title 0004013800000002 0004013820000002 # $ver 09 # $uuid 0d # $flags devmode # Status: untested, but should work -rel native_s2 +rel section2 find 0110A013 abortnf diff --git a/source/firm/firm.c b/source/firm/firm.c index 8b01b10..376d3b1 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -62,7 +62,6 @@ load_firm(const char *path) if (sig->console == console_n3ds) { if(dec_k9l(firm)) { - panic("K9L?"); free(firm); free(mem); return NULL; @@ -71,7 +70,6 @@ load_firm(const char *path) patch_entry(firm, sig->type); if (patch_section_keys(firm, sig->k9l)) { - panic("Section keys?"); free(firm); free(mem); return NULL; @@ -87,19 +85,29 @@ load_firm(const char *path) return firm; } - int boot_cfw(char* firm_path) { firm_h* firm = load_firm(firm_path); if (firm == NULL) - panic("Invalid FIRM?"); + return 1; + + struct firm_signature *sig = get_firm_info(firm); + + uint64_t tid = 0x0004013800000002LLu; + + if (sig->console == console_n3ds) + tid += 0x20000000LLu; + + tid += sig->type * 0x100LLu; + + free(sig); -// if (patch_firm_all(firm) != 0) -// return 1; + if (patch_firm_all(tid, firm) != 0) + return 1; - firmlaunch(firm); + firmlaunch(firm); // <- should NOT return if all is well - return 0; + return 1; } diff --git a/source/firm/firmlaunch.c b/source/firm/firmlaunch.c index 62a22f6..f115ffd 100644 --- a/source/firm/firmlaunch.c +++ b/source/firm/firmlaunch.c @@ -17,6 +17,8 @@ void firmlaunch(firm_h* firm) { memmove((void *)section->address, (void *)((uint8_t*)firm + section->offset), section->size); } + free(firm); // Really, no point in this. Why not, though. + fflush(stderr); // Flush logs if need be before unmount. fumount(); // Unmount SD. diff --git a/source/interpreter.c b/source/interpreter.c index 0602309..2d99329 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -69,59 +69,13 @@ int init_bytecode = 0; #ifndef LOADER extern int is_n3ds; static const char hexDigits[] = "0123456789ABCDEF"; -#else -int is_n3ds = 1; // TODO - We don't really need to care, but it should still work from loader -#endif - -#define STACK_SIZE 4096 -#ifdef LOADER - static uint8_t stack_glob[STACK_SIZE]; -#else - static uint8_t *stack_glob = NULL; - firm_h* firm_patch; #endif int -exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_size, uint16_t ver, int debug) +exec_bytecode(uint8_t *bytecode, uint32_t len, uint16_t ver, int debug) { - if (!init_bytecode) { -#ifndef LOADER - modes[0].memory = (uint8_t *)firm_patch; - modes[0].size = firm_patch->section[0].size + firm_patch->section[1].size + sizeof(firm_h) + - firm_patch->section[2].size + firm_patch->section[3].size; // NATIVE_FIRM - -#if 0 - // FIRM Process9 (This is also the default mode.) - modes[1].memory = (uint8_t *)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; - modes[1].size = firm_p9_exefs->fileHeaders[0].size; -#endif - - // FIRM Sect 0 - modes[2].memory = (uint8_t *)firm_patch + firm_patch->section[0].offset; - modes[2].size = firm_patch->section[0].size; - // FIRM Sect 1 - modes[3].memory = (uint8_t *)firm_patch + firm_patch->section[1].offset; - modes[3].size = firm_patch->section[1].size; - // FIRM Sect 2 - modes[4].memory = (uint8_t *)firm_patch + firm_patch->section[2].offset; - modes[4].size = firm_patch->section[2].size; - // FIRM Sect 3 - modes[5].memory = (uint8_t *)firm_patch + firm_patch->section[3].offset; - modes[5].size = firm_patch->section[3].size; -#endif - - init_bytecode = 1; - } + uint32_t set_mode = 0; - memset(stack, 0, stack_size); // Clear stack. - - _UNUSED uint32_t top = stack_size - 1; - -#ifdef LOADER - uint32_t set_mode = 18; -#else - uint32_t set_mode = 3; -#endif struct mode *current_mode = &modes[set_mode]; uint32_t offset = 0, new_offset = 0; @@ -395,13 +349,6 @@ exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_si eq = !eq; code += 2; break; - case OP_N3DS: - if (debug) { - log("n3ds\n"); - } - code++; - eq = is_n3ds; - break; case OP_SEEK: // Jump to offset if greater than or equal code++; offset = (uint32_t)(code[0] + (code[1] << 8) + (code[2] << 16) + (code[3] << 24)); @@ -469,12 +416,9 @@ exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_si } found = gt = lt = eq = 0; - memset(stack, 0, stack_size); // Clear stack. - top = stack_size - 1; - bytecode = code + 1; #ifndef LOADER - set_mode = 3; + set_mode = 0; current_mode = &modes[set_mode]; #else set_mode = 18; @@ -555,7 +499,7 @@ execb(uint64_t tid, uint16_t ver, uint8_t *text_mem, uint32_t text_len, uint8_t { #else int -execb(const char *filename, int build_cache) +execb(uint64_t tid, firm_h* firm_patch) { uint16_t ver = 0; // FIXME - Provide native_firm version #endif @@ -607,22 +551,88 @@ execb(const char *filename, int build_cache) FSFILE_Close(file); // Done reading in. // Set memory. - modes[18].memory = text_mem; - modes[18].size = text_len; + modes[0].memory = text_mem; + modes[0].size = text_len; // Set memory. - modes[19].memory = data_mem; - modes[19].size = data_len; + modes[1].memory = data_mem; + modes[1].size = data_len; // Set memory. - modes[20].memory = ro_mem; - modes[20].size = ro_len; + modes[2].memory = ro_mem; + modes[2].size = ro_len; log(" exec\n"); uint8_t *patch_mem = (uint8_t *)patch_dat; patch_len = file_size; #else + // The WHOLE firm. + modes[0].memory = (uint8_t *)firm_patch; + modes[0].size = firm_patch->section[0].size + firm_patch->section[1].size + sizeof(firm_h) + + firm_patch->section[2].size + firm_patch->section[3].size; + + // FIRM Sect 0 + modes[1].memory = (uint8_t *)firm_patch + firm_patch->section[0].offset; + modes[1].size = firm_patch->section[0].size; + + // FIRM Sect 1 + modes[2].memory = (uint8_t *)firm_patch + firm_patch->section[1].offset; + modes[2].size = firm_patch->section[1].size; + + // FIRM Sect 2 + modes[3].memory = (uint8_t *)firm_patch + firm_patch->section[2].offset; + modes[3].size = firm_patch->section[2].size; + + // FIRM Sect 3 + modes[4].memory = (uint8_t *)firm_patch + firm_patch->section[3].offset; + modes[4].size = firm_patch->section[3].size; + + char cache_path[] = PATH_LOADER_CACHE "/0000000000000000"; + + uint64_t title = tid; + + uint32_t tlen = strlen(cache_path) - 1; + int j = 16; + while (j--) { + cache_path[tlen--] = hexDigits[title & 0xF]; + title >>= 4; + } + + // Read patch to scrap memory. + + FILE *f = fopen(cache_path, "r"); + if (!f) { + // File wasn't found. The user didn't enable anything. + return 0; + } + + patch_len = fsize(f); + + uint8_t* patch_mem = malloc(patch_len); + + fread(patch_mem, 1, patch_len, f); + fclose(f); +#endif + + int debug = 0; +#ifdef LOADER + if (config.options[OPTION_OVERLY_VERBOSE]) { +#else + if (get_opt_u32(OPTION_OVERLY_VERBOSE)) { +#endif + debug = 1; + } + + return exec_bytecode(patch_mem, patch_len, ver, debug); +} + +#ifndef LOADER + +int cache_patch(const char *filename) { + uint16_t ver = 0; // FIXME - Provide native_firm version + uint32_t patch_len; + struct system_patch *patch; uint8_t *patch_mem; // Read patch to scrap memory. @@ -640,55 +650,42 @@ execb(const char *filename, int build_cache) fread(patch_loc, 1, len, f); fclose(f); - if (build_cache == 1) { - patch = (struct system_patch*)patch_loc; + patch = (struct system_patch*)patch_loc; - // Make sure various bits are correct. - if (memcmp(patch->magic, "AIDA", 4)) { - // Incorrect magic. - return 1; - } + // Make sure various bits are correct. + if (memcmp(patch->magic, "AIDA", 4)) { + // Incorrect magic. + return 1; + } - fprintf(stderr, "Cache: %s\n", patch->name); + fprintf(stderr, "Cache: %s\n", patch->name); - patch_mem = (uint8_t *)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8); - patch_len = patch->size; + 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); + 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); - fprintf(stderr, " Version: %u\n", patch->version); + fprintf(stderr, " Version: %u\n", patch->version); - for (uint32_t i = 0; i < patch->titles; i++) { - char cache_path[] = PATH_LOADER_CACHE "/0000000000000000"; + for (uint32_t i = 0; i < patch->titles; i++) { + char cache_path[] = PATH_LOADER_CACHE "/0000000000000000"; - uint64_t title = 0; - memcpy(&title, &title_buf[i * 8], 8); + uint64_t title = 0; + memcpy(&title, &title_buf[i * 8], 8); - uint32_t tlen = strlen(cache_path) - 1; - int j = 16; - while (j--) { - cache_path[tlen--] = hexDigits[title & 0xF]; - title >>= 4; - } - - fprintf(stderr, " cache: %s\n", &cache_path[strlen(cache_path) - 16]); + uint32_t tlen = strlen(cache_path) - 1; + int j = 16; + while (j--) { + cache_path[tlen--] = hexDigits[title & 0xF]; + title >>= 4; + } - char reset = 0xFF; + fprintf(stderr, " cache: %s\n", &cache_path[strlen(cache_path) - 16]); - 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. - } - } else { - // BOOT patch - char cache_path[] = PATH_LOADER_CACHE "/BOOT"; char reset = 0xFF; FILE *cache = fopen(cache_path, "w"); @@ -696,29 +693,11 @@ execb(const char *filename, int build_cache) fwrite(patch_mem, 1, patch_len, cache); fwrite(&reset, 1, 1, cache); fclose(cache); + // Add to cache. } - - return 0; - } else { - patch_mem = patch_loc; - patch_len = len; } -#endif - int debug = 0; -#ifdef LOADER - if (config.options[OPTION_OVERLY_VERBOSE]) { -#else - if (get_opt_u32(OPTION_OVERLY_VERBOSE)) { -#endif - debug = 1; - } + return 0; +} -#ifndef LOADER - if (stack_glob == NULL) { - stack_glob = malloc(STACK_SIZE); - } #endif - - return exec_bytecode(patch_mem, patch_len, stack_glob, STACK_SIZE, ver, debug); -} diff --git a/source/patcher.c b/source/patcher.c index 5e0a62e..61293ef 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -29,7 +29,7 @@ patch_cache_func(char* fpath) if (enable_list[p.uuid]) { // Patch is enabled. Cache it. - if (execb(fpath, 1)) { + if (cache_patch(fpath)) { panic("Failed to cache:\n %s\n", fpath); } @@ -51,9 +51,9 @@ generate_patch_cache() } int -patch_firm_all(firm_h* firm) +patch_firm_all(uint64_t tid, firm_h* firm) { - execb(PATH_LOADER_CACHE "/BOOT", 0); + execb(tid, firm); fprintf(stderr, "VM exited without issue\n");