]> Chaos Git - corbenik/corbenik.git/commitdiff
Many changes here.
authorchaoskagami <chaos.kagami@gmail.com>
Thu, 19 May 2016 19:26:23 +0000 (15:26 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Thu, 19 May 2016 19:26:23 +0000 (15:26 -0400)
- Make services assembled from .s files in external/services
- Arbitrary service loading now, including a NULL safety toggle
- Drop armips for clever gnu as usage
- Loader can (theoretically) resize segments now, so one step closer
  to building a romfs overlay into loader
- Split function for patches into text, data, ro patches
- Stub IFile_Write - Hopefully I implement it soon, I'd like logging.
- Other misc changes. I forget whether this was the previous commit,
  but I added @TuxSH's RO patch.

15 files changed:
external/Makefile
external/loader/source/ifile.c
external/loader/source/ifile.h
external/loader/source/loader.c
external/loader/source/patcher.c
external/loader/source/patcher.h
external/service/7b.s [moved from external/service/backdoor.s with 56% similarity]
external/service/Makefile [new file with mode: 0644]
external/service/link.ld [new file with mode: 0644]
source/config.h
source/menu.c
source/patch/module.c
source/patch/svc.c
source/patch_format.h
source/patcher.c

index c623d56a85ce7a8b797af3a23dc7edab42a97bad..736b3a005c92668ae1075281e96ec9d54e9ff7a6 100644 (file)
@@ -1,10 +1,12 @@
-.PHONY: all copyout
-all: loader
+.PHONY: all
+all: loader service
        mkdir -p ../out/corbenik/lib/module
+       mkdir -p ../out/corbenik/lib/service
        cp loader/loader.cxi ../out/corbenik/lib/module/loader.cxi
+       cp service/7b.bin ../out/corbenik/lib/service/7b.bin
 
 .PHONY: clean
-clean: clean_loader
+clean: clean_loader clean_service
        rm -rf ../out/corbenik/bin
 
 .PHONY: loader
@@ -14,3 +16,11 @@ loader:
 .PHONY: clean_loader
 clean_loader:
        make -C loader clean
+
+.PHONY: service
+service:
+       make -C service
+
+.PHONY: clean_service
+clean_service:
+       make -C service clean
index 5faf2ae3b14ff93397ee3ae7e2cb82a864831ed1..4433cbe0f43e5475e86609591920f7bcf4508292 100644 (file)
@@ -63,4 +63,8 @@ Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len)
 
   *total = cur;
   return res;
-}
\ No newline at end of file
+}
+
+Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len) {
+       return 1; // FIXME - Not yet implemented.
+}
index bf2ae7e70c9efc958bb1af34b39a3d4e344f7ecb..d4b256e46086bbf990ab82fa017fb6aaab348486 100644 (file)
@@ -12,4 +12,5 @@ typedef struct
 Result IFile_Open(IFile *file, FS_Archive archive, FS_Path path, u32 flags);
 Result IFile_Close(IFile *file);
 Result IFile_GetSize(IFile *file, u64 *size);
-Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len);
\ No newline at end of file
+Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len);
+Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len);
index 9698b8d1a4cd7d51ea3f4cc5f5583cd405298b0a..74ebd864ea17c92672b6c01c772e1758ddc265a8 100644 (file)
@@ -97,16 +97,18 @@ static int lzss_decompress(u8 *end)
 
 static Result allocate_shared_mem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags)
 {
+  // Somehow, we need to allow reallocating.
+
   u32 dummy;
 
   memcpy(shared, vaddr, sizeof(prog_addrs_t));
-  shared->text_addr = 0x10000000;
+  shared->text_addr = 0x10000000; // Code is forcibly relocated to this address to kill ASLR (I believe.)
   shared->ro_addr = shared->text_addr + (shared->text_size << 12);
   shared->data_addr = shared->ro_addr + (shared->ro_size << 12);
   return svcControlMemory(&dummy, shared->text_addr, 0, shared->total_size << 12, (flags & 0xF00) | MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
 }
 
-static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int is_compressed)
+static Result load_code(u64 progid, prog_addrs_t *shared, prog_addrs_t *original, u64 prog_handle, int is_compressed)
 {
   IFile file;
   FS_Archive archive;
@@ -156,8 +158,10 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
     lzss_decompress((u8 *)shared->text_addr + size);
   }
 
