--- /dev/null
+Note that the branch name here is now a misnomer. It should be called wip/the_great_unclusterfuck now. Really.
+
+source/firm/firm.c
+ Has to GO. The time for cakes' decryptor has ended; time for a new one.
+ There's too many hacks and it has become an unmaintainable mess.
cmp r2, #4
bcc flush_dcache
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 // drain write buffer before jump
+
// Reload argc and argv.
ldr r0, argc
ldr r1, argv
-all: bdfe font
+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:
make -C bdfe
clean:
make -C bdfe clean
- rm -f termfont.bin
+ rm -f termfont.bin key_char error_decoder
--- /dev/null
+#!/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 ""
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <openssl/sha.h>
+
+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 <key>\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;
+}
#include <std/allocator.h>
#include <firm/decryptor.h>
#include <firm/firm.h>
+#include <firm/keys.h>
#include <menu.h>
#include <menu-backend.h>
enum firm_type type; ///< Type of FIRM.
};
-extern firm_h *firm_loc;
-extern uint32_t firm_size;
-extern struct firm_signature *current_firm;
-extern firm_section_h firm_proc9;
-extern exefs_h *firm_p9_exefs;
-
-extern firm_h *twl_firm_loc;
-extern uint32_t twl_firm_size;
-extern struct firm_signature *current_twl_firm;
-extern firm_section_h twl_firm_proc9;
-extern exefs_h *twl_firm_p9_exefs;
-
-extern firm_h *agb_firm_loc;
-extern uint32_t agb_firm_size;
-extern struct firm_signature *current_agb_firm;
-extern firm_section_h agb_firm_proc9;
-extern exefs_h *agb_firm_p9_exefs;
-
/* Returns a struct describing the version of a decrypted FIRM
*/
struct firm_signature *get_firm_info(firm_h *firm);
-/* Initializes 0x11 KeyY
- */
-void slot0x11key96_init();
-
-/* Extracts 0x05 KeyY from FIRM0 on NAND
- */
-void extract_slot0x05keyY();
-
-/* Extracts 0x3D KeyY from FIRM0 on NAND
- */
-void extract_slot0x3DkeyY();
-
-/* Loads FIRM files
- */
-int load_firms();
-
/* Boots native FIRM - do not call directly.
*/
void boot_firm();
/* Loads a firmware off disk, returning it. The memory should be free()'d when done, unless you plan to boot.
*/
-firm_h* load_firm(const char *path, const char *path_firmkey, const char *path_cetk, uint32_t *size);
+firm_h* load_firm(const char *path);
#endif
--- /dev/null
+#ifndef __FIRM_KEYS_H
+#define __FIRM_KEYS_H
+
+// See the D9 source code (by @d0k3) for info on these defines and structs:
+// https://github.com/d0k3/Decrypt9WIP/blob/master/source/decryptor/keys.h
+
+#define KEY_ENCRYPT (1<<0)
+#define KEY_DECRYPT (1<<1)
+
+#define KEYS_UNKNOWN 0
+#define KEYS_RETAIL 1
+#define KEYS_DEVKIT 2
+
+typedef struct {
+ uint8_t slot; // keyslot, 0x00...0x3F
+ char type; // type 'X' / 'Y' / 'N' for normalKey
+ char id[10]; // key ID for special keys, all zero for standard keys
+ uint8_t reserved[2]; // reserved space
+ uint8_t isDevkitKey; // 0 for retail units / 1 for DevKit units
+ uint8_t isEncrypted; // 0 if not / anything else if it is
+ uint8_t key[16];
+} __attribute__((packed)) aeskeydbent_t;
+
+typedef struct {
+ uint16_t roll;
+ uint8_t sha[32];
+ uint8_t key[16];
+} key_find_t;
+
+#endif
#include <stdint.h>
-void patch_emunand(uint32_t size);
+void patch_emunand(firm_h* firm_loc, uint32_t size);
#endif
#include <stdint.h>
// Build patch into CFW instead of as module.
-#define PATCH(name) int patch_##name()
+#define PATCH(name) int patch_##name(firm_h* firm_loc)
#endif
#define PATH_TWL_FIRMKEY PATH_KEYS "/twl.key" ///< TWL FIRM decrypted titlekey
#define PATH_AGB_FIRMKEY PATH_KEYS "/agb.key" ///< AGB FIRM decrypted titlekey
-#define PATH_SLOT0X11KEY96 PATH_KEYS "/11Key96.key" ///< 0x11 KeyY (for 9.6 FIRM arm9loader)
-
-#define PATH_ALT_SLOT0X11KEY96 "/slot0x11key96.bin" ///< Alternate path for 0x11 KeyY
+#define PATH_SLOT0X11KEY95 "/slot0x11key95.bin" ///< Alternate path for 0x11 KeyY
+#define PATH_SLOT0X11KEY96 "/slot0x11key96.bin" ///< Alternate path for 0x11 KeyY
#define PATH_LOG LOCALSTATEDIR "/log" ///< Log directory
inc_dir = $(top_srcdir)/include
-corbenik_SOURCES = patch/reboot.c patch/svc.c patch/module.c patch/emunand.c main.c std/fs.c std/draw.c std/memory.c std/abort.c std/allocator.c menu.c firm/version.c firm/firm.c firm/decryptor.c interpreter.c input.c patcher.c chainloader.c config-backend-file.c menu-backend.c start.s interrupt.c arm11.c
+corbenik_SOURCES = patch/reboot.c patch/svc.c patch/module.c patch/emunand.c main.c std/fs.c std/draw.c std/memory.c std/abort.c std/allocator.c menu.c firm/util.c firm/keys.c firm/firmlaunch.c firm/version.c firm/firm.c firm/decryptor.c interpreter.c input.c patcher.c chainloader.c config-backend-file.c menu-backend.c start.s interrupt.c arm11.c
-/*
- This is all fairly minimal and based on @d0k3's decrypt9 code.
-*/
-
#include <common.h>
#include <ctr9/aes.h>
#include <ctr9/sha.h>
#include <ctr9/sha.h>
#include <common.h>
-firm_h *firm_loc = NULL;
-uint32_t firm_size = FCRAM_SPACING;
-firm_section_h firm_proc9;
-exefs_h *firm_p9_exefs;
-
-firm_h *twl_firm_loc = NULL;
-uint32_t twl_firm_size = FCRAM_SPACING * 2;
-firm_section_h twl_firm_proc9;
-exefs_h *twl_firm_p9_exefs;
-
-firm_h *agb_firm_loc = NULL;
-uint32_t agb_firm_size = FCRAM_SPACING * 2;
-firm_section_h agb_firm_proc9;
-exefs_h *agb_firm_p9_exefs;
-
-firm_h* firm0 = NULL;
-firm_h* firm1 = NULL;
-
-static int update_96_keys = 0;
-
-static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8;
-
-// Fwd decl
-int decrypt_arm9bin(arm9bin_h *header, struct firm_signature *sig);
-
-#define SECTOR_SIZE 0x200
-
-// 0x0B130000 = start of FIRM0 partition, 0x400000 = size of FIRM partition (4MB)
-void dump_firm(firm_h** buffer, uint8_t index) {
- if (*buffer != NULL) return;
-
- // 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
-
- buffer[0] = malloc(firm_b_size);
-
- uint8_t ctr[0x10],
- cid[0x10],
- sha_t[0x20];
-
- firm_h* firm = buffer[0];
-
- if (sdmmc_nand_readsectors(firm_offset / SECTOR_SIZE, firm_b_size / SECTOR_SIZE, (uint8_t*)firm))
- abort(" Failed to read NAND!\n");
-
- fprintf(stderr, " Read FIRM%u off NAND.\n", index);
-
- 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);
-
- use_aeskey(0x06);
- set_ctr(ctr);
- ctr_decrypt(firm, firm, firm_b_size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, ctr);
-
- if (memcmp((char*) & firm->magic, "FIRM", 4))
- abort(" Decryption failed on FIRM.\n");
-
- fprintf(stderr, " AES decrypted FIRM%u.\n", index);
-
- fprintf(stderr, " Magic is intact on FIRM%u.\n", index);
-
- struct firm_signature* sig = get_firm_info(firm);
-
- sig->k9l = 0;
- if(index == 1)
- sig->k9l = 2;
-
- fprintf(stderr, " FIRM: K9L%u, Console:%u, Type:%u\n", sig->k9l, sig->console, sig->type);
-
- if(decrypt_arm9bin((arm9bin_h*)((uint8_t*)firm + firm->section[2].offset), sig)) {
- abort(" Failed to decrypt FIRM%u arm9loader.\n", index);
- }
-
- free(sig);
-
- fprintf(stderr, " Decrypted FIRM%u arm9loader.\n", index);
-}
-
-void
-slot0x11key96_init()
-{
- // 9.6 crypto may need us to get the key from somewhere else.
- // Unless the console already has the key initialized, that is.
- uint8_t key[AES_BLOCK_SIZE];
- if (read_file(key, PATH_SLOT0X11KEY96, AES_BLOCK_SIZE) != 0 || read_file(key, PATH_ALT_SLOT0X11KEY96, AES_BLOCK_SIZE) != 0) {
- // Read key successfully.
- setup_aeskey(0x11, key);
-
- // Tell boot_firm it needs to regenerate the keys.
- update_96_keys = 1;
- }
-}
-
-uint8_t* key_search(uint8_t* mem, uint32_t size, uint8_t* sha256, uint8_t byte) {
- uint8_t hash[0x20] = {0};
-
- // Search ARM9 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 extract_slot0x05keyY() {
- if (firm0 == NULL)
- dump_firm(&firm0, 0);
-
- uint8_t sha256[] = {0x98, 0x24, 0x27, 0x14, 0x22, 0xB0, 0x6B, 0xF2, 0x10, 0x96, 0x9C, 0x36, 0x42, 0x53, 0x7C, 0x86,
- 0x62, 0x22, 0x5C, 0xFD, 0x6F, 0xAE, 0x9B, 0x0A, 0x85, 0xA5, 0xCE, 0x21, 0xAA, 0xB6, 0xC8, 0x4D};
-
- uint8_t* key_loc = (uint8_t*)firm0 + firm0->section[2].offset;
- uint32_t search_size = firm0->section[2].size;
-
- uint8_t mem[16] __attribute__((aligned(4))) = {0};
-
- uint8_t* key_data = key_search(key_loc, search_size, sha256, 0x4D);
-
- if (!key_data)
- abort(" 0x05 KeyY not found!\n");
-
- fprintf(stderr, " 0x05 KeyY at %lx in FIRM1\n", (uint32_t)key_data - (uint32_t)key_loc);
-
- memcpy(mem, key_data, 16);
-
- setup_aeskeyY(0x05, mem);
-}
-
-void extract_slot0x3DkeyY() {
- if (firm0 == NULL)
- dump_firm(&firm0, 0);
-
- uint8_t sha256[] = {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};
-
- uint8_t* key_loc = (uint8_t*)firm0 + firm0->section[2].offset;
- uint32_t search_size = firm0->section[2].size;
-
- uint8_t mem[16] __attribute__((aligned(4))) = {0};
-
- uint8_t* key_data = key_search(key_loc, search_size, sha256, 0x0C);
-
- if (!key_data)
- abort(" 0x3D KeyY #1 not found!\n");
-
- fprintf(stderr, " 0x3D KeyY #1 at %lx in FIRM0\n", (uint32_t)key_data - (uint32_t)key_loc);
-
- memcpy(mem, key_data, 16);
-
- setup_aeskeyY(0x3D, mem);
-}
-
-void* find_section_key() {
- // The key will be dword-aligned (I think? Verify this. May need new NFIRM to check assumption. Go, Nintendo!)
-
- // 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};
- 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)
- abort(" FIRM Section key not found!\n");
-
- fprintf(stderr, " FIRM Section key at %lx in FIRM\n", (uint32_t)key_data - (uint32_t)key_loc);
-
- return key_data;
-}
-
-int
-decrypt_cetk_key(void *key, const void *cetk)
-{
- static int got_cetk = 0;
- uint8_t iv[AES_BLOCK_SIZE] = { 0 };
- uint32_t sigtype = __builtin_bswap32(*(const uint32_t *)cetk);
-
- if (sigtype != SIG_TYPE_RSA2048_SHA256)
- return 1;
-
- const ticket_h *ticket = (const ticket_h *)((const uint8_t*)cetk + sizeof(sigtype) + 0x13C);
- if (ticket->ticketCommonKeyYIndex != 1)
- return 1;
-
- if (got_cetk == 0) {
- fprintf(stderr, " Retrieving 0x3D KeyY...\n");
- extract_slot0x3DkeyY();
- got_cetk = 1;
- }
-
- use_aeskey(0x3D);
-
- 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);
-
- fprintf(stderr, " Extracted titlekey from cetk.\n");
-
- return 0;
-}
-
-int
-decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key)
-{
- uint8_t firm_iv[16] = { 0 };
- uint8_t exefs_key[16] = { 0 };
- uint8_t exefs_iv[16] = { 0 };
-
- fprintf(stderr, " Decrypting FIRM container (size is %lu blocks)\n", *size / AES_BLOCK_SIZE);
-
- setup_aeskey(0x16, key);
- use_aeskey(0x16);
-
- cbc_decrypt(ncch, ncch, *size / AES_BLOCK_SIZE, AES_CNT_CBC_DECRYPT_MODE, firm_iv);
-
- if (ncch->magic != NCCH_MAGIC)
- return 1;
-
- 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;
-
- fprintf(stderr, " Decrypting ExeFs for FIRM (size is %lu blocks)\n", exefs_size / AES_BLOCK_SIZE);
-
- 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 (firm->magic != FIRM_MAGIC)
- return 1;
-
- memcpy(dest, firm, *size);
-
- return 0;
-}
-
-int
-decrypt_arm9bin(arm9bin_h *header, struct firm_signature *sig)
-{
- uint8_t slot = 0x15;
-
- if (sig->type == type_native && sig->k9l >= 2) {
- uint8_t decrypted_keyx[AES_BLOCK_SIZE];
-
- slot0x11key96_init();
- slot = 0x16;
-
- use_aeskey(0x11);
- ecb_decrypt(header->slot0x16keyX, decrypted_keyx, 1, AES_CNT_ECB_DECRYPT_MODE);
- setup_aeskeyX(slot, decrypted_keyx);
- }
-
- setup_aeskeyY(slot, header->keyy);
- set_ctr(header->ctr);
-
- void *arm9bin = (uint8_t *)header + 0x800;
- int size = atoi(header->size);
-
- use_aeskey(slot);
- ctr_decrypt(arm9bin, arm9bin, (size_t)size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, header->ctr);
-
- if (sig->type == type_native && *(uint32_t *)arm9bin == ARM9BIN_MAGIC)
- return 0;
-
- else if ((sig->type == type_twl || sig->type == type_agb) && *(uint32_t *)arm9bin == LGY_ARM9BIN_MAGIC)
- return 0;
-
- return 1;
-}
-
-int
-decrypt_firm(firm_h *dest, const char *path_firmkey, const char *path_cetk, uint32_t *size)
-{
- uint8_t firm_key[AES_BLOCK_SIZE];
-
- // Firmware is likely encrypted. Decrypt.
- if (!read_file(firm_key, path_firmkey, AES_BLOCK_SIZE)) {
- uint8_t* temp = malloc(FCRAM_SPACING);
- // Missing firmkey. Attempt to get from CETK (only works if system was booted)
- if (!read_file(temp, path_cetk, FCRAM_SPACING) || decrypt_cetk_key(firm_key, temp)) {
- fprintf(stderr, " No firmkey and failed to extract from cetk\n");
- return 1;
- } else {
- fprintf(stderr, " Saving firmkey for future use.\n");
- write_file(firm_key, path_firmkey, AES_BLOCK_SIZE);
- }
- free(temp);
- } else {
- fprintf(stderr, " Read firmkey from filesystem.\n");
- }
-
- fprintf(stderr, " Decrypting FIRM\n");
- if (decrypt_firm_title(dest, (void *)dest, size, firm_key) != 0) {
- fprintf(stderr, " Failed to decrypt FIRM title.\n");
- return 1;
- }
- return 0;
-}
-
-extern int patch_services();
-
-firm_h*
-load_firm(const char *path, const char *path_firmkey, const char *path_cetk, uint32_t *size)
-{
- if (path == NULL || path_firmkey == NULL || path_cetk == NULL || size == NULL)
- return NULL;
-
- firm_h *dest;
-
- int status = 0;
- int firmware_changed = 0;
-
- FILE* f = fopen(path, "r");
- if (!f) {
- fprintf(stderr, " FIRM file is missing.\n");
- return NULL;
- }
- *size = fsize(f);
-
- dest = (firm_h*)malloc(*size);
-
- fread(dest, 1, *size, f);
-
- fclose(f);
- fprintf(stderr, " Loaded FIRM off filesystem\n");
-
- // Check and decrypt FIRM if it is encrypted.
- if (dest->magic != FIRM_MAGIC) {
- status = decrypt_firm(dest, path_firmkey, path_cetk, size);
- if (status != 0) {
- fprintf(stderr, " Decryption seems to have failed\n");
- return NULL;
- }
- firmware_changed = 1; // Decryption performed.
- } else {
- fprintf(stderr, " FIRM is decrypted\n");
- }
-
- struct firm_signature *fsig = get_firm_info(dest);
-
- fprintf(stderr, " FIRM: K9L%u, Console:%u, Type:%u\n", fsig->k9l, fsig->console, fsig->type);
-
- // The N3DS firm has an additional encryption layer for ARM9
- if (fsig->console == console_n3ds) {
- // Look for the arm9 section
- for (firm_section_h *section = dest->section; section < dest->section + 4; section++) {
- if (section->type == FIRM_TYPE_ARM9) {
- // Check whether the arm9bin is encrypted.
- int arm9bin_iscrypt = 0;
- uint32_t magic = *(uint32_t *)((uintptr_t)dest + section->offset + 0x800);
- if (fsig->type == type_native)
- arm9bin_iscrypt = (magic != ARM9BIN_MAGIC);
- else if (fsig->type == type_twl || fsig->type == type_agb)
- arm9bin_iscrypt = (magic != LGY_ARM9BIN_MAGIC);
-
- if (arm9bin_iscrypt) {
- // Decrypt the arm9bin.
- fprintf(stderr, " ARM9 segment is encrypted\n");
- if (decrypt_arm9bin((arm9bin_h *)((uintptr_t)dest + section->offset), fsig)) {
- fprintf(stderr, " ARM9 segment failed to decrypt\n");
- return NULL;
- }
- firmware_changed = 1; // Decryption of arm9bin performed.
- } else {
- fprintf(stderr, " ARM9 segment is decrypted\n");
- if (fsig->type == type_native && fsig->k9l >= 2) {
- slot0x11key96_init(); // This has to be loaded
- // regardless, otherwise boot will
- // fail.
- }
- }
-
- // We assume there's only one section to decrypt.
- break;
- }
- }
- }
-
- // Save firmware.bin if decryption was done.
- if (firmware_changed) {
- fprintf(stderr, " Overwriting FIRM with decrypted FIRM\n");
- write_file(dest, path, *size);
- }
-
- if (fsig->console == console_n3ds) {
- fprintf(stderr, " Patching arm9 entrypoint\n");
-
- // Patch the entrypoint to skip arm9loader
- if (fsig->type == type_native) {
- dest->a9Entry = 0x0801B01C;
- } else if (fsig->type == type_twl || fsig->type == type_agb) {
- dest->a9Entry = 0x0801301C;
- }
- // The entrypoints seem to be the same across different FIRM versions,
- // so we don't change them.
- }
-
- fprintf(stderr, " Loaded.\n");
-
- free(fsig);
-
- return dest;
-}
-
__attribute__ ((noreturn))
void
-boot_firm()
+boot_firm(firm_h* firm)
{
- struct firm_signature *fsig = get_firm_info(firm_loc);
-
- fprintf(stderr, " FIRM: K9L%u, Console:%u, Type:%u\n", fsig->k9l, fsig->console, fsig->type);
-
- // Set up the keys needed to boot a few firmwares, due to them being unset,
- // depending on which firmware you're booting from.
- // TODO: Don't use the hardcoded offset.
- if (update_96_keys && fsig->console == console_n3ds && fsig->k9l >= 2) {
- uint8_t *keydata = find_section_key();
- if (!keydata) {
- abort("Couldn't find section key.\n");
- }
-
- wait();
-
- use_aeskey(0x11);
- uint8_t keyx[AES_BLOCK_SIZE];
- for (int slot = 0x19; slot < 0x20; slot++) {
- ecb_decrypt(keydata, keyx, 1, AES_CNT_ECB_DECRYPT_MODE);
- setup_aeskeyX(slot, keyx);
- *(uint8_t *)(keydata + 0xF) += 1;
- }
-
- fprintf(stderr, "Updated keyX keyslots.\n");
- }
-
- free(fsig);
-
-#ifdef MALLOC_DEBUG
- print_alloc_stats();
- wait();
-#endif
-
- uint32_t entry11 = firm_loc->a11Entry;
- uint32_t entry9 = firm_loc->a9Entry;
-
- // Beyond this point, using malloc() memory is unsafe, since we're trashing memory possibly.
- // free() is also irrelevant from here on.
-
- for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4 && section->address != 0; section++) {
- memmove((void *)section->address, (void *)((uint8_t*)firm_loc + section->offset), section->size);
- }
- fprintf(stderr, "Copied FIRM.\n");
-
- wait();
-
- clear_disp(stderr);
- set_cursor(stderr, 0, 0);
-
- fflush(stderr); // Flush logs if need be before unmount.
-
- fumount(); // Unmount SD. No longer needed.
-
- // No fprintf will work from here on out.
-
- deinitScreens();
-
- *a11_entry = (uint32_t)entry11;
-
- ((void (*)())entry9)();
-
+ abort("Temporarily not implemented\n");
while(1);
}
-int
-find_proc9(firm_h *firm, firm_section_h *process9, exefs_h **p9exefs)
-{
- 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 = (uint8_t *)firm + section->offset;
- while (arm9section < arm9section + section->size) {
- if (!memcmp(arm9section, "Process9", 8)) { // Process9
- 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);
- *p9exefs = (exefs_h *)(p9exheader + 1);
- process9->address = p9exheader->sci.textCodeSet.address;
- process9->size = (*p9exefs)->fileHeaders[0].size;
- process9->offset = (uint32_t)((*p9exefs) + 1) - (uint32_t)firm;
- fprintf(stderr, " Found process9 offset\n");
- return 0;
- }
- }
- ++arm9section;
- }
- }
- }
- fprintf(stderr, " Couldn't find Process9?\n");
- return 1;
-}
-
int firm_loaded = 0;
-int
-load_firms()
+firm_h*
+load_firm(const char *path)
{
- int state = 0;
-
- if (firm_loaded)
- return 0;
-
- fprintf(stderr, "FIRM load triggered.\n");
-
- fprintf(stderr, "Loading NATIVE_FIRM\n");
- if ((firm_loc = load_firm(get_opt((void*)OPTION_NFIRM_PATH), PATH_NATIVE_FIRMKEY, PATH_NATIVE_CETK, &firm_size)) == NULL) {
- abort("\n Failed to load NATIVE_FIRM.\n");
- }
- find_proc9(firm_loc, &firm_proc9, &firm_p9_exefs);
-
- fprintf(stderr, "TWL_FIRM\n");
- if ((twl_firm_loc = load_firm(get_opt((void*)OPTION_TFIRM_PATH), PATH_TWL_FIRMKEY, PATH_TWL_CETK, &twl_firm_size)) == NULL) {
- fprintf(stderr, "\n TWL_FIRM failed to load.\n");
- state = 1;
- } else {
- find_proc9(twl_firm_loc, &twl_firm_proc9, &twl_firm_p9_exefs);
- }
-
- fprintf(stderr, "AGB_FIRM\n");
- if ((agb_firm_loc = load_firm(get_opt((void*)OPTION_AFIRM_PATH), PATH_AGB_FIRMKEY, PATH_AGB_CETK, &agb_firm_size)) == NULL) {
- fprintf(stderr, "\n AGB_FIRM failed to load.\n");
- state = 1;
- } else {
- find_proc9(agb_firm_loc, &agb_firm_proc9, &agb_firm_p9_exefs);
- }
-
- firm_loaded = 1; // Loaded.
-
- return state;
+ return NULL;
}
+
void
-boot_cfw()
+boot_cfw(char* firm_path)
{
- load_firms();
+ firm_h* firm = load_firm(firm_path);
fprintf(stderr, "Patching firmware...\n");
- if (patch_firm_all() != 0)
+ if (patch_firm_all(firm) != 0)
return;
- if (get_opt_u32(OPTION_REBOOT)) {
- fprintf(stderr, "Saving FIRM for reboot...\n");
- if (!write_file(firm_loc, PATH_NATIVE_P, firm_size))
- abort("Failed to save prepatched native\n");
-
- if (!write_file(twl_firm_loc, PATH_TWL_P, twl_firm_size))
- abort("Failed to save prepatched twl\n");
-
- if (!write_file(agb_firm_loc, PATH_AGB_P, agb_firm_size))
- abort("Failed to save prepatched agb\n");
- }
-
- boot_firm();
+ boot_firm(firm);
}
--- /dev/null
+#include <common.h>
+#include <ctr9/aes.h>
+#include <ctr9/sha.h>
+
+typedef void (*void_call)();
+
+static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8;
+
+void firmlaunch(firm_h* firm) {
+ // Get entrypoints
+ uint32_t entry11 = firm->a11Entry;
+ void_call entry9 = (void_call)firm->a9Entry;
+
+ // Copy sections from FIRMs to their destination.
+ for (firm_section_h *section = firm->section; section < firm->section + 4 && section->address != 0; section++) {
+ memmove((void *)section->address, (void *)((uint8_t*)firm + section->offset), section->size);
+ }
+
+ fflush(stderr); // Flush logs if need be before unmount.
+
+ fumount(); // Unmount SD.
+
+ deinitScreens(); // Turn off display
+
+ *a11_entry = (uint32_t)entry11; // Start kernel11
+
+ entry9(); // Start process9
+}
+
--- /dev/null
+#include <common.h>
+
+#include <ctr9/aes.h>
+#include <ctr9/sha.h>
+
+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];
+ }
+ }
+
+ 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 (get_Y05()) {
+ // Pretty much a warning and nothing else atm.
+ level |= 8;
+ }
+#endif
+
+ return level;
+}
+
+int set_Y3D_common(int commonKeyIndex) {
+ setup_aeskeyY(0x3D, (void*) Y3D[commonKeyIndex].key);
+
+ use_aeskey(0x3D);
+
+ return 0;
+}
+
+int set_Y05() {
+ // N3DS nand key
+ setup_aeskeyY(0x05, Y05.key);
+
+ use_aeskey(0x05);
+
+ return 0;
+}
+
+int set_Y11_K9L(int index) {
+ setup_aeskey(0x11, Y11[index].key);
+
+ use_aeskey(0x11);
+
+ return 0;
+}
--- /dev/null
+{.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} }
--- /dev/null
+{.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} },
--- /dev/null
+{.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} },
--- /dev/null
+{.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} },
--- /dev/null
+{.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} },
--- /dev/null
+{.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} },
--- /dev/null
+{.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} }
--- /dev/null
+#include <stdint.h>
+#include <stddef.h>
+
+#include <ctr9/io.h>
+#include <ctr9/aes.h>
+#include <ctr9/sha.h>
+#include <common.h>
+
+#define SECTOR_SIZE 0x200
+
+int decrypt_k9l(arm9bin_h *header, enum firm_type type) {
+ uint8_t slot = 0x15;
+
+ if (type == type_native) {
+ uint8_t decrypted_keyx[AES_BLOCK_SIZE];
+
+ slot = 0x16;
+
+ use_aeskey(0x11);
+ ecb_decrypt(header->slot0x16keyX, decrypted_keyx, 1, AES_CNT_ECB_DECRYPT_MODE);
+ setup_aeskeyX(slot, decrypted_keyx);
+ }
+
+ setup_aeskeyY(slot, header->keyy);
+
+ set_ctr(header->ctr);
+
+ void *arm9bin = (uint8_t *)header + 0x800;
+ int size = atoi(header->size); // Size is plaintext, don't ask me *shrug*
+
+ use_aeskey(slot);
+
+ 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;
+
+ return 1; // Failed.
+}
+
+void fix_entry(firm_h* firm, enum firm_type type) {
+ // Patch the entrypoint to skip arm9loader
+ 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.
+}
+
+// 0x0B130000 = start of FIRM0 partition, 0x400000 = size of FIRM partition (4MB)
+firm_h* dump_firm(firm_h* buffer, uint8_t index) {
+ firm_h* firm;
+
+ // 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
+
+ firm = malloc(firm_b_size);
+
+ uint8_t ctr[0x10],
+ cid[0x10],
+ sha_t[0x20];
+
+ if (sdmmc_nand_readsectors(firm_offset / SECTOR_SIZE, firm_b_size / SECTOR_SIZE, (uint8_t*)firm))
+ goto failure;
+
+ 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);
+
+ use_aeskey(0x06);
+ set_ctr(ctr);
+ ctr_decrypt(firm, firm, firm_b_size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, ctr);
+
+ if (memcmp((char*) & firm->magic, "FIRM", 4))
+ goto failure;
+
+ return firm;
+
+failure:
+ free(firm);
+
+ return NULL;
+}
+
+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};
+
+ 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)
+ abort(" FIRM Section key not found!\n");
+
+ fprintf(stderr, " FIRM Section key at %lx in FIRM\n", (uint32_t)key_data - (uint32_t)key_loc);
+ return key_data;
+#endif
+ return NULL;
+}
+
+int set_section_keys(firm_h* firm_loc) {
+ // 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);
+ uint8_t keyx[AES_BLOCK_SIZE];
+ for (int slot = 0x19; slot < 0x20; slot++) {
+ ecb_decrypt(keydata, keyx, 1, AES_CNT_ECB_DECRYPT_MODE);
+ setup_aeskeyX(slot, keyx);
+ *(uint8_t *)(keydata + 0xF) += 1;
+ }
+
+ return 0;
+}
static uint8_t stack_glob[STACK_SIZE];
#else
static uint8_t *stack_glob = NULL;
+ firm_h* firm_patch;
#endif
int
{
if (!init_bytecode) {
#ifndef LOADER
- modes[0].memory = (uint8_t *)firm_loc;
- modes[0].size = firm_loc->section[0].size + firm_loc->section[1].size + sizeof(firm_h) +
- firm_loc->section[2].size + firm_loc->section[3].size; // NATIVE_FIRM
-
- modes[1].memory = (uint8_t *)agb_firm_loc;
- modes[1].size = agb_firm_loc->section[0].size + agb_firm_loc->section[1].size + sizeof(firm_h) +
- agb_firm_loc->section[2].size + agb_firm_loc->section[3].size; // AGB_FIRM
-
- modes[2].memory = (uint8_t *)twl_firm_loc;
- modes[2].size = twl_firm_loc->section[0].size + twl_firm_loc->section[1].size + sizeof(firm_h) +
- twl_firm_loc->section[2].size + twl_firm_loc->section[3].size; // TWL_FIRM
-
- // NATIVE_FIRM Process9 (This is also the default mode.)
- modes[3].memory = (uint8_t *)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
- modes[3].size = firm_p9_exefs->fileHeaders[0].size;
- // AGB_FIRM Process9
- modes[4].memory = (uint8_t *)agb_firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
- modes[4].size = firm_p9_exefs->fileHeaders[0].size;
- // TWL_FIRM Process9
- modes[5].memory = (uint8_t *)twl_firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
- modes[5].size = firm_p9_exefs->fileHeaders[0].size;
-
- // NATIVE_FIRM Sect 0
- modes[6].memory = (uint8_t *)firm_loc + firm_loc->section[0].offset;
- modes[6].size = firm_loc->section[0].size;
- // NATIVE_FIRM Sect 1
- modes[7].memory = (uint8_t *)firm_loc + firm_loc->section[1].offset;
- modes[7].size = firm_loc->section[1].size;
- // NATIVE_FIRM Sect 2
- modes[8].memory = (uint8_t *)firm_loc + firm_loc->section[2].offset;
- modes[8].size = firm_loc->section[2].size;
- // NATIVE_FIRM Sect 3
- modes[9].memory = (uint8_t *)firm_loc + firm_loc->section[3].offset;
- modes[9].size = firm_loc->section[3].size;
-
- // AGB_FIRM Sect 0
- modes[10].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[0].offset;
- modes[10].size = agb_firm_loc->section[0].size;
- // AGB_FIRM Sect 1
- modes[11].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[1].offset;
- modes[11].size = agb_firm_loc->section[1].size;
- // AGB_FIRM Sect 2
- modes[12].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[2].offset;
- modes[12].size = agb_firm_loc->section[2].size;
- // AGB_FIRM Sect 3
- modes[13].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[3].offset;
- modes[13].size = agb_firm_loc->section[3].size;
-
- // TWL_FIRM Sect 0
- modes[14].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[0].offset;
- modes[14].size = twl_firm_loc->section[0].size;
- // TWL_FIRM Sect 1
- modes[15].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[1].offset;
- modes[15].size = twl_firm_loc->section[1].size;
- // TWL_FIRM Sect 2
- modes[16].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[2].offset;
- modes[16].size = twl_firm_loc->section[2].size;
- // TWL_FIRM Sect 3
- modes[17].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[3].offset;
- modes[17].size = twl_firm_loc->section[3].size;
+ 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;
}
void
-patch_emunand(uint32_t index)
+patch_emunand(firm_h* firm_loc, uint32_t index)
{
+#if 0
// ARM9 section.
uint8_t *arm9Section = (uint8_t *)firm_loc + firm_loc->section[2].offset;
uint32_t arm9SectionSize = firm_loc->section[2].size;
patchMPU(arm9Section, arm9SectionSize);
fprintf(stderr, "emunand: patched MPU settings\n");
+#endif
}
// FIXME - We're potentially corrupting memory here depending on whether we go over the theoretical maximum size of FIRM
+ // SUPER FIXME 9000: DO NOT LEAVE AS IS.
memmove((uint8_t *)sysmodule + module->contentSize * 0x200, (uint8_t *)sysmodule + sysmodule->contentSize * 0x200,
- ((uint32_t)firm_modules + firm_size) - ((uint32_t)sysmodule + (module->contentSize * 0x200)));
+ ((uint32_t)firm_modules + 0x100000) - ((uint32_t)sysmodule + (module->contentSize * 0x200)));
sysmodule_section->size += 0x200 * need_units;
for (int i = 1; i < 4; i++) {
}
int
-patch_modules()
+patch_modules(firm_h* firm_loc)
{
firm_modules = firm_loc;
recurse_call(PATH_MODULE_NATIVE, inject_module);
- firm_modules = twl_firm_loc;
- recurse_call(PATH_MODULE_TWL, inject_module);
- firm_modules = agb_firm_loc;
- recurse_call(PATH_MODULE_AGB, inject_module);
return 0;
}
}
void
-patch_reboot()
+patch_reboot(firm_h* firm_loc)
{
// Look for firmlaunch code
const uint8_t pattern[] = { 0xDE, 0x1F, 0x8D, 0xE2 };
// This code handles restoration of backdoor
int
-patch_services()
+patch_svc_calls(firm_h* firm_loc)
{
if (svc_offs_init == 0) {
arm11Section1 = (uint8_t *)firm_loc + firm_loc->section[1].offset;
// TODO - Basically all this needs to move to patcher programs.
-extern int patch_services();
-extern int patch_modules();
-extern int patch_reboot();
+extern int patch_svc_calls(firm_h*);
+extern int patch_modules(firm_h*);
+extern int patch_reboot(firm_h*);
extern int doing_autoboot;
}
int
-patch_firm_all()
+patch_firm_all(firm_h* firm)
{
execb(PATH_LOADER_CACHE "/BOOT", 0);
// Hook firmlaunch?
if (get_opt_u32(OPTION_REBOOT)) {
- patch_reboot();
+ patch_reboot(firm);
wait();
}
// Use EmuNAND?
if (get_opt_u32(OPTION_EMUNAND)) {
// Yes.
- patch_emunand(get_opt_u32(OPTION_EMUNAND_INDEX));
+ patch_emunand(firm, get_opt_u32(OPTION_EMUNAND_INDEX));
wait();
}
// Inject services?
if (get_opt_u32(OPTION_SVCS)) {
- if (patch_services()) {
+ if (patch_svc_calls(firm)) {
abort("Fatal. Svc inject has failed.");
}
wait();
// Replace loader?
if (get_opt_u32(OPTION_LOADER)) {
- if (patch_modules()) {
+ if (patch_modules(firm)) {
abort("Fatal. Loader inject has failed.");
}
// This requires OPTION_SIGPATCH.