From 220f6a471e095add2f3b0eb4c87602125a8f26a2 Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Mon, 5 Sep 2016 10:06:55 -0400 Subject: [PATCH] Firmlaunch code is now working. It's also fairly modularized and standalone now, so feel free to reuse it - it doesn't depend on corbenik's other code. --- Makefile.am | 12 +-- common.mk | 5 +- host/Makefile | 1 - host/generate_keys.sh | 40 ------- host/key_char.c | 102 ------------------ include/firm/firm.h | 8 +- include/firm/headers.h | 5 +- include/firm/internal.h | 39 +++++++ include/std/abort.h | 2 +- include/std/memory.h | 2 + source/chainloader.c | 4 +- source/firm/decryptor.c | 3 + source/firm/firm.c | 99 ++++++++++++++--- source/firm/firmlaunch.c | 3 +- source/firm/keys.c | 206 +++++++----------------------------- source/firm/keys/Y05.gen | 1 - source/firm/keys/Y11_95.gen | 1 - source/firm/keys/Y11_96.gen | 1 - source/firm/keys/Y3D_0.gen | 1 - source/firm/keys/Y3D_1.gen | 1 - source/firm/keys/Y3D_2.gen | 1 - source/firm/keys/Y3D_3.gen | 1 - source/firm/keys/Y3D_4.gen | 1 - source/firm/keys/Y3D_5.gen | 1 - source/firm/util.c | 190 +++++++++++++++++++++++---------- source/firm/version.c | 13 +-- source/interpreter.c | 20 ++-- source/interrupt.c | 11 +- source/main.c | 4 +- source/patch/emunand.c | 10 +- source/patch/reboot.c | 8 +- source/patcher.c | 6 +- source/std/abort.c | 2 +- source/std/allocator.c | 2 +- source/std/draw.c | 13 ++- source/std/memory.c | 11 ++ 36 files changed, 369 insertions(+), 461 deletions(-) delete mode 100755 host/generate_keys.sh delete mode 100644 host/key_char.c create mode 100644 include/firm/internal.h delete mode 100644 source/firm/keys/Y05.gen delete mode 100644 source/firm/keys/Y11_95.gen delete mode 100644 source/firm/keys/Y11_96.gen delete mode 100644 source/firm/keys/Y3D_0.gen delete mode 100644 source/firm/keys/Y3D_1.gen delete mode 100644 source/firm/keys/Y3D_2.gen delete mode 100644 source/firm/keys/Y3D_3.gen delete mode 100644 source/firm/keys/Y3D_4.gen delete mode 100644 source/firm/keys/Y3D_5.gen diff --git a/Makefile.am b/Makefile.am index d7f4b63..3e9fef3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,18 +31,18 @@ all-local: chmod +x out/generate_localeemu.sh echo "#!/bin/bash" > out/o3ds_firm.sh echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000002/00000052 -O .@libdir@/firmware/native" >> out/o3ds_firm.sh - echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000002/cetk -O .@datarootdir@/keys/native.cetk" >> out/o3ds_firm.sh + echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000002/cetk -O .@libdir@/firmware/native.cetk" >> out/o3ds_firm.sh echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000102/00000016 -O .@libdir@/firmware/twl" >> out/o3ds_firm.sh - echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000102/cetk -O .@datarootdir@/keys/twl.cetk" >> out/o3ds_firm.sh + echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000102/cetk -O .@libdir@/firmware/twl.cetk" >> out/o3ds_firm.sh echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000202/0000000B -O .@libdir@/firmware/agb" >> out/o3ds_firm.sh - echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000202/cetk -O .@datarootdir@/keys/agb.cetk" >> out/o3ds_firm.sh + echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013800000202/cetk -O .@libdir@/firmware/agb.cetk" >> out/o3ds_firm.sh echo "#!/bin/bash" > out/n3ds_firm.sh echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000002/00000021 -O .@libdir@/firmware/native" >> out/n3ds_firm.sh - echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000002/cetk -O .@datarootdir@/keys/native.cetk" >> out/n3ds_firm.sh + echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000002/cetk -O .@libdir@/firmware/native.cetk" >> out/n3ds_firm.sh echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000102/00000000 -O .@libdir@/firmware/twl" >> out/n3ds_firm.sh - echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000102/cetk -O .@datarootdir@/keys/twl.cetk" >> out/n3ds_firm.sh + echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000102/cetk -O .@libdir@/firmware/twl.cetk" >> out/n3ds_firm.sh echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000202/00000000 -O .@libdir@/firmware/agb" >> out/n3ds_firm.sh - echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000202/cetk -O .@datarootdir@/keys/agb.cetk" >> out/n3ds_firm.sh + echo "wget http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004013820000202/cetk -O .@libdir@/firmware/agb.cetk" >> out/n3ds_firm.sh chmod 755 out/*.sh cp README.md LICENSE.txt out/ diff --git a/common.mk b/common.mk index 912ed05..538fabc 100644 --- a/common.mk +++ b/common.mk @@ -16,8 +16,9 @@ AM_CFLAGS= -std=gnu11 -Os -g -ffast-math \ -fno-builtin -std=gnu11 -DREVISION=\"$(REVISION)\" \ -DFW_NAME=\"corbenik\" $(PATHARGS) -DMALLOC_DEBUG=1 +# -fsanitize=undefined -AM_LDFLAGS=-Wl,--use-blx,--pic-veneer,-q -nostdlib -nodefaultlibs -Wl,-z,defs -lgcc \ - -lc -L$(top_srcdir)/external/libctr9/src +AM_LDFLAGS=-Wl,--use-blx,--pic-veneer,-q -Wl,-z,defs \ + -L$(top_srcdir)/external/libctr9/src OCFLAGS=--set-section-flags .bss=alloc,load,contents diff --git a/host/Makefile b/host/Makefile index 8cdd2e3..9835ece 100644 --- a/host/Makefile +++ b/host/Makefile @@ -1,7 +1,6 @@ all: bdfe font misc misc: - gcc -o key_char key_char.c -lcrypto -g -O0 gcc -o error_decoder error_decoder.c -g -O0 bdfe_dir: diff --git a/host/generate_keys.sh b/host/generate_keys.sh deleted file mode 100755 index 1c7ba5d..0000000 --- a/host/generate_keys.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# Okay, so obviously this file would be non-redistributable if I put the keys here. -# You'll need to get them yourself (in plaintext) and put them in the correct place. - -# Optionally, you can call this file with an option -# and the output binary will contain the keys. DO NOT do this unless you know -# you will NOT share the binaries; the resultant output is NOT MY PROBLEM, and -# logs will be marked as "Tainted key loading used". If I have any reason to believe -# you have enabled this option, NO SUPPORT will be provided unless you go and use -# a build with that off. - -if [ "$1" == "--tainted-no-support" ]; then - WELP_USER_IS_A_WEIRDO_BUT_WHATEVER="$1" -fi - -function key() { - if [ -e "keys/$1.txt" ]; then - echo "Generating key metadata..." - mkdir -p ../source/firm/keys - ./key_char $WELP_USER_IS_A_WEIRDO_BUT_WHATEVER $(cat keys/$1.txt | tr -d '\n') > ../source/firm/keys/$1.gen - else - echo "Key not found, generating stub..." - echo -n "{}" > ../source/firm/keys/$1.gen - fi - - echo "$2" >> ../source/firm/keys/$1.gen -} - -key Y11_95 "," -key Y11_96 "" - -key Y05 "" - -key Y3D_0 "," -key Y3D_1 "," -key Y3D_2 "," -key Y3D_3 "," -key Y3D_4 "," -key Y3D_5 "" diff --git a/host/key_char.c b/host/key_char.c deleted file mode 100644 index 88e2fda..0000000 --- a/host/key_char.c +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include - -static const char digits[] = "0123456789abcdef"; -static char ascii_to_digit[256] = {0}; - -#define HASH_LEN 32 // Sha256 -void hexdump(uint8_t* text, uint8_t* bin, int bin_len) -{ - for(int i=0; i < bin_len; text += 2, bin++, i++) { - text[0] = digits[(bin[0] >> 4) & 0xf]; - text[1] = digits[bin[0] & 0xf]; - } -} - -void unhexdump(uint8_t* bin, uint8_t* str, int bin_len) -{ - for(int i=0; i < bin_len; bin++, str += 2, i++) { - bin[0] = (ascii_to_digit[str[0]] << 4) | ascii_to_digit[str[1]]; - } -} - -uint8_t* sha256(uint8_t* data, uint32_t len) { - uint8_t *hash = malloc(SHA256_DIGEST_LENGTH); - - SHA256_CTX sha256; - - SHA256_Init(&sha256); - SHA256_Update(&sha256, data, len); - SHA256_Final(hash, &sha256); - - return hash; -} - -void init() { - ascii_to_digit['0'] = 0; - ascii_to_digit['1'] = 1; - ascii_to_digit['2'] = 2; - ascii_to_digit['3'] = 3; - ascii_to_digit['4'] = 4; - ascii_to_digit['5'] = 5; - ascii_to_digit['6'] = 6; - ascii_to_digit['7'] = 7; - ascii_to_digit['8'] = 8; - ascii_to_digit['9'] = 9; - - ascii_to_digit['A'] = 0xa; - ascii_to_digit['B'] = 0xb; - ascii_to_digit['C'] = 0xc; - ascii_to_digit['D'] = 0xd; - ascii_to_digit['E'] = 0xe; - ascii_to_digit['F'] = 0xf; - - ascii_to_digit['a'] = 0xa; - ascii_to_digit['b'] = 0xb; - ascii_to_digit['c'] = 0xc; - ascii_to_digit['d'] = 0xd; - ascii_to_digit['e'] = 0xe; - ascii_to_digit['f'] = 0xf; -} - -uint16_t get_roll(uint8_t* data) { - uint16_t roll = 0; - for (int i=0; i < 16; i++) { - roll += data[i]; - } - - return roll; -} - -int main(int c, char **v) { - uint8_t data[16]; - char textsha[65] = {0}; - - if (c < 2) { - printf("Usage: %s \n", v[0]); - return 1; - } - - init(); - - unhexdump(data, v[1], 16); - - uint16_t roll = get_roll(data); - - uint8_t* sha = sha256(data, 16); - - printf("{.roll = 0x%03X, .sha = {", v[1], roll); - - for (int i=0; i < 32; i++) { - printf("0x%02X", sha[i]); - if (i != 31) - printf(", "); - } - printf("} }"); - - free(sha); - - return 0; -} diff --git a/include/firm/firm.h b/include/firm/firm.h index 5a40af6..93023f3 100644 --- a/include/firm/firm.h +++ b/include/firm/firm.h @@ -31,13 +31,9 @@ struct firm_signature */ struct firm_signature *get_firm_info(firm_h *firm); -/* Boots native FIRM - do not call directly. +/* Boots the CFW, generating caches and applying patches as-needed to the specified FIRM */ -void boot_firm(); - -/* Boots the CFW, generating caches and applying patches as-needed - */ -void boot_cfw(); +int boot_cfw(char *firm_path); /* Loads a firmware off disk, returning it. The memory should be free()'d when done, unless you plan to boot. */ diff --git a/include/firm/headers.h b/include/firm/headers.h index 09fba3c..887d83e 100644 --- a/include/firm/headers.h +++ b/include/firm/headers.h @@ -28,8 +28,7 @@ typedef struct firm_section_h typedef struct firm_h { - uint32_t magic; // FIRM - uint32_t reserved1; + char magic[8]; // "FIRM" normally, but D9 has this as "DECFIRM" uint32_t a11Entry; // ARM11 entry uint32_t a9Entry; // ARM9 entry uint8_t reserved2[0x30]; @@ -185,7 +184,7 @@ typedef struct arm9bin_h char size[8]; uint8_t pad[8]; uint8_t ctl_block[0x10]; - uint8_t unk[0x10]; + uint8_t unk[0x10]; // 3dbrew: Added with 9.5.0-X. Only used for hardware debugging: a nop instruction is executed with r0=0 and r1=
. uint8_t slot0x16keyX[0x10]; } arm9bin_h; diff --git a/include/firm/internal.h b/include/firm/internal.h new file mode 100644 index 0000000..a9b567b --- /dev/null +++ b/include/firm/internal.h @@ -0,0 +1,39 @@ +#ifdef FIRM_INTERNAL_CODE + +#ifndef __FIRM_INTENAL +#define __FIRM_INTERNAL + +#define SECTOR_SIZE 0x200 + +#define ROLL_WINDOW AES_BLOCK_SIZE +#define MODULO_WINDOW (ROLL_WINDOW / 2) + +typedef void (*void_call)(); + +void firmlaunch(firm_h* firm); +uint8_t* slice_roll_search(uint8_t *mem, uint32_t size, key_find_t* find); + +int set_Y3D_cetk(uint32_t commonKeyIndex); +int set_N11_K9L(uint32_t index); + +int decrypt_k9l(arm9bin_h *header, enum firm_type type, uint32_t k9l); + +int patch_entry(firm_h *firm, enum firm_type type); + +void* find_section_key(firm_h *firm_loc); +int patch_section_keys(firm_h* firm_loc, uint32_t k9l); + +int dec_k9l(firm_h* firm); + +uint8_t* get_titlekey(char *cetk_filename); + +//int decrypt_ncch(ncch_h *ncch, uint8_t* titlekey, size_t size); +//exefs_h *get_exefs(ncch_h *ncch); +//int decrypt_exefs(ncch_h *ncch); + +firm_h *extract_firm_from_ncch(ncch_h *ncch, uint8_t* titlekey, size_t size); + +#endif +#else + #error "Do not include internal headers directly." +#endif diff --git a/include/std/abort.h b/include/std/abort.h index 04b0d58..ad55a3f 100644 --- a/include/std/abort.h +++ b/include/std/abort.h @@ -10,6 +10,6 @@ * \param ... Format operands, see printf manpage */ -void abort(const char* x, ...) __attribute__ ((format (printf, 1, 2))); +void panic(const char* x, ...) __attribute__ ((format (printf, 1, 2))); #endif diff --git a/include/std/memory.h b/include/std/memory.h index 0a14425..464b847 100644 --- a/include/std/memory.h +++ b/include/std/memory.h @@ -19,4 +19,6 @@ uint8_t *memfind(uint8_t *startPos, uint32_t size, const void *pattern, uint32_t */ char* strdup_self(const char* str); +char* strdupcat(const char* str, const char *cat); + #endif diff --git a/source/chainloader.c b/source/chainloader.c index 754d5b2..6a0323e 100644 --- a/source/chainloader.c +++ b/source/chainloader.c @@ -28,7 +28,7 @@ void chainload_file(void* data) FILE* f = fopen(code_file, "r"); if (!f) { // File missing. - abort("Missing chainloader.\n"); + panic("Missing chainloader.\n"); } b_size = fsize(f); @@ -40,7 +40,7 @@ void chainload_file(void* data) f = fopen(chain_file, "r"); if (!f) { // File missing. - abort("Missing program to chainload?\n"); + panic("Missing program to chainload?\n"); } size = fsize(f); diff --git a/source/firm/decryptor.c b/source/firm/decryptor.c index aaab3a8..871dd48 100644 --- a/source/firm/decryptor.c +++ b/source/firm/decryptor.c @@ -2,6 +2,9 @@ #include #include +#define FIRM_INTERNAL_CODE +#include + void ncch_getctr(const ncch_h *ncch, uint8_t *ctr, uint8_t type) { diff --git a/source/firm/firm.c b/source/firm/firm.c index f98e061..8b01b10 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -6,31 +6,100 @@ #include #include -__attribute__ ((noreturn)) -void -boot_firm(firm_h* firm) -{ - abort("Temporarily not implemented\n"); - while(1); -} - -int firm_loaded = 0; +#define FIRM_INTERNAL_CODE +#include firm_h* load_firm(const char *path) { - return NULL; + int success = 0; + + FILE *firm_file = fopen(path, "r"); + if (!firm_file) { + return NULL; + } + + size_t size = fsize(firm_file); + + uint8_t* mem = malloc(size); + + firm_h *firm = (firm_h*)mem; + + fread(mem, 1, size, firm_file); + + fclose(firm_file); + + if (!memcmp(firm->magic, "DECFIRM", 7)) { + // Fully decrypted FIRM, courtesy D9. Fix the entrypoint and we're good. + firm = (firm_h*)mem; + + struct firm_signature* sig = get_firm_info(firm); + + patch_entry(firm, sig->type); + if (patch_section_keys(firm, sig->k9l)) { + free(mem); + return NULL; + } + + free(sig); + } else if (!memcmp(firm->magic, "FIRM", 4)) { + // O3DS fully decrypted FIRM + + firm = (firm_h*)mem; + } else { + // Encrypted. + char *cetk_path = strdupcat(path, ".cetk"); + + uint8_t* firmkey = get_titlekey(cetk_path); + + free(cetk_path); + + if (firmkey) { + firm = extract_firm_from_ncch((ncch_h*)mem, firmkey, size); + + if (firm) { + struct firm_signature* sig = get_firm_info(firm); + + if (sig->console == console_n3ds) { + if(dec_k9l(firm)) { + panic("K9L?"); + free(firm); + free(mem); + return NULL; + } + + patch_entry(firm, sig->type); + + if (patch_section_keys(firm, sig->k9l)) { + panic("Section keys?"); + free(firm); + free(mem); + return NULL; + } + } + + free(sig); + } + } + free(mem); + } + + return firm; } -void +int boot_cfw(char* firm_path) { firm_h* firm = load_firm(firm_path); - fprintf(stderr, "Patching firmware...\n"); - if (patch_firm_all(firm) != 0) - return; + if (firm == NULL) + panic("Invalid FIRM?"); + +// if (patch_firm_all(firm) != 0) +// return 1; + + firmlaunch(firm); - boot_firm(firm); + return 0; } diff --git a/source/firm/firmlaunch.c b/source/firm/firmlaunch.c index a0acdcf..62a22f6 100644 --- a/source/firm/firmlaunch.c +++ b/source/firm/firmlaunch.c @@ -2,7 +2,8 @@ #include #include -typedef void (*void_call)(); +#define FIRM_INTERNAL_CODE +#include static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8; diff --git a/source/firm/keys.c b/source/firm/keys.c index e7a441f..7894c64 100644 --- a/source/firm/keys.c +++ b/source/firm/keys.c @@ -3,188 +3,54 @@ #include #include -key_find_t Y11_sec; -key_find_t X11_sec; - -key_find_t Y11[] = { - #include "keys/Y11_95.gen" - #include "keys/Y11_96.gen" -}; - -key_find_t Y3D[] = { - #include "keys/Y3D_0.gen" - #include "keys/Y3D_1.gen" - #include "keys/Y3D_2.gen" - #include "keys/Y3D_3.gen" - #include "keys/Y3D_4.gen" - #include "keys/Y3D_5.gen" -}; - -key_find_t Y05 = -#include "keys/Y05.gen" -; - -#define ROLL_WINDOW AES_BLOCK_SIZE -#define MODULO_WINDOW (ROLL_WINDOW / 2) -uint8_t* slice_roll_search(uint8_t *mem, uint32_t size, key_find_t* find) { - uint16_t roll = 0; - uint32_t i = 0; - uint8_t hash[32]; - - // Initial window. - for(; i < ROLL_WINDOW; i++) { - roll += mem[i]; - } - - // Loop through, moving the window. - for(i = ROLL_WINDOW; i < size; i++) { - if (find->roll == roll) { - // Yes. Check hash. - sha256sum(hash, &mem[i], 0x10); - - if(!memcmp(find->sha, hash, 0x20)) { - return & mem[i]; - } +#define FIRM_INTERNAL_CODE +#include + +int set_N11_K9L(uint32_t index) { + static uint8_t ss_keyn[2][16] = { + { 0 }, // 9.5 + { 0 }, // 9.6+ + }; + + if (ss_keyn[0][0] == 0) { + ss_keyn[0][0] = 1; + FILE* key = fopen(PATH_SLOT0X11KEY95, "r"); + if (key) { + fread(ss_keyn[0], 1, AES_BLOCK_SIZE, key); + fclose(key); } - - roll -= mem[i-16]; - roll += mem[i]; - } - return NULL; -} - -int get_Y11_sec() { - // FIXME; this only handles the case of K9LH. Needs more sanity checks. - - uint8_t hash[32]; - - // We know better here than GCC. -#pragma GCC diagnostic push -#pragma GCC diagnostic warning "-Wdiscarded-qualifiers" - memcpy(hash, (volatile void*)REG_SHAHASH, 32); -#pragma GCC diagnostic pop - - memcpy(X11_sec.key, hash, 16); - memcpy(Y11_sec.key, hash + 16, 16); - - return 0; -} - -int get_Y11_K9L(firm_h *firm, int index) { - // A9LH corrupts this one. Can't do much here. - int level = 0; - - uint8_t key[AES_BLOCK_SIZE]; - FILE* f; - - // 9.5 key (K9L1) - f = fopen(PATH_SLOT0X11KEY95, "r"); - if (!f) { - level |= 1; - goto next; - } - - fread(Y11[0].key, 1, AES_BLOCK_SIZE, f); - fclose(f); - -next: - // 9.6 key (K9L2) - f = fopen(PATH_SLOT0X11KEY96, "r"); - if (!f) { - level |= 2; - goto end; } - fread(Y11[1].key, 1, AES_BLOCK_SIZE, f); - fclose(f); - -end: - return level; -} - -int get_Y3D(firm_h *firm, int index) { - uint8_t* key_loc = (uint8_t*)firm + firm->section[2].offset; // ARM9 segment - uint32_t search_size = firm->section[2].size; - - uint8_t mem[16] __attribute__((aligned(16))) = {0}; - - uint8_t* key_data = slice_roll_search(key_loc, search_size, & Y3D[0]); - - if (!key_data) - return 1; - - memcpy(mem, key_data, 16); - - return 0; -} - -int get_Y05(firm_h *firm) { - uint8_t* key_loc = (uint8_t*)firm + firm->section[2].offset; // ARM9 segment - uint32_t search_size = firm->section[2].size; - - uint8_t mem[16] __attribute__((aligned(16))) = {0}; - - uint8_t* key_data = slice_roll_search(key_loc, search_size, &Y05); - - if (!key_data) - return 1; - - fprintf(stderr, " 0x05 KeyY at %lx in FIRM1\n", (uint32_t)key_data - (uint32_t)key_loc); - - memcpy(mem, key_data, 16); - - return 0; -} - -int extract_keys() { - int level = 0; - - if (get_Y11_sec()) {// MUST be done first. Otherwise, sha register gets clobbered. - // At best, a warning. - level |= 1; - } - -#if 0 - if (get_Y11_K9L()) { // For decrypting K9L. - // Also a warning, but potentially fatal if an N3DS. - level |= 2; - } - - if (get_Y3D()) { - // No cetk decryption. - level |= 4; + if (ss_keyn[1][0] == 0) { + ss_keyn[1][0] = 1; + FILE* key = fopen(PATH_SLOT0X11KEY96, "r"); + if (key) { + fread(ss_keyn[1], 1, AES_BLOCK_SIZE, key); + fclose(key); + } } - if (get_Y05()) { - // Pretty much a warning and nothing else atm. - level |= 8; - } -#endif + setup_aeskey(0x11, (void*) ss_keyn[index]); - return level; -} - -int set_Y3D_common(int commonKeyIndex) { - setup_aeskeyY(0x3D, (void*) Y3D[commonKeyIndex].key); - - use_aeskey(0x3D); + use_aeskey(0x11); return 0; } -int set_Y05() { - // N3DS nand key - setup_aeskeyY(0x05, Y05.key); - - use_aeskey(0x05); +int set_Y3D_cetk(uint32_t index) { + // From https://github.com/profi200/Project_CTR/blob/master/makerom/pki/prod.h#L19 + static uint8_t common_keyy[6][16] = { + {0xD0, 0x7B, 0x33, 0x7F, 0x9C, 0xA4, 0x38, 0x59, 0x32, 0xA2, 0xE2, 0x57, 0x23, 0x23, 0x2E, 0xB9} , // 0 - eShop Titles + {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C} , // 1 - System Titles + {0xC4, 0x75, 0xCB, 0x3A, 0xB8, 0xC7, 0x88, 0xBB, 0x57, 0x5E, 0x12, 0xA1, 0x09, 0x07, 0xB8, 0xA4} , // 2 + {0xE4, 0x86, 0xEE, 0xE3, 0xD0, 0xC0, 0x9C, 0x90, 0x2F, 0x66, 0x86, 0xD4, 0xC0, 0x6F, 0x64, 0x9F} , // 3 + {0xED, 0x31, 0xBA, 0x9C, 0x04, 0xB0, 0x67, 0x50, 0x6C, 0x44, 0x97, 0xA3, 0x5B, 0x78, 0x04, 0xFC} , // 4 + {0x5E, 0x66, 0x99, 0x8A, 0xB4, 0xE8, 0x93, 0x16, 0x06, 0x85, 0x0F, 0xD7, 0xA1, 0x6D, 0xD7, 0x55} , // 5 + }; - return 0; -} + setup_aeskeyY(0x3D, (void*) common_keyy[index]); -int set_Y11_K9L(int index) { - setup_aeskey(0x11, Y11[index].key); - - use_aeskey(0x11); + use_aeskey(0x3D); return 0; } diff --git a/source/firm/keys/Y05.gen b/source/firm/keys/Y05.gen deleted file mode 100644 index 0967ef4..0000000 --- a/source/firm/keys/Y05.gen +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/source/firm/keys/Y11_95.gen b/source/firm/keys/Y11_95.gen deleted file mode 100644 index 174e1e6..0000000 --- a/source/firm/keys/Y11_95.gen +++ /dev/null @@ -1 +0,0 @@ -{}, diff --git a/source/firm/keys/Y11_96.gen b/source/firm/keys/Y11_96.gen deleted file mode 100644 index 9bba4bb..0000000 --- a/source/firm/keys/Y11_96.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0x5D1D533A, .sha = {0x8B, 0xB9, 0x77, 0x76, 0x86, 0xBD, 0xCC, 0xFF, 0x30, 0xE9, 0x4D, 0xC6, 0x5F, 0x23, 0x43, 0xF7, 0x41, 0x2E, 0x3D, 0x6C, 0x19, 0x12, 0xE3, 0x18, 0xDA, 0x9F, 0x17, 0x35, 0x96, 0xB9, 0xE8, 0x98} } diff --git a/source/firm/keys/Y3D_0.gen b/source/firm/keys/Y3D_0.gen deleted file mode 100644 index 7753ffd..0000000 --- a/source/firm/keys/Y3D_0.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0x9EFCCA41, .sha = {0x0A, 0x1C, 0x7B, 0x55, 0x86, 0x05, 0x89, 0xB0, 0xED, 0xD8, 0x87, 0x4B, 0x50, 0x55, 0xE3, 0x47, 0x16, 0xA2, 0xCD, 0xE2, 0x5B, 0xAD, 0x12, 0x48, 0xBB, 0xBB, 0xEE, 0xD1, 0xB3, 0x40, 0xB1, 0xB8} }, diff --git a/source/firm/keys/Y3D_1.gen b/source/firm/keys/Y3D_1.gen deleted file mode 100644 index b170fd7..0000000 --- a/source/firm/keys/Y3D_1.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0x65D5C908, .sha = {0x21, 0x12, 0xF4, 0x50, 0x78, 0x6D, 0xCE, 0x64, 0x39, 0xFD, 0xB8, 0x71, 0x14, 0x74, 0x41, 0xF4, 0x69, 0xB6, 0xC4, 0x70, 0xA4, 0xB1, 0x5F, 0x7D, 0xFD, 0xE8, 0xCC, 0xE4, 0xC4, 0x62, 0x82, 0x5B} }, diff --git a/source/firm/keys/Y3D_2.gen b/source/firm/keys/Y3D_2.gen deleted file mode 100644 index 78e28ff..0000000 --- a/source/firm/keys/Y3D_2.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0xC1F558D6, .sha = {0xF7, 0x12, 0x1A, 0xCA, 0x63, 0x61, 0xC0, 0x9C, 0x10, 0xBB, 0x62, 0x8D, 0x69, 0x85, 0x23, 0x08, 0xCB, 0x81, 0xDB, 0x22, 0x9E, 0xFD, 0xC1, 0xAB, 0xF5, 0x7B, 0xA3, 0x8E, 0xDA, 0x64, 0x56, 0x74} }, diff --git a/source/firm/keys/Y3D_3.gen b/source/firm/keys/Y3D_3.gen deleted file mode 100644 index 99c8698..0000000 --- a/source/firm/keys/Y3D_3.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0x67D738E, .sha = {0xD8, 0xCF, 0x95, 0x7D, 0x88, 0x46, 0x6C, 0x7C, 0x42, 0x50, 0x7C, 0xA5, 0x53, 0xD2, 0x37, 0x34, 0x65, 0x0E, 0x34, 0x32, 0x3A, 0x58, 0x80, 0x76, 0x7E, 0xB5, 0x3A, 0x07, 0xEB, 0x5E, 0x00, 0xFD} }, diff --git a/source/firm/keys/Y3D_4.gen b/source/firm/keys/Y3D_4.gen deleted file mode 100644 index ae21926..0000000 --- a/source/firm/keys/Y3D_4.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0xCC1BE763, .sha = {0x75, 0x71, 0x64, 0x46, 0x3B, 0xDA, 0xEC, 0x71, 0x57, 0x95, 0x85, 0x17, 0xDF, 0x9B, 0x1D, 0xC7, 0xF3, 0x6A, 0x87, 0x22, 0x09, 0x70, 0x60, 0xD9, 0x48, 0xCC, 0x01, 0xFF, 0x72, 0x0F, 0xEE, 0x56} }, diff --git a/source/firm/keys/Y3D_5.gen b/source/firm/keys/Y3D_5.gen deleted file mode 100644 index 3999b71..0000000 --- a/source/firm/keys/Y3D_5.gen +++ /dev/null @@ -1 +0,0 @@ -{.roll = 0xC7A98491, .sha = {0xA4, 0x5B, 0x06, 0xC3, 0x37, 0xB7, 0x51, 0x6D, 0xF7, 0xA7, 0xCD, 0x87, 0xC2, 0x1D, 0x5F, 0xFC, 0x22, 0xA4, 0xAA, 0xB6, 0x48, 0x10, 0x2B, 0x98, 0x7E, 0x00, 0xD5, 0xC2, 0x48, 0x39, 0x6C, 0xF8} } diff --git a/source/firm/util.c b/source/firm/util.c index c94bb0f..3ba183c 100644 --- a/source/firm/util.c +++ b/source/firm/util.c @@ -6,17 +6,19 @@ #include #include -#define SECTOR_SIZE 0x200 +#define FIRM_INTERNAL_CODE +#include -int decrypt_k9l(arm9bin_h *header, enum firm_type type) { +int decrypt_k9l(arm9bin_h *header, enum firm_type type, uint32_t k9l) { uint8_t slot = 0x15; - if (type == type_native) { + if (type == type_native && k9l) { uint8_t decrypted_keyx[AES_BLOCK_SIZE]; slot = 0x16; - use_aeskey(0x11); + set_N11_K9L(k9l - 1); + ecb_decrypt(header->slot0x16keyX, decrypted_keyx, 1, AES_CNT_ECB_DECRYPT_MODE); setup_aeskeyX(slot, decrypted_keyx); } @@ -32,91 +34,169 @@ int decrypt_k9l(arm9bin_h *header, enum firm_type type) { ctr_decrypt(arm9bin, arm9bin, (size_t)size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, header->ctr); - if (type == type_native && *(uint32_t *)arm9bin == ARM9BIN_MAGIC) - return 0; - else if (*(uint32_t *)arm9bin == LGY_ARM9BIN_MAGIC) - return 0; + if (type == type_native) + return *(uint32_t *)arm9bin != ARM9BIN_MAGIC; - return 1; // Failed. + return *(uint32_t *)arm9bin != LGY_ARM9BIN_MAGIC; } -void fix_entry(firm_h* firm, enum firm_type type) { - // Patch the entrypoint to skip arm9loader +int patch_entry(firm_h *firm, enum firm_type type) { if (type == type_native) firm->a9Entry = 0x0801B01C; else firm->a9Entry = 0x0801301C; - // The entrypoints seem to be the same across different FIRM versions, - // so we don't change them. + return 0; } -// 0x0B130000 = start of FIRM0 partition, 0x400000 = size of FIRM partition (4MB) -firm_h* dump_firm(firm_h* buffer, uint8_t index) { - firm_h* firm; +uint8_t* +get_titlekey(char *cetk_filename) +{ + FILE* f = fopen(cetk_filename, "r"); + size_t size = fsize(f); + + uint8_t* cetk = malloc(size); + + fread(cetk, 1, size, f); - // NOTE - Cast, because GCC is making assumptions about 'index'. - uint32_t firm_offset = (uint32_t)(0x0B130000 + (index % 2) * 0x400000), - firm_b_size = 0x00100000; // 1MB, because + fclose(f); - firm = malloc(firm_b_size); + uint8_t iv[AES_BLOCK_SIZE] = { 0 }; + uint32_t sigtype = __builtin_bswap32(*(const uint32_t *)cetk); - uint8_t ctr[0x10], - cid[0x10], - sha_t[0x20]; + if (sigtype != SIG_TYPE_RSA2048_SHA256) { + free(cetk); + return NULL; + } - if (sdmmc_nand_readsectors(firm_offset / SECTOR_SIZE, firm_b_size / SECTOR_SIZE, (uint8_t*)firm)) - goto failure; + const ticket_h *ticket = (const ticket_h *)((const uint8_t*)cetk + sizeof(sigtype) + 0x13C); - sdmmc_get_cid(1, (uint32_t*)cid); - sha256sum(sha_t, cid, 0x10); - memcpy(ctr, sha_t, 0x10); - add_ctr(ctr, firm_offset / AES_BLOCK_SIZE); + set_Y3D_cetk(1); - use_aeskey(0x06); - set_ctr(ctr); - ctr_decrypt(firm, firm, firm_b_size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, ctr); + uint8_t *key = malloc(AES_BLOCK_SIZE); - if (memcmp((char*) & firm->magic, "FIRM", 4)) - goto failure; + memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); + memcpy(key, ticket->titleKey, sizeof(ticket->titleKey)); - return firm; + cbc_decrypt(key, key, 1, AES_CNT_TITLEKEY_DECRYPT_MODE, iv); -failure: - free(firm); + free(cetk); - return NULL; + return key; } -uint8_t* find_section_key(firm_h *firm_loc) { - // The key will be dword-aligned (I think? Verify this. May need new NFIRM to check assumption. Go, Nintendo!) -#if 0 - // The hash of the key. Can't give the key itself out, obviously. - uint8_t sha256[] = {0xb9, 0x4d, 0xb1, 0xb1, 0xc3, 0xe0, 0x11, 0x08, 0x9c, 0x19, 0x46, 0x06, 0x4a, 0xbc, 0x40, 0x2a, - 0x7c, 0x66, 0xf4, 0x4a, 0x74, 0x6f, 0x71, 0x50, 0x32, 0xfd, 0xff, 0x03, 0x74, 0xd7, 0x45, 0x2c}; +int dec_k9l(firm_h* firm) { + firm_section_h *arm9 = NULL; + for (firm_section_h* section = firm->section; section < firm->section + 4; section++) { + if (section->type == FIRM_TYPE_ARM9) { // ARM9 + arm9 = section; + break; + } + } - uint8_t* key_loc = (uint8_t*)firm_loc + firm_loc->section[2].offset; - uint32_t search_size = firm_loc->section[2].size; + if (arm9 == NULL) + return 1; - uint8_t* key_data = key_search(key_loc, search_size, sha256, 0xDD); + struct firm_signature* sig = get_firm_info(firm); + + if (decrypt_k9l((arm9bin_h*)((uint8_t*)firm + arm9->offset), sig->type, sig->k9l)) + return 1; - if (!key_data) - abort(" FIRM Section key not found!\n"); + // Recalc section hash. + sha256sum(arm9->hash, (uint8_t*)firm + arm9->offset, arm9->size); - fprintf(stderr, " FIRM Section key at %lx in FIRM\n", (uint32_t)key_data - (uint32_t)key_loc); - return key_data; -#endif - return NULL; + // Magic like D9. + memcpy(firm->magic, "DECFIRM", 7); + + free(sig); + + return 0; } -int set_section_keys(firm_h* firm_loc) { +firm_h* +extract_firm_from_ncch(ncch_h *ncch, uint8_t *titlekey, size_t size) +{ + uint8_t firm_iv[16] = { 0 }; + uint8_t exefs_key[16] = { 0 }; + uint8_t exefs_iv[16] = { 0 }; + + setup_aeskey(0x16, titlekey); + use_aeskey(0x16); + cbc_decrypt(ncch, ncch, size / AES_BLOCK_SIZE, AES_CNT_CBC_DECRYPT_MODE, firm_iv); + + if (ncch->magic != NCCH_MAGIC) { + return NULL; + } + + memcpy(exefs_key, ncch, AES_BLOCK_SIZE); + ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS); + + // Get the exefs offset and size from the NCCH + exefs_h *exefs = (exefs_h *)((uint8_t *)ncch + ncch->exeFSOffset * MEDIA_UNITS); + uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS; + + setup_aeskeyY(0x2C, exefs_key); + use_aeskey(0x2C); + ctr_decrypt(exefs, exefs, exefs_size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, exefs_iv); + + // Get the decrypted FIRM + // We assume the firm.bin is always the first file + firm_h *firm = (firm_h *)&exefs[1]; // The offset right behind the exefs + + // header; the first file. + size = exefs->fileHeaders[0].size; + if (memcmp(firm->magic, "FIRM", 4)) { + return NULL; + } + + firm_h* dest = malloc(size); + + memcpy(dest, firm, size); + + return dest; +} + +uint8_t* key_search(uint8_t* mem, uint32_t size, uint8_t* sha256, uint8_t byte) { + uint8_t hash[0x20] = {0}; + // Search for key. + for(uint32_t j = 0; j < size; j++) { + // Is candidate? + if (mem[j] == byte) { + // Yes. Check hash. + sha256sum(hash, &mem[j], 0x10); + if(!memcmp(sha256, hash, 0x20)) { + return &mem[j]; + } + } + } + return NULL; +} + +void* find_section_key(firm_h* firm_loc) { + uint8_t sha256[] = {0xb9, 0x4d, 0xb1, 0xb1, 0xc3, 0xe0, 0x11, 0x08, 0x9c, 0x19, 0x46, 0x06, 0x4a, 0xbc, 0x40, 0x2a, + 0x7c, 0x66, 0xf4, 0x4a, 0x74, 0x6f, 0x71, 0x50, 0x32, 0xfd, 0xff, 0x03, 0x74, 0xd7, 0x45, 0x2c}; + + uint8_t* key_loc = (uint8_t*)firm_loc + firm_loc->section[2].offset; + uint32_t search_size = firm_loc->section[2].size; + + uint8_t* key_data = key_search(key_loc, search_size, sha256, 0xDD); + + if (!key_data) + return NULL; + + return key_data; +} + +int patch_section_keys(firm_h* firm_loc, uint32_t k9l) { // Set up the keys needed to boot a few firmwares, due to them being unset, // depending on which firmware you're booting from. + uint8_t *keydata = find_section_key(firm_loc); if (!keydata) return 1; - use_aeskey(0x11); + set_N11_K9L(k9l - 1); + uint8_t keyx[AES_BLOCK_SIZE]; for (int slot = 0x19; slot < 0x20; slot++) { ecb_decrypt(keydata, keyx, 1, AES_CNT_ECB_DECRYPT_MODE); diff --git a/source/firm/version.c b/source/firm/version.c index 9db7067..1762448 100644 --- a/source/firm/version.c +++ b/source/firm/version.c @@ -1,5 +1,8 @@ #include +#define FIRM_INTERNAL_CODE +#include + struct firm_signature * get_firm_info(firm_h *firm) { @@ -29,15 +32,9 @@ get_firm_info(firm_h *firm) // Check for the presence of a TWL/AGB only sysmodule if( memfind((uint8_t*)firm + firm->section[0].offset, firm->section[0].size, "TwlBg", 5)) { signature->type = type_twl; - fprintf(stderr, " TwlBg module found; probably TWL\n"); } else if( memfind((uint8_t*)firm + firm->section[0].offset, firm->section[0].size, "AgbBg", 5)) { signature->type = type_agb; - fprintf(stderr, " AgbBg module found; probably AGB\n"); - } else { - fprintf(stderr, " Warning: Native, but there is a 4th section. Report this IMMEDIATELY.\n"); } - } else { - fprintf(stderr, " Section #4 is empty; this is probably native\n"); } for (firm_section_h *section = firm->section; section < firm->section + 4; section++) { @@ -51,10 +48,8 @@ get_firm_info(firm_h *firm) // Only N3DS FIRMs have this property. uint8_t* k9l = (uint8_t*)memfind((uint8_t*)firm + section->offset, section->size, "K9L", 3); if (k9l == NULL) { // O3DS. - fprintf(stderr, " No K9L; this is likely an O3DS FIRM\n"); signature->console = console_o3ds; } else { // N3DS. - fprintf(stderr, " K9L found; this is likely an N3DS FIRM\n"); signature->console = console_n3ds; signature->k9l = (unsigned int)(k9l[3] - '0'); // String is "K9LN" where N is the version } @@ -66,10 +61,8 @@ get_firm_info(firm_h *firm) // which allows determining which console it is intended for. if (section->address == 0x08006800) { // O3DS entry signature->console = console_o3ds; - fprintf(stderr, " Entry point seems correct for O3DS\n"); } else if (section->address == 0x08006000) { // N3DS entry signature->console = console_n3ds; - fprintf(stderr, " Entry point seems correct for N3DS\n"); } } diff --git a/source/interpreter.c b/source/interpreter.c index 4d1f5dc..0602309 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -49,7 +49,7 @@ #ifdef LOADER #define log(a) logstr(a) - #define abort(a) \ + #define panic(a) \ { \ logstr(a); \ svcBreak(USERBREAK_ASSERT); \ @@ -419,49 +419,49 @@ exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_si if (debug) log("abort\n"); - abort("abort triggered, halting VM!\n"); + panic("abort triggered, halting VM!\n"); break; case OP_ABORTEQ: code++; if (debug) log("aborteq\n"); if (eq) - abort("eq flag not set, halting VM!\n"); + panic("eq flag not set, halting VM!\n"); break; case OP_ABORTNE: code++; if (debug) log("abortlt\n"); if (!eq) - abort("eq flag not set, halting VM!\n"); + panic("eq flag not set, halting VM!\n"); break; case OP_ABORTLT: code++; if (debug) log("abortlt\n"); if (lt) - abort("lt flag set, halting VM!\n"); + panic("lt flag set, halting VM!\n"); break; case OP_ABORTGT: code++; if (debug) log("abortgt\n"); if (gt) - abort("gt flag set, halting VM!\n"); + panic("gt flag set, halting VM!\n"); break; case OP_ABORTF: code++; if (debug) log("abortf\n"); if (found) - abort("f flag set, halting VM!\n"); + panic("f flag set, halting VM!\n"); break; case OP_ABORTNF: code++; if (debug) log("abortnf\n"); if (!found) - abort("f flag is not set, halting VM!\n"); + panic("f flag is not set, halting VM!\n"); break; case OP_NEXT: if (debug) { @@ -524,7 +524,7 @@ exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_si (uint32_t)code, *code); #endif - abort("Halting startup.\n"); + panic("Halting startup.\n"); break; } @@ -532,7 +532,7 @@ exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_si #ifndef LOADER fprintf(stderr, " -> %lx", offset); #endif - abort("seeked out of bounds\n"); + panic("seeked out of bounds\n"); } #ifndef LOADER diff --git a/source/interrupt.c b/source/interrupt.c index 94c5242..5bbb62e 100644 --- a/source/interrupt.c +++ b/source/interrupt.c @@ -3,7 +3,7 @@ #include void dump_state_printf(uint32_t* regs) { - fprintf(stderr, " cpsr:%x sp:%x lr:%x\n" + fprintf(stderr, " cpsr:%x sp:%x pc:%x\n" " r0:%x r1:%x r2:%x r3:%x\n" " r4:%x r5:%x r6:%x r7:%x\n" " r8:%x r9:%x r10:%x r11:%x\n" @@ -22,7 +22,7 @@ void reset_INT(_UNUSED uint32_t* regs) { void undef_INT(uint32_t* regs) { fprintf(stderr, "Undefined instruction.\n"); dump_state_printf(regs); - abort("Cannot continue. Halting.\n"); + panic("Cannot continue. Halting.\n"); } void swi_INT(_UNUSED uint32_t* regs) { @@ -30,22 +30,21 @@ void swi_INT(_UNUSED uint32_t* regs) { } void preabrt_INT(uint32_t* regs) { - fprintf(stderr, "Prefetch Abort.\n"); + fprintf(stderr, "Prefetch abort.\n"); dump_state_printf(regs); - abort("Cannot continue. Halting.\n"); + panic("Cannot continue. Halting.\n"); } void databrt_INT(uint32_t* regs) { fprintf(stderr, "Data abort.\n"); dump_state_printf(regs); - abort("Cannot continue. Halting.\n"); + panic("Cannot continue. Halting.\n"); } void fiq_INT(_UNUSED uint32_t* regs) { fprintf(stderr, "FIQ called. Returning.\n"); } - void install_interrupts() { ctr_interrupt_prepare(); ctr_irq_initialize(); diff --git a/source/main.c b/source/main.c index f0988f5..7da5e77 100644 --- a/source/main.c +++ b/source/main.c @@ -63,5 +63,7 @@ main(int argc, char** argv) generate_patch_cache(); } - boot_cfw(); + boot_cfw(config->firm[0]); + + panic("Firmlaunch failed!\n"); } diff --git a/source/patch/emunand.c b/source/patch/emunand.c index 0659163..8c18055 100644 --- a/source/patch/emunand.c +++ b/source/patch/emunand.c @@ -34,7 +34,7 @@ verify_emunand(uint32_t index, uint32_t *off, uint32_t *head) fprintf(stderr, "emunand: found NCSD magic for %lu\n", index); fprintf(stderr, "emunand: layout is gateway\n"); } else { - abort("emunand: selected NAND image is not valid.\n"); + panic("emunand: selected NAND image is not valid.\n"); } free(emunand_temp); @@ -82,7 +82,7 @@ patchNANDRW(uint8_t *pos, uint32_t size, uint32_t branchOffset) uint16_t *writeOffset = (uint16_t *)memfind((uint8_t*)(readOffset + 5), 0x100, pattern, 4) - 3; if (!readOffset || !writeOffset) - abort("emunand: pattern for r/w missing!\n"); + panic("emunand: pattern for r/w missing!\n"); readOffset[0] = nandRedir[0]; readOffset[1] = nandRedir[1]; @@ -127,11 +127,11 @@ patch_emunand(firm_h* firm_loc, uint32_t index) // Copy emuNAND code void *emuCodeOffset = getEmuCode(arm9Section, arm9SectionSize); if (!emuCodeOffset) - abort("emunand: code missing from arm9?\n"); + panic("emunand: code missing from arm9?\n"); FILE *f = fopen(PATH_EMUNAND_CODE, "r"); if (!f) - abort("emunand: code not found on SD.\n"); + panic("emunand: code not found on SD.\n"); uint32_t emunand_size = fsize(f); fread(emuCodeOffset, 1, emunand_size, f); @@ -147,7 +147,7 @@ patch_emunand(firm_h* firm_loc, uint32_t index) *pos_sdmmc = (uint32_t *)memfind(emuCodeOffset, emunand_size, "SDMC", 4); if (!pos_offset || !pos_head || !pos_sdmmc) - abort("emunand: couldn't find pattern in hook?\n"); + panic("emunand: couldn't find pattern in hook?\n"); verify_emunand(index, pos_offset, pos_head); diff --git a/source/patch/reboot.c b/source/patch/reboot.c index f448056..332d9bf 100644 --- a/source/patch/reboot.c +++ b/source/patch/reboot.c @@ -42,7 +42,7 @@ patch_reboot(firm_h* firm_loc) // Copy firmlaunch code FILE *f = fopen(PATH_REBOOT_HOOK, "r"); if (!f) - abort("reboot: hook not found on SD\n"); + panic("reboot: hook not found on SD\n"); uint32_t size = fsize(f); fread(off, 1, size, f); @@ -51,7 +51,7 @@ patch_reboot(firm_h* firm_loc) // Put the fOpen offset in the right location uint32_t *pos_fopen = (uint32_t *)memfind(off, size, "open", 4); if (!pos_fopen) - abort("reboot: fopen location missing\n"); + panic("reboot: fopen location missing\n"); *pos_fopen = fOpenOffset; @@ -60,7 +60,7 @@ patch_reboot(firm_h* firm_loc) uint32_t *pos_agb = (uint32_t *)memfind(off, size, "AGBF", 4); if (!pos_native && !pos_twl && !pos_agb) - abort("reboot: missing string placeholder?\n"); + panic("reboot: missing string placeholder?\n"); fprintf(stderr, "reboot: NATF @ %lx\n", (uint32_t)pos_native); fprintf(stderr, "reboot: TWLF @ %lx\n", (uint32_t)pos_twl); @@ -104,7 +104,7 @@ patch_reboot(firm_h* firm_loc) f = fopen(PATH_REBOOT_CODE, "r"); if (!f) - abort("reboot: boot not found on SD\n"); + panic("reboot: boot not found on SD\n"); fread(mem, 1, fsize(f), f); fclose(f); diff --git a/source/patcher.c b/source/patcher.c index f5992a6..5e0a62e 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -30,7 +30,7 @@ patch_cache_func(char* fpath) if (enable_list[p.uuid]) { // Patch is enabled. Cache it. if (execb(fpath, 1)) { - abort("Failed to cache:\n %s\n", fpath); + panic("Failed to cache:\n %s\n", fpath); } wait(); @@ -75,7 +75,7 @@ patch_firm_all(firm_h* firm) // Inject services? if (get_opt_u32(OPTION_SVCS)) { if (patch_svc_calls(firm)) { - abort("Fatal. Svc inject has failed."); + panic("Fatal. Svc inject has failed."); } wait(); } @@ -83,7 +83,7 @@ patch_firm_all(firm_h* firm) // Replace loader? if (get_opt_u32(OPTION_LOADER)) { if (patch_modules(firm)) { - abort("Fatal. Loader inject has failed."); + panic("Fatal. Loader inject has failed."); } // This requires OPTION_SIGPATCH. wait(); diff --git a/source/std/abort.c b/source/std/abort.c index 48db2f1..fcc387b 100644 --- a/source/std/abort.c +++ b/source/std/abort.c @@ -4,7 +4,7 @@ #include #include -void abort(char* x, ...) { +void panic(char* x, ...) { va_list ap; va_start(ap, x); diff --git a/source/std/allocator.c b/source/std/allocator.c index e0c4eec..4b21ed9 100644 --- a/source/std/allocator.c +++ b/source/std/allocator.c @@ -118,7 +118,7 @@ void free(void* ptr) { #ifdef MALLOC_DEBUG if (block->canary != 0x1337d00d) { - abort("%s: Attempt free non-pointer.\n", info); + panic("%s: Attempt free non-pointer.\n", info); } ++free_count; diff --git a/source/std/draw.c b/source/std/draw.c index 2da5866..901f03e 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -179,7 +179,7 @@ void set_font(const char* filename) { FILE* f = fopen(filename, "r"); - if (!f) abort("Failed to load font file!\n"); + if (!f) panic("Failed to load font file!\n"); unsigned int new_w, new_h; @@ -187,7 +187,7 @@ void set_font(const char* filename) { fread(&new_h, 1, 4, f); if (new_w == 0 || new_h == 0) { - abort("Invalid font file: w/h is 0 - not loaded\n"); + panic("Invalid font file: w/h is 0 - not loaded\n"); } unsigned int c_font_w = (new_w / 8) + ((new_w % 8) ? 1 : 0); @@ -641,9 +641,10 @@ vfprintf(void *channel, const char *format, va_list ap) { if ((channel == stdout || channel == stderr) && kill_output) return; - - char *copy = strdup_self(format); - char *ref = copy; +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wdiscarded-qualifiers" + char *ref = format; +#pragma GCC diagnostic pop unsigned char *color = NULL; if (channel == TOP_SCREEN) @@ -709,8 +710,6 @@ vfprintf(void *channel, const char *format, va_list ap) } ++ref; } - - free(copy); } void diff --git a/source/std/memory.c b/source/std/memory.c index 5a039b0..977e7f9 100644 --- a/source/std/memory.c +++ b/source/std/memory.c @@ -12,6 +12,17 @@ strdup_self(const char* str) return new_st; } +char* +strdupcat(const char* str, const char *cat) +{ + size_t l_str = strlen(str); + size_t l_cat = strlen(cat); + char *out = malloc(l_str + l_cat + 1); + memcpy(out, str, l_str); + memcpy(out + l_str, cat, l_cat + 1); + return out; +} + int atoi(const char *str) { -- 2.39.5