From: root Date: Wed, 1 Jun 2016 12:45:59 +0000 (-0400) Subject: Import (and correct) a few more bits from Luma3DS X-Git-Tag: stable-1~21 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=4c9b0e41e20ff9138a2b928c09eb72a7b74be9cf;p=corbenik%2Fcorbenik.git Import (and correct) a few more bits from Luma3DS --- diff --git a/doc/firmware.md b/doc/firmware.md index 89c08f1..a1edaee 100644 --- a/doc/firmware.md +++ b/doc/firmware.md @@ -32,7 +32,7 @@ New 3DS AGB_FIRM (Firmware for GBA games): Note that while latest is usually greatest, if you MUST use 11.0 FIRMs, please enable both the loader replacement and service fix. Nintendo broke quite a bit, and it was -quite literally a anti-hack. +quite literally a anti-hack update. -Also, I may reimplement a token based svcBackdoor since it can now be used to detect -CFW's presence. +I may implement a token based svcBackdoor since it can now be used to detect CFW's +presence. diff --git a/doc/todo.md b/doc/todo.md index bd9b928..dbb2738 100644 --- a/doc/todo.md +++ b/doc/todo.md @@ -3,6 +3,7 @@ Next * Make config file for corbenik plaintext. Nobody likes binary configs. They suck. Massively. Especially when you fuck up a setting and need to change it on something that isn't a 3ds. * In place firmware loading/patching. + * Weird hack central - Developer 11.4 leaked. Allow injecting debug module? Ehehehehe. No clue what the point of this would be, but hey, it'd be FUCKING cool, man. Shortterm ------------- @@ -31,3 +32,5 @@ Longterm * Rewrite all hardcoded constants that are machine code as assembly. * Read: all the patches. * Change some stdlib functions to more closely imitate their userland counterparts + * EmuNAND. By this, I mean any non-physical NAND, not just gateway style. + * I'd like to implement a loop-mount-like NAND. The NAND would be a file off the SD card rather than a region before partition 1 in this setup, and on the upside near unlimited NANDs could be accomodated without moving partitions. On the downside, any user stupid enough to move the NAND bin while the system is running would be in for severe consequences. diff --git a/external/loader/source/patch/errdisp.c b/external/loader/source/patch/errdisp.c new file mode 100644 index 0000000..8578d93 --- /dev/null +++ b/external/loader/source/patch/errdisp.c @@ -0,0 +1,21 @@ +#include "patch.h" + +void errdisp_devpatch(u64 progId, u8* code, u32 size) { + static const u8 unitinfoCheckPattern1[] = {0x14, 0x00, 0xD0, 0xE5, 0xDB, 0x9A, 0x9F, 0xED}; + static const u8 unitinfoCheckPattern2[] = {0x14, 0x00, 0xD0, 0xE5, 0x01, 0x00, 0x10, 0xE3} ; + static const u8 unitinfoCheckPatch[] = {0x00, 0x00, 0xA0, 0xE3} ; + + patchMemory(code, size, + unitinfoCheckPattern1, + sizeof(unitinfoCheckPattern1), 0, + unitinfoCheckPatch, + sizeof(unitinfoCheckPatch), 1 + ); + + patchMemory(code, size, + unitinfoCheckPattern2, + sizeof(unitinfoCheckPattern2), 0, + unitinfoCheckPatch, + sizeof(unitinfoCheckPatch), 3 + ); +} diff --git a/external/loader/source/patch/patch.h b/external/loader/source/patch/patch.h index de6c95d..e9bc4c4 100644 --- a/external/loader/source/patch/patch.h +++ b/external/loader/source/patch/patch.h @@ -21,5 +21,6 @@ void settings_string(u64 progId, u8* code, u32 size); void region_patch(u64 progId, u8* code, u32 size); void ro_sigpatch(u64 progId, u8* code, u32 size); void secureinfo_sigpatch(u64 progId, u8* code, u32 size); +void errdisp_devpatch(u64 progId, u8* code, u32 size); #endif diff --git a/external/loader/source/patcher.c b/external/loader/source/patcher.c index 6f5a16a..121f55c 100644 --- a/external/loader/source/patcher.c +++ b/external/loader/source/patcher.c @@ -407,6 +407,11 @@ patch_text(u64 progId, u8* text, u32 size, u32 orig_size) ro_sigpatch(progId, text, orig_size); break; } + case 0x0004003000008A02LL: // ErrDisp + { + errdisp_devpatch(progId, text, orig_size); + break; + } default: // Anything else. { language_emu(progId, text, orig_size); diff --git a/host/copy.sh b/host/copy.sh index ab6dce3..84ce86b 100755 --- a/host/copy.sh +++ b/host/copy.sh @@ -15,4 +15,5 @@ cp out/arm9loaderhax.bin $mnt/anim/boot/l.bin || exit 0 cp -r out/corbenik $mnt/ || exit 0 cp -r input/corbenik $mnt/ || exit 0 umount $mnt || exit 0 +sync || exit 0 eject ${dev} || exit 0 diff --git a/source/config.h b/source/config.h index 0aad54c..a990723 100644 --- a/source/config.h +++ b/source/config.h @@ -70,6 +70,8 @@ struct options_s // there's a reason. #define OPTION_AADOWNGRADE 16 // Anti-anti-downgrade. +#define OPTION_MEMEXEC 17 // Prevent MPU from disabling execute permissions. +#define OPTION_UNITINFO 18 // Dev UNITINFO. Note that this is overkill. //#define HEADER_COLOR 12 // Color of header text. //#define BG_COLOR 13 // Color of background. diff --git a/source/menu.c b/source/menu.c index ed8f1b7..f8efbb4 100644 --- a/source/menu.c +++ b/source/menu.c @@ -23,16 +23,24 @@ static struct options_s options[] = { { OPTION_FIRMPROT, "FIRM Protection", boolean_val, 0, 0 }, - { OPTION_LOADER, "System Modules (loader)", boolean_val, 0, 0 }, + { OPTION_LOADER, "System Modules", boolean_val, 0, 0 }, { OPTION_LOADER_CPU_L2, " CPU - L2 cache", boolean_val, 0, 0 }, { OPTION_LOADER_CPU_800MHZ, " CPU - 800Mhz", boolean_val, 0, 0 }, { OPTION_LOADER_LANGEMU, " Language Emulation", boolean_val, 0, 0 }, - { OPTION_SERVICES, "Service Replacement", boolean_val, 0, 0 }, - { OPTION_REPLACE_ALLOCATED_SVC, " Force replacement (unsafe)", boolean_val, 0, 0 }, + { OPTION_SERVICES, "Service Replacement", boolean_val, 0, 0 }, { OPTION_AADOWNGRADE, "Anti-anti-downgrade", boolean_val, 0, 0 }, + // space + { 0, "", not_option, 0, 0 }, + // Patches. + { 0, "\x1b[32;40mPatches (Developer)\x1b[0m", not_option, 0, 0 }, + + { OPTION_UNITINFO, "Developer UNITINFO", boolean_val, 0, 0 }, + { OPTION_MEMEXEC, "Disable XN on MPU", boolean_val, 0, 0 }, + { OPTION_REPLACE_ALLOCATED_SVC, "Force service replace", boolean_val, 0, 0 }, + // { OPTION_ARM9THREAD, "ARM9 Thread", boolean_val, 0, 0 }, // space diff --git a/source/patch/memexec.c b/source/patch/memexec.c new file mode 100644 index 0000000..ff3afa9 --- /dev/null +++ b/source/patch/memexec.c @@ -0,0 +1,43 @@ +#include "patch_file.h" + +// This patch clears MPU settings which lock down memory +// execution from userland. You should NOT enable this +// unless you know you need it, because it makes an obvious +// behavioral change that can be used maliciously and/or to +// detect CFW use rather easily. + +PATCH(memexec) +{ + firm_section_h* arm11_section = & firm_loc->section[1]; // Section 1, please. + + uint8_t* firm_mem = (uint8_t*)firm_loc + arm11_section->offset; + uint32_t size = arm11_section->size; + + const uint8_t pattern[] = {0x97, 0x05, 0x00, 0x00, 0x15, 0xE4, 0x00, 0x00}; + + // We look for 'exe:' first; this string is close to what we patch + uint32_t* off = (uint32_t*)memfind(firm_mem, size, pattern, 8); + + if (off == NULL) { + fprintf(stderr, "memexec: couldn't find pattern.\n"); + return 1; + } + + // NOTE - Luma3DS' check here was incoherent. + // It read as 'decrement until 0x00000000, which means on + // failure it would cause lockup due to read of unreadable mapped areas. + // Even worse, it could end up patching something that isn't in FCRAM. + while(off > (uint32_t*)firm_mem && *off != 0x16416) + off--; + + if(off == (uint32_t*)firm_mem) { + fprintf(stderr, "memexec: beginning missing.\n"); + return 1; + } + + *off &= ~(1 << 4); //Clear XN bit + + fprintf(stderr, "memexec: Cleared XN bit.\n"); + + return 0; +} diff --git a/source/patch/module.c b/source/patch/module.c index b10b978..005d293 100644 --- a/source/patch/module.c +++ b/source/patch/module.c @@ -2,7 +2,7 @@ PATCH(modules) { - // TODO - load module cxi here + // TODO - load other module cxis here FILE* f = fopen(PATH_MODULES "/loader.cxi", "r"); if (!f) { fprintf(stderr, "Module: loader.cxi not found on FS\n"); diff --git a/source/patch/unitinfo.c b/source/patch/unitinfo.c new file mode 100644 index 0000000..57f47c8 --- /dev/null +++ b/source/patch/unitinfo.c @@ -0,0 +1,44 @@ +#include "patch_file.h" + +// This patch makes the console think it is a developer unit. +// Note that this is generally invasive and not useful to users; +// usually the ErrDisp patch in loader should be good enough for +// debugging crashes. + +PATCH(unitinfo) +{ + firm_section_h* arm9_section; + int found_sect = 0; + + for (arm9_section = firm_loc->section; + arm9_section < firm_loc->section + 4; arm9_section++) { + if (arm9_section->type == FIRM_TYPE_ARM9) { + found_sect = 1; + break; + } + } + + if (!found_sect) { + fprintf(stderr, "unitinfo: no arm9 section?\n"); + return 1; + } + + uint8_t* firm_mem = (uint8_t*)firm_loc + arm9_section->offset; + uint32_t size = arm9_section->size; + + const uint8_t pattern[] = {0x01, 0x10, 0xA0, 0x13}; + + // We look for 'exe:' first; this string is close to what we patch + uint8_t* off = memfind(firm_mem, size, pattern, 4); + + if (off == NULL) { + fprintf(stderr, "unitinfo: Couldn't find UNITINFO.\n"); + return 1; + } + + off[3] = 0xE3; + + fprintf(stderr, "unitinfo: Applied\n"); + + return 0; +} diff --git a/source/patcher.c b/source/patcher.c index f33151a..720194d 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -15,6 +15,8 @@ extern int patch_firmprot(); extern int patch_services(); extern int patch_modules(); extern int patch_aadowngrade(); +extern int patch_memexec(); +extern int patch_unitinfo(); extern int doing_autoboot; @@ -84,5 +86,21 @@ patch_firm_all() wait(); } + if (config.options[OPTION_UNITINFO]) { + if (patch_unitinfo()) { + abort("UNITINFO patch failed."); + } + + wait(); + } + + if (config.options[OPTION_MEMEXEC]) { + if (patch_memexec()) { + abort("MPU execution patch failed."); + } + + wait(); + } + return 0; } diff --git a/source/std/draw.c b/source/std/draw.c index 0cdacac..491910a 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -373,6 +373,8 @@ fflush(void* channel) } } +int disable_format = 0; + void vfprintf(void* channel, const char* format, va_list ap) { @@ -425,7 +427,7 @@ vfprintf(void* channel, const char* format, va_list ap) // terminates an ANSI sequence while (!(*ref >= 0x40 && *ref <= 0x7E)) ref++; - } else if (*ref == '%') { + } else if (*ref == '%' && !disable_format) { int type_size = 0; int length = -1; check_format: @@ -453,7 +455,10 @@ vfprintf(void* channel, const char* format, va_list ap) } break; case 's': - puts(channel, va_arg(ap, char*)); + // Using puts isn't correct here... + disable_format = 1; // Disable format strings. + fprintf(channel, va_arg(ap, char*)); + disable_format = 0; // Reenable. break; case 'c': putc(channel, va_arg(ap, int));