]> Chaos Git - corbenik/corbenik.git/commitdiff
it's a beautiful day outside.
authorchaoskagami <chaos.kagami@gmail.com>
Sat, 3 Sep 2016 14:15:51 +0000 (10:15 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Sat, 3 Sep 2016 14:22:19 +0000 (10:22 -0400)
birds are chirping,

flowers are blooming.

on days like these, code like you...

s h o u l d   b e   b u r n i n g   i n   h e l l

34 files changed:
TODO.txt [new file with mode: 0644]
external/bits/chain.s
host/Makefile
host/error_decoder.c [moved from host/error-decoder.c with 100% similarity]
host/generate_keys.sh [new file with mode: 0755]
host/key_char.c [new file with mode: 0644]
include/common.h
include/firm/firm.h
include/firm/keys.h [new file with mode: 0644]
include/patch/emunand.h
include/patch/patch_file.h
include/patch_format.h
source/Makefile.am
source/firm/decryptor.c
source/firm/firm.c
source/firm/firmlaunch.c [new file with mode: 0644]
source/firm/keys.c [new file with mode: 0644]
source/firm/keys/Y05.gen [new file with mode: 0644]
source/firm/keys/Y11_95.gen [new file with mode: 0644]
source/firm/keys/Y11_96.gen [new file with mode: 0644]
source/firm/keys/Y3D_0.gen [new file with mode: 0644]
source/firm/keys/Y3D_1.gen [new file with mode: 0644]
source/firm/keys/Y3D_2.gen [new file with mode: 0644]
source/firm/keys/Y3D_3.gen [new file with mode: 0644]
source/firm/keys/Y3D_4.gen [new file with mode: 0644]
source/firm/keys/Y3D_5.gen [new file with mode: 0644]
source/firm/util.c [new file with mode: 0644]
source/interpreter.c
source/patch/emunand.c
source/patch/module.c
source/patch/reboot.c
source/patch/svc.c
source/patcher.c
source/std/memory.c

diff --git a/TODO.txt b/TODO.txt
new file mode 100644 (file)
index 0000000..c21503e
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,5 @@
+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.
index 98f823b1cd352d9a445750106b16603c86e2f4a8..05a79ab940578eb9f4bedcf98554bc14c385305c 100644 (file)
@@ -49,6 +49,9 @@ boot:
         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
index 1f107985ff71d687cdfa78b6ccee5bfab6a4efae..8cdd2e3f979c87bcf655eeba356080276950ca70 100644 (file)
@@ -1,4 +1,8 @@
-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
@@ -8,4 +12,4 @@ font: bdfe_dir
 
 clean:
        make -C bdfe clean
-       rm -f termfont.bin
+       rm -f termfont.bin key_char error_decoder
similarity index 100%
rename from host/error-decoder.c
rename to host/error_decoder.c
diff --git a/host/generate_keys.sh b/host/generate_keys.sh
new file mode 100755 (executable)
index 0000000..1c7ba5d
--- /dev/null
@@ -0,0 +1,40 @@
+#!/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
new file mode 100644 (file)
index 0000000..88e2fda
--- /dev/null
@@ -0,0 +1,102 @@
+#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;
+}
index e9d82f2695f57c939c4c643edda8c9a388aea555..cae7211f5c80d542201b30a23908d4b32bd300be 100644 (file)
@@ -18,6 +18,7 @@
 #include <std/allocator.h>
 #include <firm/decryptor.h>
 #include <firm/firm.h>
+#include <firm/keys.h>
 
 #include <menu.h>
 #include <menu-backend.h>
index 8a1cffcb85d5214449196a7aab59d9129db68eb3..5a40af607d03b8782e053f0b7d6e21180c626921 100644 (file)
@@ -27,44 +27,10 @@ struct firm_signature
     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();
@@ -75,6 +41,6 @@ void boot_cfw();
 
 /* 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
diff --git a/include/firm/keys.h b/include/firm/keys.h
new file mode 100644 (file)
index 0000000..b25bea3
--- /dev/null
@@ -0,0 +1,30 @@
+#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
index 35b3c565fe51dada88267642c2266506869f60ae..1c26bcd9ad61f017ab36d309a19c3a634eb7b0f9 100644 (file)
@@ -3,6 +3,6 @@
 
 #include <stdint.h>
 
-void patch_emunand(uint32_t size);
+void patch_emunand(firm_h* firm_loc, uint32_t size);
 
 #endif
index 152ad877c882de0ebbc95759a7af2acc9ecae1b7..c07e2ef72886311631f0b52a55dfc41a89569223 100644 (file)
@@ -4,6 +4,6 @@
 #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
index 9c3bd4b8be9dd1c1a4e1068a7bf0c378d6e43a13..c16b6007ee7d871ca59588da790e8a22aa04cf6a 100644 (file)
@@ -75,9 +75,8 @@
 #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
 
index 8fac0917f9a131184ae47694153bd95f3689ea8c..f62fb997681deda5de582756b450e80e05fa9d10 100644 (file)
@@ -19,4 +19,4 @@ corbenikdir = $(top_srcdir)/source
 
 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
index cd628f6671c4830c9b081e7dc500fd1817299ad6..aaab3a858f585153fa2155c7678a81d1e488a3ba 100644 (file)
@@ -1,7 +1,3 @@
-/*
-  This is all fairly minimal and based on @d0k3's decrypt9 code.
-*/
-
 #include <common.h>
 #include <ctr9/aes.h>
 #include <ctr9/sha.h>
