From f2dc37212d80ab34b191da003503d9ecb27486fa Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Tue, 27 Sep 2016 00:45:01 -0400 Subject: [PATCH] Update FIRM handling code to cache shit --- host/copy-min.sh | 7 +-- source/firm/firm.c | 144 +++++++++++++++++++++++++++----------------- source/firm/keys.c | 30 +++++----- source/firm/util.c | 146 ++++++++++++++++++++++----------------------- source/main.c | 47 ++++++++------- 5 files changed, 205 insertions(+), 169 deletions(-) mode change 100644 => 100755 host/copy-min.sh diff --git a/host/copy-min.sh b/host/copy-min.sh old mode 100644 new mode 100755 index 86590ad..87f9959 --- a/host/copy-min.sh +++ b/host/copy-min.sh @@ -3,13 +3,10 @@ # This is just a helper script I use to copy shit to my own unit. # You don't and shouldn't need to use it. -mnt=/media/sd -dev=/dev/sdc - -mnt=/mnt/ext1 +mnt=/media +dev=/dev/mmcblk0p mount -t vfat ${dev}1 $mnt || exit 0 cp out/arm9loaderhax.bin $mnt/arm9loaderhax_si.bin || exit 0 umount $mnt || exit 0 sync || exit 0 -eject ${dev} || exit 0 diff --git a/source/firm/firm.c b/source/firm/firm.c index 9d15e62..5dd1e7c 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -12,19 +12,28 @@ firm_h* load_firm(const char *path, size_t *size_out) { + uint8_t* mem; + struct firm_signature* sig; int success = 0; + FILE* firm_file; + size_t size; + int save_dec = 0; - FILE *firm_file = fopen(path, "r"); + char* decpath = strdupcat(path, ".dec"); + firm_file = fopen(decpath, "r"); if (!firm_file) { - return NULL; + firm_file = fopen(path, "r"); + if (!firm_file) { + return NULL; + } } - size_t size = fsize(firm_file); + size = fsize(firm_file); if (size_out) *size_out = size; - uint8_t* mem = malloc(size); + mem = malloc(size); firm_h *firm = (firm_h*)mem; @@ -32,57 +41,84 @@ load_firm(const char *path, size_t *size_out) 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; + if (memcmp(firm->magic, "FIRM", 4)) { + char *key_path = strdupcat(path, ".key"); - struct firm_signature* sig = get_firm_info(firm); + // Attempt to open keyfile. + uint8_t* firmkey = malloc(16); + if (read_file(firmkey, key_path, 16) != 16) { + // Keyfile couldn't be opened, try the cetk. + free(firmkey); - patch_entry(firm, sig->type); - if (patch_section_keys(firm, sig->k9l)) { - free(mem); - return NULL; + // Encrypted. Open CETK. + char *cetk_path = strdupcat(path, ".cetk"); + firmkey = get_titlekey(cetk_path); + free(cetk_path); + + // Save firmkey. + FILE* keyfile = fopen(key_path, "w"); + fwrite(firmkey, 1, 16, keyfile); + fclose(keyfile); } - free(sig); - } else if (!memcmp(firm->magic, "FIRM", 4)) { - // O3DS fully decrypted FIRM + free(key_path); - firm = (firm_h*)mem; - } else { - // Encrypted. - char *cetk_path = strdupcat(path, ".cetk"); + if (firmkey) { + firm = extract_firm_from_ncch((ncch_h*)mem, firmkey, size); - uint8_t* firmkey = get_titlekey(cetk_path); + free(firmkey); - free(cetk_path); + if (!firm) { + free(mem); + return NULL; + } + } else { + free(mem); + return NULL; + } - if (firmkey) { - firm = extract_firm_from_ncch((ncch_h*)mem, firmkey, size); + save_dec = 1; + } - if (firm) { - struct firm_signature* sig = get_firm_info(firm); + sig = get_firm_info(firm); - if (sig->console == console_n3ds) { - if(dec_k9l(firm)) { - free(firm); - free(mem); - return NULL; - } + if (memcmp(firm->magic, "FIRM", 4)) { + // Error. Abort. + free(mem); + return NULL; + } - patch_entry(firm, sig->type); + // If this is a FIRM and not a k9l decrypted FIRM... + if (!memcmp(firm->magic, "FIRM", 4) && memcmp(firm->magic + 4, "DEC", 3)) { + if (sig->console == console_n3ds) { + if (dec_k9l(firm)) { + free(firm); + free(mem); + return NULL; + } + } + } - if (sig->type == type_native && patch_section_keys(firm, sig->k9l)) { - free(firm); - free(mem); - return NULL; - } - } + // Save decrypted FIRM. + if (save_dec == 1) { + firm_file = fopen(decpath, "w"); + fwrite(firm, 1, size, firm_file); + fclose(firm_file); + } + + free(decpath); + + // Arm9 decrypted firmware (n3ds)? + if (!memcmp(firm->magic, "FIRMDEC", 7)) { + if (sig->console == console_n3ds) { + patch_entry(firm, sig->type); - free(sig); + if (sig->type == type_native && patch_section_keys(firm, sig->k9l)) { + free(firm); + free(mem); + return NULL; } } - free(mem); } return firm; @@ -91,7 +127,7 @@ load_firm(const char *path, size_t *size_out) int prepatch_firm(const char* firm_path, const char* prepatch_path, const char* module_path) { - size_t size = 0; + size_t size = 0; firm_h* firm = load_firm(firm_path, &size); if (firm == NULL) @@ -109,23 +145,23 @@ prepatch_firm(const char* firm_path, const char* prepatch_path, const char* modu free(sig); if (patch_firm_all(tid, firm, module_path)) { - free(firm); + free(firm); return 1; - } + } - FILE* f = fopen(prepatch_path, "w"); - fwrite(firm, 1, size, f); - fclose(f); + FILE* f = fopen(prepatch_path, "w"); + fwrite(firm, 1, size, f); + fclose(f); - free(firm); + free(firm); - return 0; + return 0; } int boot_firm(const char* firm_path, const char* prepatch_path, const char* module_path) { - size_t size = 0; + size_t size = 0; firm_h* firm = load_firm(firm_path, &size); if (firm == NULL) @@ -143,13 +179,13 @@ boot_firm(const char* firm_path, const char* prepatch_path, const char* module_p free(sig); if (patch_firm_all(tid, firm, module_path)) { - free(firm); + free(firm); return 1; - } + } - FILE* f = fopen(prepatch_path, "w"); - fwrite(firm, 1, size, f); - fclose(f); + FILE* f = fopen(prepatch_path, "w"); + fwrite(firm, 1, size, f); + fclose(f); firmlaunch(firm); // <- should NOT return if all is well diff --git a/source/firm/keys.c b/source/firm/keys.c index 7894c64..44211b6 100644 --- a/source/firm/keys.c +++ b/source/firm/keys.c @@ -7,7 +7,7 @@ #include int set_N11_K9L(uint32_t index) { - static uint8_t ss_keyn[2][16] = { + static uint8_t ss_keyn[2][16] = { { 0 }, // 9.5 { 0 }, // 9.6+ }; @@ -32,25 +32,25 @@ int set_N11_K9L(uint32_t index) { setup_aeskey(0x11, (void*) ss_keyn[index]); - use_aeskey(0x11); + use_aeskey(0x11); - return 0; + return 0; } 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 - }; + // 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 + }; - setup_aeskeyY(0x3D, (void*) common_keyy[index]); + setup_aeskeyY(0x3D, (void*) common_keyy[index]); - use_aeskey(0x3D); + use_aeskey(0x3D); - return 0; + return 0; } diff --git a/source/firm/util.c b/source/firm/util.c index f16a90c..0b9d1d4 100644 --- a/source/firm/util.c +++ b/source/firm/util.c @@ -61,28 +61,28 @@ get_titlekey(char *cetk_filename) fclose(f); - uint8_t iv[AES_BLOCK_SIZE] = { 0 }; - uint32_t sigtype = __builtin_bswap32(*(const uint32_t *)cetk); + uint8_t iv[AES_BLOCK_SIZE] = { 0 }; + uint32_t sigtype = __builtin_bswap32(*(const uint32_t *)cetk); - if (sigtype != SIG_TYPE_RSA2048_SHA256) { + if (sigtype != SIG_TYPE_RSA2048_SHA256) { free(cetk); - return NULL; + return NULL; } - const ticket_h *ticket = (const ticket_h *)((const uint8_t*)cetk + sizeof(sigtype) + 0x13C); + const ticket_h *ticket = (const ticket_h *)((const uint8_t*)cetk + sizeof(sigtype) + 0x13C); set_Y3D_cetk(1); uint8_t *key = malloc(AES_BLOCK_SIZE); - memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); - memcpy(key, ticket->titleKey, sizeof(ticket->titleKey)); + memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); + memcpy(key, ticket->titleKey, sizeof(ticket->titleKey)); - cbc_decrypt(key, key, 1, AES_CNT_TITLEKEY_DECRYPT_MODE, iv); + cbc_decrypt(key, key, 1, AES_CNT_TITLEKEY_DECRYPT_MODE, iv); free(cetk); - return key; + return key; } int dec_k9l(firm_h* firm) { @@ -106,7 +106,7 @@ int dec_k9l(firm_h* firm) { sha256sum(arm9->hash, (uint8_t*)firm + arm9->offset, arm9->size); // Magic like D9. - memcpy(firm->magic, "DECFIRM", 7); + memcpy(firm->magic, "FIRMDEC", 7); free(sig); @@ -116,75 +116,75 @@ int dec_k9l(firm_h* firm) { 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 }; + 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); + 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; + if (ncch->magic != NCCH_MAGIC) { + return NULL; } - memcpy(exefs_key, ncch, AES_BLOCK_SIZE); - ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS); + 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; + // 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); + 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 + // 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; + // 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); + memcpy(dest, firm, size); - return dest; + 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; + 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 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_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); + uint8_t* key_data = key_search(key_loc, search_size, sha256, 0xDD); - if (!key_data) - return NULL; + if (!key_data) + return NULL; - return key_data; + return key_data; } int patch_section_keys(firm_h* firm_loc, uint32_t k9l) { @@ -211,21 +211,21 @@ int patch_section_keys(firm_h* firm_loc, uint32_t k9l) { exefs_h* find_proc9(firm_h *firm) { - for (firm_section_h *section = firm->section; section < firm->section + 4; section++) { - if (section->address == 0) - break; - if (section->type == FIRM_TYPE_ARM9) { - uint8_t* arm9section = memfind((uint8_t *)firm + section->offset, section->size, "Process9", 8); - if (!arm9section) - return NULL; - - ncch_h *ncch = (ncch_h *)((uint8_t*)arm9section - sizeof(ncch_h)); - if (ncch->magic == NCCH_MAGIC) { - // Found Process9 - ncch_ex_h *p9exheader = (ncch_ex_h *)(ncch + 1); - return (exefs_h *)(p9exheader + 1); - } - } - } - return NULL; + for (firm_section_h *section = firm->section; section < firm->section + 4; section++) { + if (section->address == 0) + break; + if (section->type == FIRM_TYPE_ARM9) { + uint8_t* arm9section = memfind((uint8_t *)firm + section->offset, section->size, "Process9", 8); + if (!arm9section) + return NULL; + + ncch_h *ncch = (ncch_h *)((uint8_t*)arm9section - sizeof(ncch_h)); + if (ncch->magic == NCCH_MAGIC) { + // Found Process9 + ncch_ex_h *p9exheader = (ncch_ex_h *)(ncch + 1); + return (exefs_h *)(p9exheader + 1); + } + } + } + return NULL; } diff --git a/source/main.c b/source/main.c index cb3135a..5d63a52 100644 --- a/source/main.c +++ b/source/main.c @@ -1,3 +1,4 @@ + #include #include #include @@ -48,32 +49,34 @@ main(int argc, char** argv) clear_disp(TOP_SCREEN); clear_disp(BOTTOM_SCREEN); - if (get_opt_u32(OPTION_AUTOBOOT) && !r_held) { - doing_autoboot = 1; + while (1) { + if (get_opt_u32(OPTION_AUTOBOOT) && !r_held && !doing_autoboot) { + doing_autoboot = 1; - if (get_opt_u32(OPTION_SILENCE)) - shut_up(); // This does exactly what it sounds like. - } else { - menu_handler(); - } + if (get_opt_u32(OPTION_SILENCE)) + shut_up(); // This does exactly what it sounds like. + } else { + menu_handler(); + } - if (changed_consoles) { - fprintf(stderr, "Console changed, regenerating caches\n"); - save_config(); - generate_patch_cache(); - } + if (changed_consoles) { + fprintf(stderr, "Console changed, regenerating caches\n"); + save_config(); + generate_patch_cache(); + } - if (prepatch_firm(config->firm[1], PATH_TWL_P, PATH_MODULE_TWL)) { - fprintf(stderr, "WARNING: Failed to load/patch TWL.\n"); - wait(); - } + if (prepatch_firm(config->firm[1], PATH_TWL_P, PATH_MODULE_TWL)) { + fprintf(stderr, "WARNING: Failed to load/patch TWL.\n"); + wait(); + } - if(prepatch_firm(config->firm[2], PATH_AGB_P, PATH_MODULE_AGB)) { - fprintf(stderr, "WARNING: Failed to load/patch AGB.\n"); - wait(); - } + if(prepatch_firm(config->firm[2], PATH_AGB_P, PATH_MODULE_AGB)) { + fprintf(stderr, "WARNING: Failed to load/patch AGB.\n"); + wait(); + } - boot_firm(config->firm[0], PATH_NATIVE_P, PATH_MODULE_NATIVE); + boot_firm(config->firm[0], PATH_NATIVE_P, PATH_MODULE_NATIVE); - panic("Firmlaunch failed!\n"); + fprintf(stderr, "Firmlaunch failed, returning to menu\n"); + } } -- 2.39.5