From: chaoskagami Date: Thu, 19 May 2016 19:26:23 +0000 (-0400) Subject: Many changes here. X-Git-Tag: stable-1~63 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=0329d74ba2105f2028d3dd965852b7cd9bca0017;p=corbenik%2Fcorbenik.git Many changes here. - 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. --- diff --git a/external/Makefile b/external/Makefile index c623d56..736b3a0 100644 --- a/external/Makefile +++ b/external/Makefile @@ -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 diff --git a/external/loader/source/ifile.c b/external/loader/source/ifile.c index 5faf2ae..4433cbe 100644 --- a/external/loader/source/ifile.c +++ b/external/loader/source/ifile.c @@ -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. +} diff --git a/external/loader/source/ifile.h b/external/loader/source/ifile.h index bf2ae7e..d4b256e 100644 --- a/external/loader/source/ifile.h +++ b/external/loader/source/ifile.h @@ -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); diff --git a/external/loader/source/loader.c b/external/loader/source/loader.c index 9698b8d..74ebd86 100644 --- a/external/loader/source/loader.c +++ b/external/loader/source/loader.c @@ -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; diff --git a/external/loader/source/patcher.c b/external/loader/source/patcher.c index efe681b..272ea5e 100644 --- a/external/loader/source/patcher.c +++ b/external/loader/source/patcher.c @@ -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 +} diff --git a/external/loader/source/patcher.h b/external/loader/source/patcher.h index 4bb48ea..710b8fc 100644 --- a/external/loader/source/patcher.h +++ b/external/loader/source/patcher.h @@ -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(); diff --git a/external/service/backdoor.s b/external/service/7b.s similarity index 56% rename from external/service/backdoor.s rename to external/service/7b.s index 3450322..9a22f67 100644 --- a/external/service/backdoor.s +++ b/external/service/7b.s @@ -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 index 0000000..b390e72 --- /dev/null +++ b/external/service/Makefile @@ -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 index 0000000..c089581 --- /dev/null +++ b/external/service/link.ld @@ -0,0 +1,6 @@ +SECTIONS +{ + .text : { + *(.text.*) + } +} diff --git a/source/config.h b/source/config.h index 261ac4d..c87a314 100644 --- a/source/config.h +++ b/source/config.h @@ -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. diff --git a/source/menu.c b/source/menu.c index 21efc0d..b26ae33 100644 --- a/source/menu.c +++ b/source/menu.c @@ -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 }, diff --git a/source/patch/module.c b/source/patch/module.c index ea52e79..ccc6cd9 100644 --- a/source/patch/module.c +++ b/source/patch/module.c @@ -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. } diff --git a/source/patch/svc.c b/source/patch/svc.c index 21c880d..661a4be 100644 --- a/source/patch/svc.c +++ b/source/patch/svc.c @@ -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; diff --git a/source/patch_format.h b/source/patch_format.h index b0ae99d..27d13cc 100644 --- a/source/patch_format.h +++ b/source/patch_format.h @@ -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 '.exefs' diff --git a/source/patcher.c b/source/patcher.c index 0d6bae1..0e1758a 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -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]) {