]> Chaos Git - corbenik/corbenik.git/commitdiff
Update FIRM handling code to cache shit
authorchaoskagami <chaos.kagami@gmail.com>
Tue, 27 Sep 2016 04:45:01 +0000 (00:45 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Tue, 27 Sep 2016 04:45:01 +0000 (00:45 -0400)
host/copy-min.sh [changed mode: 0644->0755]
source/firm/firm.c
source/firm/keys.c
source/firm/util.c
source/main.c

old mode 100644 (file)
new mode 100755 (executable)
index 86590ad..87f9959
@@ -3,13 +3,10 @@
 # This is just a helper script I use to copy shit to my own unit.
 # You don't and shouldn't need to use it.
 
-mnt=/media/sd
-dev=/dev/sdc
-
-mnt=/mnt/ext1
+mnt=/media
+dev=/dev/mmcblk0p
 
 mount -t vfat ${dev}1 $mnt || exit 0
 cp out/arm9loaderhax.bin $mnt/arm9loaderhax_si.bin || exit 0
 umount $mnt || exit 0
 sync || exit 0
-eject ${dev} || exit 0
index 9d15e6240ce6993b5ed515d39e982624f3e12677..5dd1e7cc2fcda839c852ad319ad3a35694cab066 100644 (file)
 firm_h*
 load_firm(const char *path, size_t *size_out)
 {
+    uint8_t* mem;
+    struct firm_signature* sig;
     int success = 0;
+    FILE* firm_file;
+    size_t size;
+    int save_dec = 0;
 
-    FILE *firm_file = fopen(path, "r");
+    char* decpath = strdupcat(path, ".dec");
+    firm_file = fopen(decpath, "r");
     if (!firm_file) {
-        return NULL;
+        firm_file = fopen(path, "r");
+        if (!firm_file) {
+            return NULL;
+        }
     }
 
-    size_t size = fsize(firm_file);
+    size = fsize(firm_file);
 
     if (size_out)
         *size_out = size;
 
-    uint8_t* mem = malloc(size);
+    mem = malloc(size);
 
     firm_h *firm = (firm_h*)mem;
 
@@ -32,57 +41,84 @@ load_firm(const char *path, size_t *size_out)
 
     fclose(firm_file);
 
-    if (!memcmp(firm->magic, "DECFIRM", 7)) {
-        // Fully decrypted FIRM, courtesy D9. Fix the entrypoint and we're good.
-        firm = (firm_h*)mem;
+    if (memcmp(firm->magic, "FIRM", 4)) {
+        char *key_path = strdupcat(path, ".key");
 
-        struct firm_signature* sig = get_firm_info(firm);
+        // Attempt to open keyfile.
+        uint8_t* firmkey = malloc(16);
+        if (read_file(firmkey, key_path, 16) != 16) {
+            // Keyfile couldn't be opened, try the cetk.
+            free(firmkey);
 
-        patch_entry(firm, sig->type);
-        if (patch_section_keys(firm, sig->k9l)) {
-            free(mem);
-            return NULL;
+            // Encrypted. Open CETK.
+            char *cetk_path = strdupcat(path, ".cetk");
+            firmkey = get_titlekey(cetk_path);
+            free(cetk_path);
+
+            // Save firmkey.
+            FILE* keyfile = fopen(key_path, "w");
+            fwrite(firmkey, 1, 16, keyfile);
+            fclose(keyfile);
         }
 
-        free(sig);
-    } else if (!memcmp(firm->magic, "FIRM", 4)) {
-        // O3DS fully decrypted FIRM
+        free(key_path);
 
-        firm = (firm_h*)mem;
-    } else {
-        // Encrypted.
-        char *cetk_path = strdupcat(path, ".cetk");
+        if (firmkey) {
+            firm = extract_firm_from_ncch((ncch_h*)mem, firmkey, size);
 
-        uint8_t* firmkey = get_titlekey(cetk_path);
+            free(firmkey);
 
-        free(cetk_path);
+            if (!firm) {
+                free(mem);
+                return NULL;
+            }
+        } else {
+            free(mem);
+            return NULL;
+        }
 
-        if (firmkey) {
-            firm = extract_firm_from_ncch((ncch_h*)mem, firmkey, size);
+        save_dec = 1;
+    }
 
-            if (firm) {
-                struct firm_signature* sig = get_firm_info(firm);
+    sig = get_firm_info(firm);
 
-                if (sig->console == console_n3ds) {
-                    if(dec_k9l(firm)) {
-                        free(firm);
-                        free(mem);
-                        return NULL;
-                    }
+    if (memcmp(firm->magic, "FIRM", 4)) {
+        // Error. Abort.
+        free(mem);
+        return NULL;
+    }
 
-                    patch_entry(firm, sig->type);
+    // If this is a FIRM and not a k9l decrypted FIRM...
+    if (!memcmp(firm->magic, "FIRM", 4) && memcmp(firm->magic + 4, "DEC", 3)) {
+        if (sig->console == console_n3ds) {
+            if (dec_k9l(firm)) {
+                free(firm);
+                free(mem);
+                return NULL;
+            }
+        }
+    }
 
-                    if (sig->type == type_native && patch_section_keys(firm, sig->k9l)) {
-                        free(firm);
-                        free(mem);
-                        return NULL;
-                    }
-                }
+    // Save decrypted FIRM.
+    if (save_dec == 1) {
+        firm_file = fopen(decpath, "w");
+        fwrite(firm, 1, size, firm_file);
+        fclose(firm_file);
+    }
+
+    free(decpath);
+
+    // Arm9 decrypted firmware (n3ds)?
+    if (!memcmp(firm->magic, "FIRMDEC", 7)) {
+        if (sig->console == console_n3ds) {
+            patch_entry(firm, sig->type);
 
-                free(sig);
+            if (sig->type == type_native && patch_section_keys(firm, sig->k9l)) {
+                free(firm);
+                free(mem);
+                return NULL;
             }
         }
-        free(mem);
     }
 
     return firm;
@@ -91,7 +127,7 @@ load_firm(const char *path, size_t *size_out)
 int
 prepatch_firm(const char* firm_path, const char* prepatch_path, const char* module_path)
 {
-       size_t size = 0;
+    size_t size = 0;
     firm_h* firm = load_firm(firm_path, &size);
 
     if (firm == NULL)
@@ -109,23 +145,23 @@ prepatch_firm(const char* firm_path, const char* prepatch_path, const char* modu
     free(sig);
 
     if (patch_firm_all(tid, firm, module_path)) {
-               free(firm);
+        free(firm);
         return 1;
-       }
+    }
 
-       FILE* f = fopen(prepatch_path, "w");
-       fwrite(firm, 1, size, f);
-       fclose(f);
+    FILE* f = fopen(prepatch_path, "w");
+    fwrite(firm, 1, size, f);
+    fclose(f);
 
-       free(firm);
+    free(firm);
 
-       return 0;
+    return 0;
 }
 
 int
 boot_firm(const char* firm_path, const char* prepatch_path, const char* module_path)
 {
-       size_t size = 0;
+    size_t size = 0;
     firm_h* firm = load_firm(firm_path, &size);
 
     if (firm == NULL)
@@ -143,13 +179,13 @@ boot_firm(const char* firm_path, const char* prepatch_path, const char* module_p
     free(sig);
 
     if (patch_firm_all(tid, firm, module_path)) {
-               free(firm);
+        free(firm);
         return 1;
-       }
+    }
 
-       FILE* f = fopen(prepatch_path, "w");
-       fwrite(firm, 1, size, f);
-       fclose(f);
+    FILE* f = fopen(prepatch_path, "w");
+    fwrite(firm, 1, size, f);
+    fclose(f);
 
     firmlaunch(firm); // <- should NOT return if all is well
 
index 7894c64e81219a4f9c014ab2b0861e5d0862af93..44211b686ac954c3e3fc8bb2afd78431154329dc 100644 (file)
@@ -7,7 +7,7 @@
 #include <firm/internal.h>
 
 int set_N11_K9L(uint32_t index) {
-       static uint8_t ss_keyn[2][16] = {
+    static uint8_t ss_keyn[2][16] = {
         { 0 }, // 9.5
         { 0 }, // 9.6+
     };
@@ -32,25 +32,25 @@ int set_N11_K9L(uint32_t index) {
 
     setup_aeskey(0x11, (void*) ss_keyn[index]);
 
-       use_aeskey(0x11);
+    use_aeskey(0x11);
 
-       return 0;
+    return 0;
 }
 
 int set_Y3D_cetk(uint32_t index) {
-       // From https://github.com/profi200/Project_CTR/blob/master/makerom/pki/prod.h#L19
-       static uint8_t common_keyy[6][16] = {
-               {0xD0, 0x7B, 0x33, 0x7F, 0x9C, 0xA4, 0x38, 0x59, 0x32, 0xA2, 0xE2, 0x57, 0x23, 0x23, 0x2E, 0xB9} , // 0 - eShop Titles
-               {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C} , // 1 - System Titles
-               {0xC4, 0x75, 0xCB, 0x3A, 0xB8, 0xC7, 0x88, 0xBB, 0x57, 0x5E, 0x12, 0xA1, 0x09, 0x07, 0xB8, 0xA4} , // 2
-               {0xE4, 0x86, 0xEE, 0xE3, 0xD0, 0xC0, 0x9C, 0x90, 0x2F, 0x66, 0x86, 0xD4, 0xC0, 0x6F, 0x64, 0x9F} , // 3
-               {0xED, 0x31, 0xBA, 0x9C, 0x04, 0xB0, 0x67, 0x50, 0x6C, 0x44, 0x97, 0xA3, 0x5B, 0x78, 0x04, 0xFC} , // 4
-               {0x5E, 0x66, 0x99, 0x8A, 0xB4, 0xE8, 0x93, 0x16, 0x06, 0x85, 0x0F, 0xD7, 0xA1, 0x6D, 0xD7, 0x55} , // 5
-       };
+    // From https://github.com/profi200/Project_CTR/blob/master/makerom/pki/prod.h#L19
+    static uint8_t common_keyy[6][16] = {
+        {0xD0, 0x7B, 0x33, 0x7F, 0x9C, 0xA4, 0x38, 0x59, 0x32, 0xA2, 0xE2, 0x57, 0x23, 0x23, 0x2E, 0xB9} , // 0 - eShop Titles
+        {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C} , // 1 - System Titles
+        {0xC4, 0x75, 0xCB, 0x3A, 0xB8, 0xC7, 0x88, 0xBB, 0x57, 0x5E, 0x12, 0xA1, 0x09, 0x07, 0xB8, 0xA4} , // 2
+        {0xE4, 0x86, 0xEE, 0xE3, 0xD0, 0xC0, 0x9C, 0x90, 0x2F, 0x66, 0x86, 0xD4, 0xC0, 0x6F, 0x64, 0x9F} , // 3
+        {0xED, 0x31, 0xBA, 0x9C, 0x04, 0xB0, 0x67, 0x50, 0x6C, 0x44, 0x97, 0xA3, 0x5B, 0x78, 0x04, 0xFC} , // 4
+        {0x5E, 0x66, 0x99, 0x8A, 0xB4, 0xE8, 0x93, 0x16, 0x06, 0x85, 0x0F, 0xD7, 0xA1, 0x6D, 0xD7, 0x55} , // 5
+    };
 
-       setup_aeskeyY(0x3D, (void*) common_keyy[index]);
+    setup_aeskeyY(0x3D, (void*) common_keyy[index]);
 
-       use_aeskey(0x3D);
+    use_aeskey(0x3D);
 
-       return 0;
+    return 0;
 }
index f16a90c5dcfb2723808d94cacf53912dce0b7c8c..0b9d1d42d775990a997a9267a2a676922653d89b 100644 (file)
@@ -61,28 +61,28 @@ get_titlekey(char *cetk_filename)
 
     fclose(f);
 
-       uint8_t iv[AES_BLOCK_SIZE] = { 0 };
-       uint32_t sigtype = __builtin_bswap32(*(const uint32_t *)cetk);
+    uint8_t iv[AES_BLOCK_SIZE] = { 0 };
+    uint32_t sigtype = __builtin_bswap32(*(const uint32_t *)cetk);
 
-       if (sigtype != SIG_TYPE_RSA2048_SHA256) {
+    if (sigtype != SIG_TYPE_RSA2048_SHA256) {
         free(cetk);
-               return NULL;
+        return NULL;
     }
 
-       const ticket_h *ticket = (const ticket_h *)((const uint8_t*)cetk + sizeof(sigtype) + 0x13C);
+    const ticket_h *ticket = (const ticket_h *)((const uint8_t*)cetk + sizeof(sigtype) + 0x13C);
 
     set_Y3D_cetk(1);
 
     uint8_t *key = malloc(AES_BLOCK_SIZE);
 
-       memcpy(iv, ticket->titleID, sizeof(ticket->titleID));
-       memcpy(key, ticket->titleKey, sizeof(ticket->titleKey));
+    memcpy(iv, ticket->titleID, sizeof(ticket->titleID));
+    memcpy(key, ticket->titleKey, sizeof(ticket->titleKey));
 
-       cbc_decrypt(key, key, 1, AES_CNT_TITLEKEY_DECRYPT_MODE, iv);
+    cbc_decrypt(key, key, 1, AES_CNT_TITLEKEY_DECRYPT_MODE, iv);
 
     free(cetk);
 
-       return key;
+    return key;
 }
 
 int dec_k9l(firm_h* firm) {
@@ -106,7 +106,7 @@ int dec_k9l(firm_h* firm) {
     sha256sum(arm9->hash, (uint8_t*)firm + arm9->offset, arm9->size);
 
     // Magic like D9.
-    memcpy(firm->magic, "DECFIRM", 7);
+    memcpy(firm->magic, "FIRMDEC", 7);
 
     free(sig);
 
@@ -116,75 +116,75 @@ int dec_k9l(firm_h* firm) {
 firm_h*
 extract_firm_from_ncch(ncch_h *ncch, uint8_t *titlekey, size_t size)
 {
-       uint8_t firm_iv[16] = { 0 };
-       uint8_t exefs_key[16] = { 0 };
-       uint8_t exefs_iv[16] = { 0 };
+    uint8_t firm_iv[16] = { 0 };
+    uint8_t exefs_key[16] = { 0 };
+    uint8_t exefs_iv[16] = { 0 };
 
-       setup_aeskey(0x16, titlekey);
-       use_aeskey(0x16);
-       cbc_decrypt(ncch, ncch, size / AES_BLOCK_SIZE, AES_CNT_CBC_DECRYPT_MODE, firm_iv);
+    setup_aeskey(0x16, titlekey);
+    use_aeskey(0x16);
+    cbc_decrypt(ncch, ncch, size / AES_BLOCK_SIZE, AES_CNT_CBC_DECRYPT_MODE, firm_iv);
 
-       if (ncch->magic != NCCH_MAGIC) {
-               return NULL;
+    if (ncch->magic != NCCH_MAGIC) {
+        return NULL;
     }
 
-       memcpy(exefs_key, ncch, AES_BLOCK_SIZE);
-       ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS);
+    memcpy(exefs_key, ncch, AES_BLOCK_SIZE);
+    ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS);
 
-       // Get the exefs offset and size from the NCCH
-       exefs_h *exefs = (exefs_h *)((uint8_t *)ncch + ncch->exeFSOffset * MEDIA_UNITS);
-       uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS;
+    // Get the exefs offset and size from the NCCH
+    exefs_h *exefs = (exefs_h *)((uint8_t *)ncch + ncch->exeFSOffset * MEDIA_UNITS);
+    uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS;
 
-       setup_aeskeyY(0x2C, exefs_key);
-       use_aeskey(0x2C);
-       ctr_decrypt(exefs, exefs, exefs_size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, exefs_iv);
+    setup_aeskeyY(0x2C, exefs_key);
+    use_aeskey(0x2C);
+    ctr_decrypt(exefs, exefs, exefs_size / AES_BLOCK_SIZE, AES_CNT_CTRNAND_MODE, exefs_iv);
 
-       // Get the decrypted FIRM
-       // We assume the firm.bin is always the first file
-       firm_h *firm = (firm_h *)&exefs[1]; // The offset right behind the exefs
+    // Get the decrypted FIRM
+    // We assume the firm.bin is always the first file
+    firm_h *firm = (firm_h *)&exefs[1]; // The offset right behind the exefs
 
-       // header; the first file.
-       size = exefs->fileHeaders[0].size;
-       if (memcmp(firm->magic, "FIRM", 4)) {
-               return NULL;
+    // header; the first file.
+    size = exefs->fileHeaders[0].size;
+    if (memcmp(firm->magic, "FIRM", 4)) {
+        return NULL;
     }
 
     firm_h* dest = malloc(size);
 
-       memcpy(dest, firm, size);
+    memcpy(dest, firm, size);
 
-       return dest;
+    return dest;
 }
 
 uint8_t* key_search(uint8_t* mem, uint32_t size, uint8_t* sha256, uint8_t byte) {
-       uint8_t hash[0x20] = {0};
-       // Search for key.
-       for(uint32_t j = 0; j < size; j++) {
-               // Is candidate?
-               if (mem[j] == byte) {
-                       // Yes. Check hash.
-                       sha256sum(hash, &mem[j], 0x10);
-                       if(!memcmp(sha256, hash, 0x20)) {
-                               return &mem[j];
-                       }
-               }
-       }
-       return NULL;
+    uint8_t hash[0x20] = {0};
+    // Search for key.
+    for(uint32_t j = 0; j < size; j++) {
+        // Is candidate?
+        if (mem[j] == byte) {
+            // Yes. Check hash.
+            sha256sum(hash, &mem[j], 0x10);
+            if(!memcmp(sha256, hash, 0x20)) {
+                return &mem[j];
+            }
+        }
+    }
+    return NULL;
 }
 
 void* find_section_key(firm_h* firm_loc) {
-       uint8_t sha256[] = {0xb9, 0x4d, 0xb1, 0xb1, 0xc3, 0xe0, 0x11, 0x08, 0x9c, 0x19, 0x46, 0x06, 0x4a, 0xbc, 0x40, 0x2a,
-                           0x7c, 0x66, 0xf4, 0x4a, 0x74, 0x6f, 0x71, 0x50, 0x32, 0xfd, 0xff, 0x03, 0x74, 0xd7, 0x45, 0x2c};
+    uint8_t sha256[] = {0xb9, 0x4d, 0xb1, 0xb1, 0xc3, 0xe0, 0x11, 0x08, 0x9c, 0x19, 0x46, 0x06, 0x4a, 0xbc, 0x40, 0x2a,
+                        0x7c, 0x66, 0xf4, 0x4a, 0x74, 0x6f, 0x71, 0x50, 0x32, 0xfd, 0xff, 0x03, 0x74, 0xd7, 0x45, 0x2c};
 
-       uint8_t* key_loc = (uint8_t*)firm_loc + firm_loc->section[2].offset;
-       uint32_t search_size = firm_loc->section[2].size;
+    uint8_t* key_loc = (uint8_t*)firm_loc + firm_loc->section[2].offset;
+    uint32_t search_size = firm_loc->section[2].size;
 
-       uint8_t* key_data = key_search(key_loc, search_size, sha256, 0xDD);
+    uint8_t* key_data = key_search(key_loc, search_size, sha256, 0xDD);
 
-       if (!key_data)
-               return NULL;
+    if (!key_data)
+        return NULL;
 
-       return key_data;
+    return key_data;
 }
 
 int patch_section_keys(firm_h* firm_loc, uint32_t k9l) {
@@ -211,21 +211,21 @@ int patch_section_keys(firm_h* firm_loc, uint32_t k9l) {
 exefs_h*
 find_proc9(firm_h *firm)
 {
-       for (firm_section_h *section = firm->section; section < firm->section + 4; section++) {
-               if (section->address == 0)
-                       break;
-               if (section->type == FIRM_TYPE_ARM9) {
-                       uint8_t* arm9section = memfind((uint8_t *)firm + section->offset, section->size, "Process9", 8);
-                       if (!arm9section)
-                               return NULL;
-
-                       ncch_h *ncch = (ncch_h *)((uint8_t*)arm9section - sizeof(ncch_h));
-                       if (ncch->magic == NCCH_MAGIC) {
-                               // Found Process9
-                               ncch_ex_h *p9exheader = (ncch_ex_h *)(ncch + 1);
-                               return (exefs_h *)(p9exheader + 1);
-                       }
-               }
-       }
-       return NULL;
+    for (firm_section_h *section = firm->section; section < firm->section + 4; section++) {
+        if (section->address == 0)
+            break;
+        if (section->type == FIRM_TYPE_ARM9) {
+            uint8_t* arm9section = memfind((uint8_t *)firm + section->offset, section->size, "Process9", 8);
+            if (!arm9section)
+                return NULL;
+
+            ncch_h *ncch = (ncch_h *)((uint8_t*)arm9section - sizeof(ncch_h));
+            if (ncch->magic == NCCH_MAGIC) {
+                // Found Process9
+                ncch_ex_h *p9exheader = (ncch_ex_h *)(ncch + 1);
+                return (exefs_h *)(p9exheader + 1);
+            }
+        }
+    }
+    return NULL;
 }
index cb3135ac87e8ec093bd01a964ecc211cb137802d..5d63a52736f6a8066972bc2fe340cb1cdf15ac02 100644 (file)
@@ -1,3 +1,4 @@
+
 #include <ctr9/ctr_hid.h>
 #include <ctr9/io.h>
 #include <ctr9/ctr_screen.h>
@@ -48,32 +49,34 @@ main(int argc, char** argv)
     clear_disp(TOP_SCREEN);
     clear_disp(BOTTOM_SCREEN);
 
-    if (get_opt_u32(OPTION_AUTOBOOT) && !r_held) {
-        doing_autoboot = 1;
+    while (1) {
+        if (get_opt_u32(OPTION_AUTOBOOT) && !r_held && !doing_autoboot) {
+            doing_autoboot = 1;
 
-        if (get_opt_u32(OPTION_SILENCE))
-            shut_up(); // This does exactly what it sounds like.
-    } else {
-        menu_handler();
-    }
+            if (get_opt_u32(OPTION_SILENCE))
+                shut_up(); // This does exactly what it sounds like.
+        } else {
+            menu_handler();
+        }
 
-    if (changed_consoles) {
-        fprintf(stderr, "Console changed, regenerating caches\n");
-        save_config();
-        generate_patch_cache();
-    }
+        if (changed_consoles) {
+            fprintf(stderr, "Console changed, regenerating caches\n");
+            save_config();
+            generate_patch_cache();
+        }
 
-    if (prepatch_firm(config->firm[1], PATH_TWL_P, PATH_MODULE_TWL)) {
-        fprintf(stderr, "WARNING: Failed to load/patch TWL.\n");
-        wait();
-    }
+        if (prepatch_firm(config->firm[1], PATH_TWL_P, PATH_MODULE_TWL)) {
+            fprintf(stderr, "WARNING: Failed to load/patch TWL.\n");
+            wait();
+        }
 
-    if(prepatch_firm(config->firm[2], PATH_AGB_P, PATH_MODULE_AGB)) {
-        fprintf(stderr, "WARNING: Failed to load/patch AGB.\n");
-        wait();
-    }
+        if(prepatch_firm(config->firm[2], PATH_AGB_P, PATH_MODULE_AGB)) {
+            fprintf(stderr, "WARNING: Failed to load/patch AGB.\n");
+            wait();
+        }
 
-    boot_firm(config->firm[0], PATH_NATIVE_P, PATH_MODULE_NATIVE);
+        boot_firm(config->firm[0], PATH_NATIVE_P, PATH_MODULE_NATIVE);
 
-    panic("Firmlaunch failed!\n");
+        fprintf(stderr, "Firmlaunch failed, returning to menu\n");
+    }
 }