index 1a7b1fccd77ca5a43387c4ef37fa40aca7d4569f..f98e061587571cb4ec86c46413bd3bc808cd8a21 100644 (file)
 #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);
 }
diff --git a/source/firm/firmlaunch.c b/source/firm/firmlaunch.c
new file mode 100644 (file)
index 0000000..a0acdcf
--- /dev/null
@@ -0,0 +1,29 @@
+#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
+}
+
diff --git a/source/firm/keys.c b/source/firm/keys.c
new file mode 100644 (file)
index 0000000..e7a441f
--- /dev/null
@@ -0,0 +1,190 @@
+#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;
+}
diff --git a/source/firm/keys/Y05.gen b/source/firm/keys/Y05.gen
new file mode 100644 (file)
index 0000000..0967ef4
--- /dev/null
@@ -0,0 +1 @@
+{}
diff --git a/source/firm/keys/Y11_95.gen b/source/firm/keys/Y11_95.gen
new file mode 100644 (file)
index 0000000..174e1e6
--- /dev/null
@@ -0,0 +1 @@
+{},
diff --git a/source/firm/keys/Y11_96.gen b/source/firm/keys/Y11_96.gen
new file mode 100644 (file)
index 0000000..9bba4bb
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..7753ffd
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..b170fd7
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..78e28ff
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..99c8698
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..ae21926
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..3999b71
--- /dev/null
@@ -0,0 +1 @@
+{.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
new file mode 100644 (file)
index 0000000..c94bb0f
--- /dev/null
@@ -0,0 +1,128 @@
+#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;
+}
index ae38927039752e4746c760be1044184580cb92d8..4d1f5dc36a97eae2050384a04b3c379cbd81ecaf 100644 (file)
@@ -78,6 +78,7 @@ int is_n3ds = 1; // TODO - We don't really need to care, but it should still wor
   static uint8_t stack_glob[STACK_SIZE];
 #else
   static uint8_t *stack_glob = NULL;
+  firm_h* firm_patch;
 #endif
 
 int
@@ -85,66 +86,28 @@ exec_bytecode(uint8_t *bytecode, uint32_t len, uint8_t* stack, uint32_t stack_si
 {
     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;
index c5e92ab95a6203b8403ac3bffc9b6ffed0b382eb..06591635aa8986e2bd7f2c5fa1b856d7b028123e 100644 (file)
@@ -114,8 +114,9 @@ patchMPU(uint8_t *pos, uint32_t size)
 }
 
 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;
@@ -166,4 +167,5 @@ patch_emunand(uint32_t index)
     patchMPU(arm9Section, arm9SectionSize);
 
     fprintf(stderr, "emunand: patched MPU settings\n");
+#endif
 }
index 1120168a2dc664c63950105f67d51c406e89285e..82a76f6e69c246e2d0579bf8af45f3595f4883a6 100644 (file)
@@ -41,8 +41,9 @@ inject_module(char* fpath)
 
                 // 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++) {
@@ -86,14 +87,10 @@ end_inj:
 }
 
 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;
 }
index d50237f78bc7d5060cff8e59d2d264e25332e60f..f448056f740fefed3ed3209620d039ad55a699c1 100644 (file)
@@ -15,7 +15,7 @@ getProcess9(uint8_t *pos, uint32_t size, uint32_t *process9Size, uint32_t *proce
 }
 
 void
-patch_reboot()
+patch_reboot(firm_h* firm_loc)
 {
     // Look for firmlaunch code
     const uint8_t pattern[] = { 0xDE, 0x1F, 0x8D, 0xE2 };
index 5d40e7c8fce1f340ab395b18595ef07bd8959878..48f13f54f1171b6ec3499266b3f082ae1c5e3b90 100644 (file)
@@ -7,7 +7,7 @@ int svc_offs_init = 0;
 // 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;
index 50a39f5eca7f162ce679575996d4781bc6536d7e..f5992a6bcdcce23679598cfa03552eeb06320d4a 100644 (file)
@@ -3,9 +3,9 @@
 
 // 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;
 
@@ -51,7 +51,7 @@ generate_patch_cache()
 }
 
 int
-patch_firm_all()
+patch_firm_all(firm_h* firm)
 {
     execb(PATH_LOADER_CACHE "/BOOT", 0);
 
@@ -59,7 +59,7 @@ patch_firm_all()
 
     // Hook firmlaunch?
     if (get_opt_u32(OPTION_REBOOT)) {
-        patch_reboot();
+        patch_reboot(firm);
 
         wait();
     }
@@ -67,14 +67,14 @@ patch_firm_all()
     // 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();
@@ -82,7 +82,7 @@ patch_firm_all()
 
     // 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.
index c5d1ddc10e72e5e5518bfd0a51c871cd59079851..5a039b0c05c12b32e8392bd9e4791280670010d8 100644 (file)
@@ -56,3 +56,4 @@ memfind(uint8_t *startPos, uint32_t size, const void *pattern, uint32_t patternS
 
     return NULL;
 }
+