-  // patch
-  patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
+  // Patch segments
+  patch_text(progid, (u8 *)shared->text_addr, shared->text_size << 12, original->text_size << 12);
+  patch_data(progid, (u8 *)shared->data_addr, shared->data_size << 12, original->data_size << 12);
+  patch_ro  (progid, (u8 *)shared->ro_addr,   shared->ro_size << 12,   original->ro_size << 12);
 
   return 0;
 }
@@ -195,10 +199,12 @@ static Result loader_LoadProcess(Handle *process, u64 prog_handle)
   u32 dummy;
   prog_addrs_t shared_addr;
   prog_addrs_t vaddr;
+  prog_addrs_t original_vaddr;
   Handle codeset;
   CodeSetInfo codesetinfo;
   u32 data_mem_size;
   u64 progid;
+  u32 text_grow, data_grow, ro_grow;
 
   // make sure the cached info corrosponds to the current prog_handle
   if (g_cached_prog_handle != prog_handle)
@@ -227,15 +233,31 @@ static Result loader_LoadProcess(Handle *process, u64 prog_handle)
     return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2);
   }
 
-  // allocate process memory
+  load_config(); // First order of business - we need the config file.
+
+  // What the addressing info would be if not for expansion. This is passed to patchCode.
+  original_vaddr.text_size = (g_exheader.codesetinfo.text.codesize + 4095) >> 12; // (Text size + one page) >> page size
+  original_vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + 4095) >> 12;
+  original_vaddr.data_size = (g_exheader.codesetinfo.data.codesize + 4095) >> 12;
+  original_vaddr.total_size = original_vaddr.text_size + original_vaddr.ro_size + original_vaddr.data_size;
+
+  // Allow changing code, ro, data sizes to allow adding code
+  text_grow = get_text_extend(progid, g_exheader.codesetinfo.text.codesize);
+  ro_grow   = get_ro_extend(progid, g_exheader.codesetinfo.ro.codesize);
+  data_grow = get_data_extend(progid, g_exheader.codesetinfo.data.codesize);
+
+  // One page is 4096 bytes, thus all the 4095 constants.
+
+  // Allocate process memory, growing as needed for extra patches
   vaddr.text_addr = g_exheader.codesetinfo.text.address;
-  vaddr.text_size = (g_exheader.codesetinfo.text.codesize + 4095) >> 12;
+  vaddr.text_size = (g_exheader.codesetinfo.text.codesize + text_grow + 4095) >> 12; // (Text size + one page) >> page size
   vaddr.ro_addr = g_exheader.codesetinfo.ro.address;
-  vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + 4095) >> 12;
+  vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + ro_grow + 4095) >> 12;
   vaddr.data_addr = g_exheader.codesetinfo.data.address;
