--- /dev/null
+// This is svcBackdoor's code from earlier FIRMs
+.arm.little
+.create "backdoor.bin", 0
+ bic r1, sp, #0xff
+ orr r1, r1, #0xf00
+ add r1, r1, #0x28
+ ldr r2, [r1]
+ stmdb r2!, {sp, lr}
+ mov sp, r2
+ blx r0
+ pop {r0, r1}
+ mov sp, r0
+ bx r1
+.close
--- /dev/null
+.arm.little
+
+.create "sig1.to", 0
+.thumb
+mov r0, #0
+.close
+
+.create "sig2.to", 0
+.thumb
+mov r0, #0
+bx lr
+.close
FILE* conf_handle;
+struct config_file config;
+
void regenerate_config() {
f_mkdir(PATH_CFW);
f_mkdir(PATH_FIRMWARES);
memcpy(&(config.magic), CONFIG_MAGIC, 4);
config.config_ver = config_version;
+
if(!(conf_handle = fopen(PATH_CONFIG, "w")))
abort("Failed to open config for write?\n");
fprintf(BOTTOM_SCREEN, "Config file loaded.\n");
}
+void save_config() {
+ fprintf(stderr, "Saving config.\n");
+
+ f_unlink(PATH_CONFIG);
+
+ if(!(conf_handle = fopen(PATH_CONFIG, "w")))
+ abort("Failed to open config for write?\n");
+
+ fwrite(&config, 1, sizeof(config), conf_handle);
+ fclose(conf_handle);
+}
uint64_t patch_ids[256]; // What patches are enabled by UUID. 256 is an arbitrary limit - contact me if you hit it.
}__attribute__((packed));
-_UNUSED static struct config_file config;
+extern struct config_file config;
#define OPTION_SIGPATCH 0 // Use builtin signature patch.
#define OPTION_LOADER 1 // Use builtin loader module replacer.
#define ARROW_COLOR 14 // Color of Arrow.
void load_config();
+void save_config();
/*
[CORBENIK]
firm_h *firm_loc = (firm_h *)FCRAM_FIRM_LOC;
static uint32_t firm_size = FCRAM_SPACING;
firm_section_h firm_proc9;
+exefs_h *firm_p9_exefs;
firm_h *twl_firm_loc = (firm_h *)FCRAM_TWL_FIRM_LOC;
static 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 = (firm_h *)FCRAM_AGB_FIRM_LOC;
static uint32_t agb_firm_size = FCRAM_SPACING;
firm_section_h agb_firm_proc9;
+exefs_h *agb_firm_p9_exefs;
static int update_96_keys = 0;
-static int save_firm = 0;
static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8;
return 0;
}
-int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title) {
+int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version) {
uint8_t slot = 0x15;
fprintf(BOTTOM_SCREEN, "Decrypting ARM9 FIRM binary\n");
-// if (firm_title == NATIVE_FIRM_TITLEID && version > 0x0F) {
- if (firm_title == NATIVE_FIRM_TITLEID) {
+ if (firm_title == NATIVE_FIRM_TITLEID && version > 0x0F) {
uint8_t decrypted_keyx[AES_BLOCK_SIZE];
slot0x11key96_init();
fprintf(BOTTOM_SCREEN, "FIRM not encrypted\n");
}
+ struct firm_signature* fsig = get_firm_info(dest);
+
+ fprintf(BOTTOM_SCREEN, "FIRM version: %s\n", fsig->version_string);
+
// The N3DS firm has an additional encryption layer for ARM9
- // Only run if n3ds.
- {
+ if (fsig->console == console_n3ds) {
// Look for the arm9 section
for (firm_section_h *section = dest->section;
section < dest->section + 4; section++) {
if (arm9bin_iscrypt) {
// Decrypt the arm9bin.
- if (decrypt_arm9bin((arm9bin_h *)((uintptr_t)dest + section->offset), firm_title)) {
+ if (decrypt_arm9bin((arm9bin_h *)((uintptr_t)dest + section->offset), firm_title, fsig->version)) {
fprintf(BOTTOM_SCREEN, "Couldn't decrypt ARM9 FIRM binary.\n"
"Check if you have the needed key at:\n"
" " PATH_SLOT0X11KEY96 "\n");
firmware_changed = 1; // Decryption of arm9bin performed.
} else {
fprintf(BOTTOM_SCREEN, "ARM9 FIRM binary not encrypted\n");
-// if (firm_type == NATIVE_FIRM && firm_current->version > 0x0F) {
+ if (firm_title == NATIVE_FIRM_TITLEID && fsig->version > 0x0F) {
slot0x11key96_init(); // This has to be loaded regardless, otherwise boot will fail.
-// }
+ }
}
// We assume there's only one section to decrypt.
write_file(dest, path, *size);
}
- //if (firm_current->console == console_n3ds)
+ if (fsig->console == console_n3ds)
{
fprintf(BOTTOM_SCREEN, "Fixing arm9 entrypoint\n");
fprintf(BOTTOM_SCREEN, "Updated keyX keyslots\n");
}
- struct memory_header *memory = (void *)(memory_loc + 1);
- while ((uintptr_t)memory < (uintptr_t)memory_loc + *memory_loc) {
- memcpy((void *)memory->location, memory + 1, memory->size);
- memory = (void *)((uintptr_t)(memory + 1) + memory->size);
- }
- fprintf(BOTTOM_SCREEN, "Copied memory\n");
-
for (firm_section_h *section = firm_loc->section;
section < firm_loc->section + 4 && section->address != 0; section++) {
memcpy((void *)section->address, (void *)firm_loc + section->offset, section->size);
((void (*)())firm_loc->a9Entry)();
}
-int find_proc9(firm_h* firm, firm_section_h* process9) {
+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 (ncch->magic == NCCH_MAGIC) {
// Found Process9
ncch_ex_h *p9exheader = (ncch_ex_h *)(ncch + 1);
- exefs_h *p9exefs = (exefs_h *)(p9exheader + 1);
+ *p9exefs = (exefs_h *)(p9exheader + 1);
process9->address = p9exheader->sci.textCodeSet.address;
- process9->size = p9exefs->fileHeaders[0].size;
- process9->offset = (void*)(p9exefs + 1) - (void*)firm;
+ process9->size = (*p9exefs)->fileHeaders[0].size;
+ process9->offset = (void*)((*p9exefs) + 1) - (void*)firm;
fprintf(BOTTOM_SCREEN, "Found Process9 for FIRM.\n");
return 0;
}
fprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n");
if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, NATIVE_FIRM_TITLEID) != 0)
return 1;
- find_proc9(firm_loc, &firm_proc9);
+ find_proc9(firm_loc, &firm_proc9, &firm_p9_exefs);
fprintf(BOTTOM_SCREEN, "Loading TWL_FIRM\n");
if(load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, &twl_firm_size, TWL_FIRM_TITLEID))
fprintf(BOTTOM_SCREEN, "TWL_FIRM failed to load.\n");
else
- find_proc9(twl_firm_loc, &twl_firm_proc9);
+ find_proc9(twl_firm_loc, &twl_firm_proc9, &twl_firm_p9_exefs);
fprintf(BOTTOM_SCREEN, "Loading AGB_FIRM\n");
if(load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, &agb_firm_size, AGB_FIRM_TITLEID))
fprintf(BOTTOM_SCREEN, "AGB_FIRM failed to load.\n");
else
- find_proc9(agb_firm_loc, &agb_firm_proc9);
+ find_proc9(agb_firm_loc, &agb_firm_proc9, &agb_firm_p9_exefs);
return 0;
}
if (patch_firm_all() != 0)
return;
- // Only save the firm if that option is required (or it's needed for autoboot),
- // and either the patches have been modified, or the file doesn't exist.
- if ((save_firm || config.options[OPTION_AUTOBOOT]) &&
- f_stat(PATH_NATIVE_P, NULL) != 0) {
- fprintf(BOTTOM_SCREEN, "Saving patched NATIVE_FIRM\n");
- if (write_file(firm_loc, PATH_NATIVE_P, firm_size) != firm_size) {
- fprintf(BOTTOM_SCREEN, "%pFailed to save patched FIRM.\nWriting SD failed.\nThis is fatal.\n", COLOR(RED, BLACK));
- return;
- }
- }
-
- if ((save_firm || config.options[OPTION_AUTOBOOT]) &&
- f_stat(PATH_MEMBIN, NULL) != 0) {
- fprintf(BOTTOM_SCREEN, "Saving patched memory\n");
- if (write_file(memory_loc, PATH_MEMBIN, *memory_loc) != *memory_loc) {
- fprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK));
- return;
- }
- }
-
- if (f_stat(PATH_TWL_P, NULL) != 0) {
- fprintf(BOTTOM_SCREEN, "Saving patched TWL_FIRM\n");
- if (write_file(twl_firm_loc, PATH_TWL_P, twl_firm_size) != twl_firm_size) {
- fprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK));
- return;
- }
- }
-
- if (f_stat(PATH_AGB_P, NULL) != 0) {
- fprintf(BOTTOM_SCREEN, "Saving patched AGB_FIRM\n");
- if (write_file(agb_firm_loc, PATH_AGB_P, agb_firm_size) != agb_firm_size) {
- fprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK));
- return;
- }
- }
-
boot_firm();
}
#include <stdint.h>
#include "headers.h"
+enum consoles {
+ console_o3ds,
+ console_n3ds
+};
+
+struct firm_signature {
+ uint8_t sig[0x10];
+ unsigned int version;
+ char version_string[16];
+ enum consoles console;
+};
+
extern firm_h *firm_loc;
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 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 struct firm_signature *current_agb_firm;
+extern firm_section_h agb_firm_proc9;
+extern exefs_h *agb_firm_p9_exefs;
struct firm_signature *get_firm_info(firm_h *firm);
void slot0x11key96_init();
--- /dev/null
+#include "firm.h"
+#include "../common.h"
+
+// We use the firm's section 0's hash to identify the version
+struct firm_signature firm_signatures[] = {
+ {
+ .sig = {0xEE, 0xE2, 0x81, 0x2E, 0xB9, 0x10, 0x0D, 0x03, 0xFE, 0xA2, 0x3F, 0x44, 0xB5, 0x1C, 0xB3, 0x5E},
+ .version = 0x1F,
+ .version_string = "4.1.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0x8C, 0x29, 0xDA, 0x7B, 0xB5, 0x5F, 0xFE, 0x44, 0x1F, 0x66, 0x79, 0x70, 0x8E, 0xE4, 0x42, 0xE3},
+ .version = 0x2A,
+ .version_string = "6.1.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0x1D, 0x96, 0x80, 0xD9, 0x0A, 0xA9, 0xDB, 0xE8, 0x29, 0x77, 0xCB, 0x7D, 0x90, 0x55, 0xB7, 0xF9},
+ .version = 0x30,
+ .version_string = "7.2.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0x3B, 0x61, 0x2E, 0xBA, 0x42, 0xAE, 0x24, 0x46, 0xAD, 0x60, 0x2F, 0x7B, 0x52, 0x16, 0x82, 0x91},
+ .version = 0x37,
+ .version_string = "8.0.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0x3F, 0xBF, 0x14, 0x06, 0x33, 0x77, 0x82, 0xDE, 0xB2, 0x68, 0x83, 0x01, 0x6B, 0x1A, 0x71, 0x69},
+ .version = 0x38,
+ .version_string = "9.0.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0x5C, 0x6A, 0x51, 0xF3, 0x79, 0x4D, 0x21, 0x91, 0x0B, 0xBB, 0xFD, 0x17, 0x7B, 0x72, 0x6B, 0x59},
+ .version = 0x49,
+ .version_string = "9.6.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0xF5, 0x7E, 0xC3, 0x86, 0x1F, 0x8D, 0x8E, 0xFB, 0x44, 0x61, 0xF3, 0x16, 0x51, 0x0A, 0x57, 0x7D},
+ .version = 0x50,
+ .version_string = "10.4.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0xE9, 0xAD, 0x74, 0x9D, 0x46, 0x9C, 0x9C, 0xF4, 0x96, 0x9E, 0x1A, 0x7A, 0xDF, 0x40, 0x2A, 0x82},
+ .version = 0x52,
+ .version_string = "11.0.0",
+ .console = console_o3ds
+ }, {
+ .sig = {0x31, 0xCC, 0x46, 0xCD, 0x61, 0x7A, 0xE7, 0x13, 0x7F, 0xE5, 0xFC, 0x20, 0x46, 0x91, 0x6A, 0xBB},
+ .version = 0x04,
+ .version_string = "9.0.0",
+ .console = console_n3ds
+ }, {
+ .sig = {0x40, 0x35, 0x6C, 0x9A, 0x24, 0x36, 0x93, 0x7B, 0x76, 0xFE, 0x5D, 0xB1, 0x4D, 0x05, 0x06, 0x52},
+ .version = 0x0F,
+ .version_string = "9.5.0",
+ .console = console_n3ds
+ }, {
+ .sig = {0x07, 0xFE, 0x9A, 0x62, 0x3F, 0xDE, 0x54, 0xC1, 0x9B, 0x06, 0x91, 0xD8, 0x4F, 0x44, 0x9C, 0x21},
+ .version = 0x1B,
+ .version_string = "10.2.0",
+ .console = console_n3ds
+ }, {
+ .sig = {0x1A, 0x56, 0x5C, 0xFF, 0xC9, 0xCC, 0x62, 0xBB, 0x2B, 0xC2, 0x23, 0xB6, 0x4F, 0x48, 0xD1, 0xCC},
+ .version = 0x1F,
+ .version_string = "10.4.0",
+ .console = console_n3ds
+ }, {
+ .sig = {0x52, 0x30, 0x0F, 0x55, 0xA2, 0x64, 0x4E, 0xFF, 0x96, 0x90, 0xF0, 0xE5, 0x6E, 0xC8, 0x2E, 0xB3},
+ .version = 0x21,
+ .version_string = "11.0.0",
+ .console = console_n3ds
+ },
+ {
+ .sig = {0xE8, 0xB8, 0x82, 0xF5, 0x8C, 0xC4, 0x1B, 0x24, 0x05, 0x60, 0x6D, 0xB8, 0x74, 0xF5, 0xE5, 0xDD},
+ .version = 0x16,
+ .version_string = "6.2.0_TWL",
+ .console = console_o3ds
+ }, {
+ .sig = {0x0F, 0x05, 0xC5, 0xF3, 0x60, 0x83, 0x8B, 0x9D, 0xC8, 0x44, 0x3F, 0xB3, 0x06, 0x4D, 0x30, 0xC7},
+ .version = 0x00,
+ .version_string = "9.0.0_TWL",
+ .console = console_n3ds
+ },
+ {
+ .sig = {0x65, 0xB7, 0x55, 0x78, 0x97, 0xE6, 0x5C, 0xD6, 0x11, 0x74, 0x95, 0xDD, 0x61, 0xE8, 0x08, 0x40},
+ .version = 0x0B,
+ .version_string = "6.0.0_AGB",
+ .console = console_o3ds
+ }, {
+ .sig = {0xAF, 0x81, 0xA1, 0xAB, 0xBA, 0xAC, 0xAC, 0xA7, 0x30, 0xE8, 0xD8, 0x74, 0x7C, 0x47, 0x1C, 0x5D},
+ .version = 0x00,
+ .version_string = "9.0.0_AGB",
+ .console = console_n3ds
+ },
+ {.version = 0xFF} // Terminate list
+};
+
+struct firm_signature *get_firm_info(firm_h *firm) {
+ for (struct firm_signature *signature = firm_signatures; signature->version != 0xFF; signature++) {
+ if (memcmp(signature->sig, firm->section[0].hash, 0x10) == 0) {
+ return signature;
+ }
+ }
+
+ return NULL;
+}
#include "common.h"
#include "firm/firm.h"
-void init_system() {}
+void init_system() {
+}
int menu_handler();
in_menu = menu_handler();
}
- init_system();
+ fprintf(BOTTOM_SCREEN, "Booting CFW\n");
+
+ save_config(); // Save config file.
+
+ boot_cfw();
// Under ideal conditions, we never get here.
}
#define MENU_HELP 5
#define MENU_RESET 6
#define MENU_POWER 7
+#define MENU_DUMPBOOT 8
static int cursor_y = 0;
static int which_menu = 1;
static int need_redraw = 1;
+int menu_dumpboot() {
+ // No, we can't dump the whole bootrom.
+ // I'm still curious what's in the readable half.
+
+ FILE *output9;
+ if(!(output9 = fopen("/bootrom9_low.bin", "w")))
+ abort("Failed to open file for write?\n");
+
+ fwrite((uint8_t*)0xffff0000, 1, 0x8000, output9);
+ fclose(output9);
+
+ fprintf(stderr, "Dumped 0x8000 bytes at 0xffff0000\n");
+
+ return MENU_MAIN;
+}
+
uint32_t wait_key() {
uint32_t get = 0;
while(get == 0) {
"Help/Readme",
"Reset",
"Power off",
+ "Dump partial arm9 bootrom",
"Boot firmware"
};
- int menu_max = 6;
+ int menu_max = 8;
header();
case BUTTON_A:
need_redraw = 1;
cursor_y = 0;
+ if (ret == 9)
+ return MENU_BOOTME; // Boot meh, damnit!
return ret;
}
case MENU_HELP:
to_menu = menu_help();
break;
+ case MENU_DUMPBOOT:
+ to_menu = menu_dumpboot();
+ break;
case MENU_BOOTME:
return 0;
case MENU_RESET:
uint8_t patch_data[]; // The data for the patch. This is a sort of interpreted code...see below.
} __attribute__((packed));
+struct patch_opcode {
+} __attribute__((packed));
+
/*
[PATCH]
version=1
#include <stdint.h>
#include "std/unused.h"
#include "std/memory.h"
+#include "firm/firm.h"
#include "config.h"
+#include "common.h"
-#define SIGNATURE_CHECK {0x00, 0x20}
-#define SIGNATURE_CHECK_FIX {0x70, 0x60, 0x70, 0x47}
+uint32_t wait_key();
+
+// A portion of this file is inherited from Luma3DS.
+/*
+u16 *getFirmWrite(u8 *pos, u32 size) {
+ //Look for FIRM writing code
+ u8 *const off = memsearch(pos, "exe:", size, 4);
+ const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
+
+ return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
+}
+
+u16 *getFirmWriteSafe(u8 *pos, u32 size) {
+ //Look for FIRM writing code
+ const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
+
+ return (u16 *)memsearch(pos, pattern, size, 4);
+}
+
+u32 getLoader(u8 *pos, u32 *loaderSize) {
+ u8 *off = pos;
+ u32 size;
+
+ while(1)
+ {
+ size = *(u32 *)(off + 0x104) * 0x200;
+ if(*(u32 *)(off + 0x200) == 0x64616F6C) break;
+ off += size;
+ }
+
+ *loaderSize = size;
+
+ return (u32)(off - pos);
+}
+
+
+// patch_location = (void *)((uintptr_t)firm + section->offset + (version->offset - section->address));
+
+u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
+{
+ u8 *off = memsearch(pos, "ess9", size, 4);
+
+ *process9Size = *(u32 *)(off - 0x60) * 0x200;
+ *process9MemAddr = *(u32 *)(off + 0xC);
+
+ //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
+ return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
+}
+*/
+
+int patch_signatures() {
+ //Look for signature checks
+
+ uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7};
+ uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C};
+
+ uint8_t *firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
+ uint32_t size = firm_p9_exefs->fileHeaders[0].size;
+
+ uint8_t *off = memfind(firm_mem, size, pat1, 4);
+ uint8_t *off2 = memfind(firm_mem, size, pat2, 4) - 1;
+
+ if (off == NULL) {
+ fprintf(stderr, "Signature patch failed on P0.\n");
+ return 1; // Failed to find sigpatch. Ugh.
+ }
+
+ if (off2 == NULL) {
+ fprintf(stderr, "Signature patch failed on P1.\n");
+ return 2; // Failed to find sigpatch. Ugh.
+ }
+
+ fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off);
+ fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2);
+
+ uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47};
+
+ memcpy(off, sigpatch, 2);
+ memcpy(off2, sigpatch, 4);
+ fprintf(stderr, "Signature patch succeded.\n");
+
+ return 0;
+}
int patch_firm_all() {
// Use builtin signature patcher?
+
+ fprintf(stderr, "Signature patch: %s\n", ((config.options[OPTION_SIGPATCH]) ? "yes" : "no" ));
if (config.options[OPTION_SIGPATCH]) {
- // Yes.
- // memfind(
+ if(patch_signatures()) {
+ abort("Fatal. Sigpatch has failed.");
+ }
}
// Replace loader?
// Use ARM9 hook thread?
if (config.options[OPTION_ARM9THREAD]) {
// Yes.
+
// FIXME - NYI
}
+ wait_key();
+
return 0;
}
puts(channel, out);
}
+void put_hexdump(void* channel, unsigned int num) {
+ uint8_t* num_8 = (uint8_t*)#
+ for(int i=3; i>=0; i--) {
+ uint8_t high = (num_8[i] >> 4) & 0xf;
+ uint8_t low = num_8[i] & 0xf;
+
+ putc(channel, ("0123456789abcdef")[high]);
+ putc(channel, ("0123456789abcdef")[low]);
+ }
+}
+
void put_uint(void* channel, unsigned int n, int length) {
put_uint64(channel, n, length);
}
case 'l':
++type_size;
goto check_format;
+ case 'x':
+ put_hexdump(channel, va_arg( ap, unsigned int ));
+ break;
default:
if (*ref >= '0' && *ref <= '9') {
length = *ref - '0';