]> Chaos Git - corbenik/corbenik.git/commitdiff
Import (and correct) a few more bits from Luma3DS
authorroot <chaos.kagami@gmail.com>
Wed, 1 Jun 2016 12:45:59 +0000 (08:45 -0400)
committerroot <chaos.kagami@gmail.com>
Wed, 1 Jun 2016 12:45:59 +0000 (08:45 -0400)
13 files changed:
doc/firmware.md
doc/todo.md
external/loader/source/patch/errdisp.c [new file with mode: 0644]
external/loader/source/patch/patch.h
external/loader/source/patcher.c
host/copy.sh
source/config.h
source/menu.c
source/patch/memexec.c [new file with mode: 0644]
source/patch/module.c
source/patch/unitinfo.c [new file with mode: 0644]
source/patcher.c
source/std/draw.c

index 89c08f13687450a4def82bc836e52727159604a4..a1edaee105fffe3f9af9af24094b718cb0a0491b 100644 (file)
@@ -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.
index bd9b92857d96b9c4203fce4c5cd135e57ab5bfb0..dbb2738ca26019d42ed319a9b6a02c67e874a37a 100644 (file)
@@ -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 (file)
index 0000000..8578d93
--- /dev/null
@@ -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
+       );
+}
index de6c95d883625f86760ced7b081301242b23ec6b..e9bc4c41dd7426bcb4fdf3011ab5d4a94811c429 100644 (file)
@@ -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
index 6f5a16a6e872de81ca7a75f4671102d68da24611..121f55c874a0140122200cb56c6acdb90e8b70c3 100644 (file)
@@ -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);
index ab6dce3e8d52e65d5c85cd1de8eb8c30dabedd47..84ce86b4c752f3bb485781db279d184e1d7adbfa 100755 (executable)
@@ -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
index 0aad54c6a7c4f432f489616be04c6f8d0d52b8ae..a9907231ec19c529bfc1602b227b195f7186d465 100644 (file)
@@ -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.
index ed8f1b7fb53f2fd3677cc2b56c220df877c3b8d9..f8efbb4a54b6570b2f1e62e8a0b8fc8e0b87978b 100644 (file)
@@ -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 (file)
index 0000000..ff3afa9
--- /dev/null
@@ -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;
+}
index b10b9785156a8207afc28f90dd8100b6f232a849..005d2939408ec0e7451d5f67ccd0519a4993d4f5 100644 (file)
@@ -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 (file)
index 0000000..57f47c8
--- /dev/null
@@ -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;
+}
index f33151ab717e33bfd811a4db162dec65dc289d08..720194d7acc3475ed4aa15208697ca038ec08d67 100644 (file)
@@ -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;
 }
index 0cdacac10c3c2b49d81cdafe469212a5ea25d3e8..491910a9287a9f7bc7edd7b2c7fc9813bdca81c1 100644 (file)
@@ -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));