-  vaddr.data_size = (g_exheader.codesetinfo.data.codesize + 4095) >> 12;
-  data_mem_size = (g_exheader.codesetinfo.data.codesize + g_exheader.codesetinfo.bsssize + 4095) >> 12;
-  vaddr.total_size = vaddr.text_size + vaddr.ro_size + vaddr.data_size;
+  vaddr.data_size = (g_exheader.codesetinfo.data.codesize + data_grow + 4095) >> 12;
+  data_mem_size = (g_exheader.codesetinfo.data.codesize + text_grow + g_exheader.codesetinfo.bsssize + 4095) >> 12;
+  vaddr.total_size = vaddr.text_size + vaddr.ro_size + vaddr.data_size + text_grow + ro_grow + data_grow;
+
   if ((res = allocate_shared_mem(&shared_addr, &vaddr, flags)) < 0)
   {
     return res;
@@ -243,7 +265,7 @@ static Result loader_LoadProcess(Handle *process, u64 prog_handle)
 
   // load code
   progid = g_exheader.arm11systemlocalcaps.programid;
-  if ((res = load_code(progid, &shared_addr, prog_handle, g_exheader.codesetinfo.flags.flag & 1)) >= 0)
+  if ((res = load_code(progid, &shared_addr, &original_vaddr, prog_handle, g_exheader.codesetinfo.flags.flag & 1)) >= 0)
   {
     memcpy(&codesetinfo.name, g_exheader.codesetinfo.name, 8);
     codesetinfo.program_id = progid;
index efe681b91dd87685fae3974d508dc9f98fae2c23..272ea5e6c12e85695d6d6c86d03eca50e1ae21c1 100644 (file)
@@ -120,7 +120,7 @@ static u32 secureInfoExists(void)
 static struct config_file config;
 static int failed_load_config = 1;
 
-static void load_config() {
+void load_config() {
        static IFile file;
     static u64 total;
 
@@ -507,12 +507,19 @@ void language_emu(u64 progId, u8 *code, u32 size) {
 }
 
 void overlay_patch(u64 progId, u8 *code, u32 size) {
-       // TODO - Prt
+       // TODO - Implement.
 }
 
-void patchCode(u64 progId, u8 *code, u32 size) {
-       load_config();
+// This is only for the .data segment.
+void patch_data(u64 progId, u8 *data, u32 size, u32 orig_size) {
+}
+
+// This is only for the .ro segment.
+void patch_ro(u64 progId, u8 *ro, u32 size, u32 orig_size) {
+}
 
+// This is only for the .code segment.
+void patch_text(u64 progId, u8 *text, u32 size, u32 orig_size) {
     switch(progId)
     {
         case 0x0004003000008F02LL: // USA Menu
@@ -522,20 +529,20 @@ void patchCode(u64 progId, u8 *code, u32 size) {
         case 0x000400300000A902LL: // KOR Menu
         case 0x000400300000B102LL: // TWN Menu
         {
-                       region_patch(progId, code, size);
+                       region_patch(progId, text, orig_size);
             break;
         }
 
         case 0x0004013000002C02LL: // NIM
         {
-                       disable_nim_updates(progId, code, size);
-                       disable_eshop_updates(progId, code, size);
+                       disable_nim_updates(progId, text, orig_size);
+                       disable_eshop_updates(progId, text, orig_size);
             break;
         }
 
         case 0x0004013000003202LL: // FRIENDS
         {
-                       fake_friends_version(progId, code, size);
+                       fake_friends_version(progId, text, orig_size);
             break;
         }
 
@@ -546,36 +553,45 @@ void patchCode(u64 progId, u8 *code, u32 size) {
         case 0x0004001000027000LL: // KOR MSET
         case 0x0004001000028000LL: // TWN MSET
         {
-                       settings_string(progId, code, size);
+                       settings_string(progId, text, size);
             break;
         }
         case 0x0004013000008002LL: // NS
         {
-                       disable_cart_updates(progId, code, size);
-                       adjust_cpu_settings(progId, code, size); // DEFAULT cpu settings that are inherited system-wide. Per-app is handled in default.
+                       disable_cart_updates(progId, text, orig_size);
+                       adjust_cpu_settings(progId, text, orig_size); // DEFAULT cpu settings that are inherited system-wide. Per-app is handled in default.
             break;
         }
 
         case 0x0004013000001702LL: // CFG
         {
-                       secureinfo_sigpatch(progId, code, size);
+                       secureinfo_sigpatch(progId, text, orig_size);
             break;
         }
                case 0x0004013000003702LL: // RO
                {
-                       ro_sigpatch(progId, code, size);
+                       ro_sigpatch(progId, text, orig_size);
                        break;
                }
-               case 0x00040000000B8B00LL: // Smash 4
-        case 0x00040000000EE000LL:
-        case 0x00040000000EDF00LL:
+        default: // Anything else.
                {
-                       saltysd_patch(progId, code, size);
-               }
-        default:
-               {
-                       language_emu(progId, code, size);
+                       language_emu(progId, text, orig_size);
             break;
         }
     }
 }
+
+// Gets how many bytes .text must be extended by for patches to fit.
+u32 get_text_extend(u64 progId, u32 size_orig) {
+       return 0; // Stub - nothing needs this yet
+}
+
+// Gets how many bytes .ro must be extended.
+u32 get_ro_extend(u64 progId, u32 size_orig) {
+       return 0; // Stub - nothing needs this yet
+}
+
+// Again, same, but for .data.
+u32 get_data_extend(u64 progId, u32 size_orig) {
+       return 0; // Stub - nothing needs this yet
+}
index 4bb48ea3825a9580b31ca174fc2f1c208705781f..710b8fca6ad20d1cfc12618fa39eac5d04107e37 100644 (file)
@@ -2,4 +2,12 @@
 
 #include <3ds/types.h>
 
-void patchCode(u64 progId, u8 *code, u32 size);
\ No newline at end of file
+void patch_text(u64 progId, u8 *text, u32 size, u32 orig_size);
+void patch_data(u64 progId, u8 *data, u32 size, u32 orig_size);
+void patch_ro(u64 progId, u8 *ro, u32 size, u32 orig_size);
+
+u32 get_text_extend(u64 progId, u32 size_orig);
+u32 get_ro_extend(u64 progId, u32 size_orig);
+u32 get_data_extend(u64 progId, u32 size_orig);
+
+void load_config();
similarity index 56%
rename from external/service/backdoor.s
rename to external/service/7b.s
index 34503227a7ae8c9c96d0e67663c0b881a7a16e12..9a22f67d215a06177fe1a072de697439ffec13d5 100644 (file)
@@ -1,8 +1,9 @@
 // This is svcBackdoor's code from earlier FIRMs
-.arm.little
-.create "backdoor.bin", 0
-       // Luckily, no ARM9/ARM11 specific instructions are used here.
-       // It can just be assembled via ARM9 gas.
+// Luckily, no ARM9/ARM11 specific instructions are used here.
+// It can just be assembled via ARM9 gas.
+.section .text
+.global _start
+_start:
        bic r1, sp, #0xff
        orr r1, r1, #0xf00
        add r1, r1, #0x28
@@ -13,4 +14,3 @@
        pop {r0, r1}
        mov sp, r0
        bx r1
-.close
diff --git a/external/service/Makefile b/external/service/Makefile
new file mode 100644 (file)
index 0000000..b390e72
--- /dev/null
@@ -0,0 +1,16 @@
+PATH := $(PATH):$(DEVKITARM)/bin
+
+all: 7b.bin
+
+%.o: %.s
+       arm-none-eabi-as -o $@ $<
+
+%.elf: %.o
+       arm-none-eabi-ld -T link.ld -o $@ $<
+
+%.bin: %.elf
+       arm-none-eabi-objcopy -O binary $< $@
+
+.PHONY: clean
+clean:
+       rm -f *.bin *.elf *.o
diff --git a/external/service/link.ld b/external/service/link.ld
new file mode 100644 (file)
index 0000000..c089581
--- /dev/null
@@ -0,0 +1,6 @@
+SECTIONS
+{
+    .text : {
+               *(.text.*)
+       }
+}
index 261ac4d30331bc36d1282bcadf15532dc3b6b5be..c87a314a5707f2f0157ba5cf532ea5f55d74121c 100644 (file)
@@ -52,6 +52,8 @@ struct options_s {
 #define OPTION_LOADER_CPU_800MHZ 12 // Enable 800Mhz mode.
 #define OPTION_LOADER_LANGEMU  13 // Enable 800Mhz mode.
 
+#define OPTION_REPLACE_ALLOCATED_SVC 14 // Replace allocated services. Normally you don't want this.
+
 #define IGNORE_PATCH_DEPS    14  // Ignore patch UUID dependencies. Not recommended.
 #define IGNORE_BROKEN_SHIT   15 // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason.
 
index 21efc0d7c47a951a3ac211248ccf7c882e67c381..b26ae33df1a2ee52981c92950cef95a6b5195ac8 100644 (file)
@@ -31,6 +31,8 @@ static struct options_s options[] = {
        { 12, "Loader: CPU 800Mhz mode", boolean_val, 0, 0 },
        { 13, "Loader: Language Emulation", boolean_val, 0, 0 },
 
+       { 13, "Svc: Force replace allocated", boolean_val, 0, 0 },
+
        { 14, "No dependency tracking", boolean_val, 0, 0 },
        { 15, "Allow unsafe options", boolean_val, 0, 0 },
 
index ea52e795b0aa9103240345fdcf1471945a68704d..ccc6cd9afb78a8753fbd8790b4d90b28cd2e94d6 100644 (file)
@@ -40,16 +40,18 @@ int patch_modules() {
                if (memcmp(sysmodule->programID, module->programID, 8) == 0) {
                        // Expand firmware module size if needed to accomodate replacement.
                        if (module->contentSize > sysmodule->contentSize) {
+                               uint32_t need_units = (module->contentSize - sysmodule->contentSize);
+                               fprintf(stderr, "Module: Would grow %d units but NYI\n", need_units);
+                               continue;
                                // FIXME - Adjust sysmodule section and FIRM NCCH. This is not correct.
-                               fprintf(stderr, "Module: Grow %d units\n", module->contentSize - sysmodule->contentSize);
+/*                             fprintf(stderr, "Module: Grow %d units\n", module->contentSize - sysmodule->contentSize);
                                // Location to shuffle to.
-                               uint32_t need_units = (module->contentSize - sysmodule->contentSize);
                                uint8_t* move_to = ((uint8_t*)sysmodule + (module->contentSize + need_units) * 0x200);
                                uint8_t* move_from = ((uint8_t*)sysmodule + module->contentSize * 0x200);
 
                                uint32_t copy_size = 0x10000; // FIXME - Add a safe way to properly calculate the half of NCCH we need to copy. This is okay for now.
 
-                               memmove(move_to, move_from, copy_size);
+                               memmove(move_to, move_from, copy_size); */
                                // TODO - This is hackish and possibly incorrect. It needs testing.
                        }
 
index 21c880daf0110086fb85c02cd6183689a0a6c444..661a4beaf0cdaeea60457e56b8d987639c1c1900 100644 (file)
@@ -27,16 +27,33 @@ int patch_services() {
 
        fprintf(stderr, "Svc: table at %x\n", (uint32_t)svcTable);
 
-    if(!svcTable[0x7B]) {
-        // Firmware is missing svcBackdoor. Fix it.
-        fprintf(stderr, "Svc: inject 0x7B (backdoor)\n");
+       char str[] = PATH_SERVICES "/00.bin";
+       char* at = str + (strlen(str) - 6);
+       for(uint32_t i=0; i <= 0xff; i++) {
+               // Get string for svc.
+               at[0] = ("0123456789abcdef")[((i >> 4) & 0xf)]; // This is just hexdump. Nothing complicated.
+               at[1] = ("0123456789abcdef")[(i & 0xf)];
 
-        // See extra/backdoor.s for the code to this.
-        const unsigned char svcbackdoor[40] = {
-            0xFF, 0x10, 0xCD, 0xE3, 0x0F, 0x1C, 0x81, 0xE3, 0x28, 0x10, 0x81, 0xE2, 0x00, 0x20, 0x91, 0xE5,
-            0x00, 0x60, 0x22, 0xE9, 0x02, 0xD0, 0xA0, 0xE1, 0x30, 0xFF, 0x2F, 0xE1, 0x03, 0x00, 0xBD, 0xE8,
-            0x00, 0xD0, 0xA0, 0xE1, 0x11, 0xFF, 0x2F, 0xE1
-        };
+               FILE* data = fopen(str, "r");
+               if (!data) {
+                       continue; // No file for svc. Move on.
+               }
+
+               // Refuse to replace non-NULL services unless the user says to.
+               if (svcTable[i] && !config.options[OPTION_REPLACE_ALLOCATED_SVC]) {
+                       fclose(data);
+                       fprintf(stderr, "Svc: %x non-null, moving on\n", i);
+                       continue;
+               }
+
+               uint32_t size    = fsize(data);
+               uint8_t* read_to = (void*)FCRAM_JUNK_LOCATION;
+
+               fprintf(stderr, "Svc: %s, %d bytes\n", at, size);
+
+               fread(read_to, 1, size, data);
+
+               fclose(data);
 
                if (!freeSpace) {
                        for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
@@ -44,14 +61,12 @@ int patch_services() {
 
                fprintf(stderr, "Svc: Copy code to %x\n", (uint32_t)freeSpace);
 
-        memcpy(freeSpace, svcbackdoor, sizeof(svcbackdoor));
-        svcTable[0x7B] = 0xFFFF0000 + ((uint8_t *)freeSpace - (uint8_t *)exceptionsPage);
+        memcpy(freeSpace, read_to, size);
+        svcTable[i] = 0xFFFF0000 + ((uint8_t *)freeSpace - (uint8_t *)exceptionsPage);
 
-               freeSpace += sizeof(svcbackdoor); // We keep track of this because there's more than 7B free.
+               freeSpace += size; // We keep track of this because there's more than 7B free.
 
                fprintf(stderr, "Svc: entry set as %x\n", svcTable[0x7B]);
-    } else {
-        fprintf(stderr, "Svc: no change\n");
        }
 
        return 0;
index b0ae99db7a3a5f08c8c5e521afc8ac29e22ee548..27d13cc7b039162fee25d612ffdb839d4de20a10 100644 (file)
@@ -35,7 +35,7 @@
 #define PATH_PATCHES    PATH_CFW "/bin"            // Patch binary folder.
 #define PATH_FIRMWARES  PATH_CFW "/lib/firmware"   // Firmware folder.
 #define PATH_MODULES    PATH_CFW "/lib/module"     // Sysmodule location
-#define PATH_SERVICES   PATH_CFW "/lib/svc"        // Service code location.
+#define PATH_SERVICES   PATH_CFW "/lib/service"        // Service code location.
 #define PATH_TEMP       PATH_CFW "/tmp"            // Files that are transient (user can delete them and they will be regenerated)
 #define PATH_KEYS       PATH_CFW "/share/keys"     // Keyfiles will be loaded from this dir, and additionally the root if not found.
 #define PATH_EXEFS      PATH_CFW "/lib/exe"        // ExeFS overrides, named like '<titleid>.exefs'
index 0d6bae1a4cc508f4b58e7178eb012bfad6795a75..0e1758a6b48c3058d21f220e99f3c1aab1c3f3d6 100644 (file)
@@ -37,10 +37,10 @@ extern int doing_autoboot;
 
 void wait() {
        if (config.options[OPTION_TRACE] && !doing_autoboot) {
-               fprintf(stderr, "                                 [WAIT]");
+               fprintf(stderr, "                                  [WAIT]");
                wait_key();
        }
-       fprintf(stderr, "\r                                       \r");
+       fprintf(stderr, "\r                                        \r");
 }
 
 int patch_firm_all() {
@@ -51,10 +51,6 @@ int patch_firm_all() {
 
        // Use builtin signature patcher?
 
-       // TODO - Obviously these get moved to external patchers.
-       fprintf(stderr, "Sigpatch: %s\n", ((config.options[OPTION_SIGPATCH]) ? "yes" : "no" ));
-       fprintf(stderr, "Protect: %s\n",  ((config.options[OPTION_FIRMPROT]) ? "yes" : "no" ));
-
        wait();
 
        if (config.options[OPTION_SIGPATCH]) {