return secureInfoExists;
}
-struct config_file config;
-int failed_load_config = 1;
+static struct config_file config;
+static int failed_load_config = 1;
-void clear_config() {
- // Basically; memset.
- for(int i=0;i<sizeof(struct config_file);i++)
- ((char*)&config)[i]=0;
-}
-
-void load_config() {
- IFile file;
- u64 total;
+static void load_config() {
+ static IFile file;
+ static u64 total;
// Open file.
- if (!fileOpen(&file, ARCHIVE_SDMC, PATH_CONFIG, FS_OPEN_READ)) {
+ if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, PATH_CONFIG, FS_OPEN_READ))) {
// Failed to open.
- failed_load_config = 1;
- goto ret_fail;
+ return;
}
// Read file.
- if(!IFile_Read(&file, &total, &config, sizeof(struct config_file))) {
+ if (!R_SUCCEEDED(IFile_Read(&file, &total, &config, sizeof(struct config_file)))) {
+ IFile_Close(&file); // Read to memory.
+
// Failed to read.
- goto ret_fail;
+ return;
}
IFile_Close(&file); // Read to memory.
if (config.magic[0] != 'O' || config.magic[1] != 'V' || config.magic[2] != 'A' || config.magic[3] != 'N') {
// Incorrect magic.
// Failed to read.
- goto ret_fail;
+ return;
}
if (config.config_ver != config_version) {
// Invalid version.
- goto ret_fail;
+ return;
}
failed_load_config = 0;
- return;
-
-ret_fail:
- clear_config();
-
return;
}
}
}
-void region_patch(u64 progId, u8 *code, u32 size) {
+static void region_patch(u64 progId, u8 *code, u32 size) {
static const u8 regionFreePattern[] = {0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3};
static const u8 regionFreePatch[] = {0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1};
);
}
-void disable_nim_updates(u64 progId, u8 *code, u32 size) {
+static void disable_nim_updates(u64 progId, u8 *code, u32 size) {
static const u8 blockAutoUpdatesPattern[] = {0x25, 0x79, 0x0B, 0x99};
static const u8 blockAutoUpdatesPatch[] = {0xE3, 0xA0};
);
}
-void disable_eshop_updates(u64 progId, u8 *code, u32 size) {
+static void disable_eshop_updates(u64 progId, u8 *code, u32 size) {
static const u8 skipEshopUpdateCheckPattern[] = {0x30, 0xB5, 0xF1, 0xB0};
static const u8 skipEshopUpdateCheckPatch[] = {0x00, 0x20, 0x08, 0x60, 0x70, 0x47};
);
}
-void fake_friends_version(u64 progId, u8 *code, u32 size) {
+static void fake_friends_version(u64 progId, u8 *code, u32 size) {
static const u8 fpdVerPattern[] = {0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01};
static const u8 fpdVerPatch = 0x06; // Latest version.
);
}
-void settings_string(u64 progId, u8 *code, u32 size) {
+static void settings_string(u64 progId, u8 *code, u32 size) {
static const u16 verPattern[] = u"Ver.";
static const u16 verPatch[] = u".hax";
);
}
-void disable_cart_updates(u64 progId, u8 *code, u32 size) {
+static void disable_cart_updates(u64 progId, u8 *code, u32 size) {
static const u8 stopCartUpdatesPattern[] = {0x0C, 0x18, 0xE1, 0xD8};
static const u8 stopCartUpdatesPatch[] = {0x0B, 0x18, 0x21, 0xC8};
);
}
-void adjust_cpu_settings(u64 progId, u8 *code, u32 size) {
+static void adjust_cpu_settings(u64 progId, u8 *code, u32 size) {
if (!failed_load_config) {
u32 cpuSetting = 0;
// L2
}
}
-void secureinfo_sigpatch(u64 progId, u8 *code, u32 size) {
+static void secureinfo_sigpatch(u64 progId, u8 *code, u32 size) {
static const u8 secureinfoSigCheckPattern[] = {0x06, 0x46, 0x10, 0x48, 0xFC};
static const u8 secureinfoSigCheckPatch[] = {0x00, 0x26};
);
}
-void patchCode(u64 progId, u8 *code, u32 size)
-{
- // FIXME - Config loading breaks loader. WTF is this?
- // Maybe the memcpy?
- // load_config();
+static void ro_sigpatch(u64 progId, u8 *code, u32 size) {
+ static const u8 sigCheckPattern[] = {0x30, 0x40, 0x2D, 0xE9, 0x02, 0x50, 0xA0, 0xE1};
+ static const u8 sha256ChecksPattern1[] = {0x30, 0x40, 0x2D, 0xE9, 0x24, 0xD0, 0x4D, 0xE2};
+ static const u8 sha256ChecksPattern2[] = {0xF8, 0x4F, 0x2D, 0xE9, 0x01, 0x70, 0xA0, 0xE1};
+
+ // mov r0, #0; bx lr - equivalent to 'return 0;'
+ static const u8 stub[] = {0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1};
+
+ //Disable CRR0 signature (RSA2048 with SHA256) check
+ patchMemory(code, size,
+ sigCheckPattern,
+ sizeof(sigCheckPattern), 0,
+ stub,
+ sizeof(stub), 1
+ );
+
+ //Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
+ patchMemory(code, size,
+ sha256ChecksPattern1,
+ sizeof(sha256ChecksPattern1), 0,
+ stub,
+ sizeof(stub), 1
+ );
+
+ patchMemory(code, size,
+ sha256ChecksPattern2,
+ sizeof(sha256ChecksPattern2), 0,
+ stub,
+ sizeof(stub), 1
+ );
+}
+
+void language_emu(u64 progId, u8 *code, u32 size) {
+ if(!failed_load_config && config.options[OPTION_LOADER_LANGEMU]) {
+ u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
+
+ if(tidHigh == 0x0004000) { // Normal Game
+ //Language emulation
+ u8 regionId = 0xFF,
+ languageId = 0xFF;
+
+ if(R_SUCCEEDED(loadTitleLocaleConfig(progId, ®ionId, &languageId))) {
+ u32 CFGUHandleOffset;
+
+ u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
+
+ if(CFGU_GetConfigInfoBlk2_endPos != NULL) {
+ if(languageId != 0xFF)
+ patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
+ if(regionId != 0xFF)
+ patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
+ }
+ }
+ }
+ }
+}
+
+void patchCode(u64 progId, u8 *code, u32 size) {
+ load_config();
switch(progId)
{
case 0x0004013000008002LL: // NS
{
disable_cart_updates(progId, code, size);
- adjust_cpu_settings(progId, code, size);
+ adjust_cpu_settings(progId, code, size); // DEFAULT cpu settings that are inherited system-wide. Per-app is handled in default.
break;
}
secureinfo_sigpatch(progId, code, size);
break;
}
-/* default:
+ case 0x0004013000003702LL: // RO
{
- if(!failed_load_config && config.options[OPTION_LOADER_LANGEMU])
- {
- u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
-
- if(tidHigh == 0x0004000)
- {
- //Language emulation
- u8 regionId = 0xFF,
- languageId = 0xFF;
-
- if(R_SUCCEEDED(loadTitleLocaleConfig(progId, ®ionId, &languageId)))
- {
- u32 CFGUHandleOffset;
-
- u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
-
- if(CFGU_GetConfigInfoBlk2_endPos != NULL)
- {
- if(languageId != 0xFF)
- patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
- if(regionId != 0xFF)
- patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
- }
- }
- }
- }
+ ro_sigpatch(progId, code, size);
+ break;
+ }
+ default:
+ {
+ language_emu(progId, code, size);
break;
- } */
+ }
}
}
uint8_t exefs_key[16] = {0};
uint8_t exefs_iv[16] = {0};
- fprintf(BOTTOM_SCREEN, "Decrypting the NCCH\n");
+ fprintf(BOTTOM_SCREEN, " Decrypting the NCCH\n");
aes_setkey(0x16, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x16);
aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
exefs_h *exefs = (exefs_h *)((void *)ncch + ncch->exeFSOffset * MEDIA_UNITS);
uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS;
- fprintf(BOTTOM_SCREEN, "Decrypting the exefs\n");
+ fprintf(BOTTOM_SCREEN, " Decrypting the exefs\n");
aes_setkey(0x2C, exefs_key, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C);
aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
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");
+ fprintf(BOTTOM_SCREEN, " Decrypting ARM9 FIRM binary\n");
if (firm_title == NATIVE_FIRM_TITLEID && version > 0x0F) {
uint8_t decrypted_keyx[AES_BLOCK_SIZE];
// Firmware is likely encrypted. Decrypt.
if (!read_file(firm_key, path_firmkey, AES_BLOCK_SIZE)) {
- fprintf(BOTTOM_SCREEN, "Failed to load FIRM key\n");
+ fprintf(BOTTOM_SCREEN, " Failed to load FIRM key\n");
return 1;
} else {
- fprintf(BOTTOM_SCREEN, "Loaded FIRM key\n");
+ fprintf(BOTTOM_SCREEN, " Loaded FIRM key\n");
}
- fprintf(BOTTOM_SCREEN, "Decrypting FIRM\n");
+ fprintf(BOTTOM_SCREEN, " Decrypting FIRM\n");
if (decrypt_firm_title(dest, (void *)dest, size, firm_key) != 0) {
fprintf(BOTTOM_SCREEN, "Failed to decrypt the firmware\n");
return 1;
}
int load_firms() {
- fprintf(TOP_SCREEN, "[Loading FIRM]\n");
+ fprintf(BOTTOM_SCREEN, "Loading FIRM...\n");
fprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n");
if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, NATIVE_FIRM_TITLEID) != 0)
}
void boot_cfw() {
- fprintf(TOP_SCREEN, "Applying patches...\n");
+ fprintf(BOTTOM_SCREEN, "Applying patches...\n");
if (patch_firm_all() != 0)
return;
get = BUTTON_UP;
else if (HID_PAD & BUTTON_DOWN)
get = BUTTON_DOWN;
+ else if (HID_PAD & BUTTON_RIGHT)
+ get = BUTTON_RIGHT;
+ else if (HID_PAD & BUTTON_LEFT)
+ get = BUTTON_LEFT;
else if (HID_PAD & BUTTON_A)
get = BUTTON_A;
else if (HID_PAD & BUTTON_B)
return get;
}
-void header() {
- fprintf(stdout, "\x1b[33;40m[.corbenik//%s]\x1b[0m\n", VERSION);
+void header(char* append) {
+ fprintf(stdout, "\x1b[33;40m[.corbenik//%s] %s\x1b[0m\n", VERSION, append);
}
int menu_patches() { return MENU_MAIN; }
int menu_options() {
set_cursor(TOP_SCREEN, 0, 0);
- header();
+ header("A:Enter B:Back DPAD:Nav");
int i = 0;
while(options[i].index != -1) { // -1 Sentinel.
fprintf(TOP_SCREEN, " ");
if (need_redraw)
- fprintf(TOP_SCREEN, "[%c] %s\n", (config.options[options[i].index] ? 'X' : ' '), options[i].name);
+ fprintf(TOP_SCREEN, "[%c] %s\n", (config.options[options[i].index] ? 'X' : ' '), options[i].name);
else {
// Yes, this is weird. printf does a large number of extra things we don't
// want computed at the moment; this is faster.
set_cursor(TOP_SCREEN, 0, 0);
- header();
+ header("Any:Back");
struct firm_signature *native = get_firm_info(firm_loc);
struct firm_signature *agb = get_firm_info(agb_firm_loc);
struct firm_signature *twl = get_firm_info(twl_firm_loc);
"AGB_FIRM / GBA Firmware:\n"
" Version: %s (%x)\n"
"TWL_FIRM / DSi Firmware:\n"
- " Version: %s (%x)\n"
- "\n"
- "[Press any key]\n",
+ " Version: %s (%x)\n",
native->version_string, native->version,
agb->version_string, agb->version,
twl->version_string, twl->version);
set_cursor(TOP_SCREEN, 0, 0);
- header();
+ header("Any:Back");
fprintf(stdout, "\nCorbenik is a 3DS firmware patching tool;\n"
" commonly known as a CFW. It seeks to address\n"
};
int menu_max = 7;
- header();
+ header("A:Enter DPAD:Nav");
for(int i=0; i < menu_max; i++) {
if (!(i+2 == MENU_HELP && config.options[OPTION_READ_ME])) {