From: chaoskagami Date: Tue, 31 May 2016 11:53:37 +0000 (-0400) Subject: Add logging to loader (yes, that means sdmc write support) X-Git-Tag: stable-1~25 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=c472099b10291ef12b95fbf636d11b9e714096af;p=corbenik%2Fcorbenik.git Add logging to loader (yes, that means sdmc write support) --- diff --git a/external/loader/README.md b/external/loader/README.md index ca2d3ec..579f44e 100644 --- a/external/loader/README.md +++ b/external/loader/README.md @@ -13,40 +13,52 @@ There is support for patching any executable after it's loaded but before it starts. For example, you can patch `menu` to skip region checks and have region free game launching directly from the home menu. -This currently requires recompilation which makes it less than ideal. +There is also support for SDMC read/write (not found in original loader +implementation) which means that information can be logged to SD. -There is also support for SDMC reading (not found in original loader -implementation) which means that patches can be loaded from the SD card. -Ultimately, there will be a patch system that supports easy loading of -patches from the SD card. +## About this fork -## Changes I've made +A lot of the 'disassembled' looking code has been rewritten for readability +(notable the lzss decompressor), and some cruft was cleaned out. Notably, +IFile increased the cxi size by two (!) pages, and therefore has been removed, +as it offers nothing over direct use of FSFILE and FSLDR. -A lot of the 'disassembled' looking code has been rewritten for readability, and -many cruft-ish artifacts of it have been cleaned up. Some wrapper functions -have also been rewritten out of the code, and anything nigh-unreadable and -non-rewritable has been documented when I managed to figure out what it does. +This version of loader is capable of logging to the filesystem through added +write support. Tecnically, all the work for this was already in place, but IFile +didn't allow accessing this functionality. This makes debugging much easier, +since you can now actually figure out what went wrong. -At the moment there is also experimental support for resizing segments before -loading the executable. This means that segments can be appended to. Notably, -this allows tacking on code to the end. +Experimental support for resizing segments before loading the executable was +added. This means that segments can be appended to. Notably, this allows tacking +code onto the end. -The text, data, and ro segments are handled separately to streamline the new -segment resizing and limit search space to speed things up a tad. Why search -text, data and ro (big) when you know it is in text? +The text, data, and ro segments are now handled separately to speed things up +marginally, since if you know a patch is applied to text there's no reason to +search the data segment, etc. ## Imported changes from other 3ds_injector forks -I updated it to the latest git ctrulib (in which FS_Archive is a u64, -not a struct.) @TuxSH did the work before me, although it required manual -conflict merges since my tree differs a LOT from both @yifanlu and his -version. +This was updated to the latest git ctrulib (in which FS_Archive typing has +changed to allow mountpoints.) + +@TuxSH did this work before me, although I had to implement changes +manually due to my tree sharing almost nothing at this point with upstream or +Luma. It did serve as a useful reference, though. :) ## Build You need a working 3DS build environment with a fairly recent copy of devkitARM, ctrulib, and makerom. -This is not intended to be used with anything but corbenik, so please don't use -binaries of this with any other CFW. For devs - message me if there's any changes -you want help merging. I'll be glad to help. I'm not into anti-competitive -behavior. ;P +This will automatically be built by corbenik's top-level makefile, so you shouldn't +need to monkey around in here if you aren't making changes. + +## Misc + +This is not intended to be used with anything but corbenik due to specific use of +structures incompatible with other CFW, so don't attempt to inject this with other +CFWs. At best, it doesn't work. At worst, you can't boot without removing it. + +For devs - message me if there's any changes you want help merging to your fork. +I'll be glad to help, either to explain what has been done here or to port changes. +I'm not into anti-competitive behavior, since we're all just trying to make the 3DS +better as a whole. ;P diff --git a/external/loader/source/internal.h b/external/loader/source/internal.h index f410804..a3ead07 100644 --- a/external/loader/source/internal.h +++ b/external/loader/source/internal.h @@ -1,8 +1,8 @@ #ifndef __INTERNAL_H #define __INTERNAL_H -// This is a GCC builtin, and so there's no need to carry an implementation -// here. +// These are libc builtins, so there's no need to carry an implementation here. void* memcpy(void* dest, const void* src, size_t len); +size_t strlen(const char* string); #endif diff --git a/external/loader/source/loader.c b/external/loader/source/loader.c index b7ed35b..e0a0269 100644 --- a/external/loader/source/loader.c +++ b/external/loader/source/loader.c @@ -7,6 +7,7 @@ #include "srvsys.h" #include "lzss.h" #include "internal.h" +#include "logger.h" // TODO - a lot of this is unecessarily verbose and shitty. Clean it up to be // tidy. @@ -160,6 +161,8 @@ loader_LoadProcess(Handle* process, u64 prog_handle) u64 progid; u32 text_grow, data_grow, ro_grow; + openLogger(); + // make sure the cached info corrosponds to the current prog_handle if (g_cached_prog_handle != prog_handle) { res = loader_GetProgramInfo(&g_exheader, prog_handle); @@ -182,6 +185,8 @@ loader_LoadProcess(Handle* process, u64 prog_handle) return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2); } + logstr("validated params\n"); + load_config(); // First order of business - we need the config file. // Check and set the CPU mode. Possible values: 0 - Keep o3ds speed, 1 - @@ -255,6 +260,8 @@ loader_LoadProcess(Handle* process, u64 prog_handle) &codeset, &codesetinfo, (void*)shared_addr.text_addr, (void*)shared_addr.ro_addr, (void*)shared_addr.data_addr); if (res >= 0) { + closeLogger(); + res = svcCreateProcess(process, codeset, g_exheader.arm11kernelcaps.descriptors, count); diff --git a/external/loader/source/logger.c b/external/loader/source/logger.c new file mode 100644 index 0000000..b440683 --- /dev/null +++ b/external/loader/source/logger.c @@ -0,0 +1,60 @@ +#include <3ds.h> +#include "patcher.h" +#include "fsldr.h" +#include "internal.h" +#include "memory.h" + +#ifndef PATH_MAX +#define PATH_MAX 255 +#define _MAX_LFN 255 +#endif +#include "config.h" +#include "../../../source/patch_format.h" + +#include "patch/patch.h" + +Handle log_file_hdl; +int logger_is_initd = 0; + +void openLogger() { + Result r; + + if (logger_is_initd) + return; + + r = fileOpen(&log_file_hdl, ARCHIVE_SDMC, "/corbenik/loader.log", FS_OPEN_WRITE|FS_OPEN_READ|FS_OPEN_CREATE); + + if (R_FAILED(r)) { + logger_is_initd = -1; + } + + logger_is_initd = 1; +} + +void logstr(const char* str) { + if (logger_is_initd == -1) + return; // Errored during init. Don't bother. + + u32 len = strlen(str); + u64 size; + u32 wrote; + Result r; + + // Get current size. + r = FSFILE_GetSize(log_file_hdl, &size); + if (R_FAILED(r)) + return; + + // Expand file size. + r = FSFILE_SetSize(log_file_hdl, size+len); + if (R_FAILED(r)) + return; + + // Write data. + FSFILE_Write(log_file_hdl, &wrote, size, str, len, 0); +} + +void closeLogger() { + FSFILE_Close(log_file_hdl); + logger_is_initd = 0; +} diff --git a/external/loader/source/logger.h b/external/loader/source/logger.h new file mode 100644 index 0000000..912f9bd --- /dev/null +++ b/external/loader/source/logger.h @@ -0,0 +1,8 @@ +#ifndef __LOGGER_H +#define __LOGGER_H + +void openLogger(); +void logstr(const char* str); +void closeLogger(); + +#endif diff --git a/external/loader/source/memory.c b/external/loader/source/memory.c new file mode 100644 index 0000000..40a9ddd --- /dev/null +++ b/external/loader/source/memory.c @@ -0,0 +1,92 @@ +#include <3ds.h> +#include "patcher.h" +#include "fsldr.h" +#include "internal.h" + +#ifndef PATH_MAX +#define PATH_MAX 255 +#define _MAX_LFN 255 +#endif +#include "config.h" +#include "../../../source/patch_format.h" + +#include "patch/patch.h" + +int +memcmp(const void* buf1, const void* buf2, u32 size) +{ + const u8* buf1c = (const u8*)buf1; + const u8* buf2c = (const u8*)buf2; + + for (u32 i = 0; i < size; i++) { + int cmp = buf1c[i] - buf2c[i]; + if (cmp) + return cmp; + } + + return 0; +} + +// Quick Search algorithm, adapted from +// http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 +u8* +memfind(u8* startPos, u32 size, const void* pattern, u32 patternSize) +{ + const u8* patternc = (const u8*)pattern; + + // Preprocessing + u32 table[256]; + + for (u32 i = 0; i < 256; ++i) + table[i] = patternSize + 1; + for (u32 i = 0; i < patternSize; ++i) + table[patternc[i]] = patternSize - i; + + // Searching + u32 j = 0; + + while (j <= size - patternSize) { + if (memcmp(patternc, startPos + j, patternSize) == 0) + return startPos + j; + j += table[startPos[j + patternSize]]; + } + + return NULL; +} + +u32 +patchMemory(u8* start, u32 size, const void* pattern, u32 patSize, int offset, + const void* replace, u32 repSize, u32 count) +{ + u32 i; + + for (i = 0; i < count; i++) { + u8* found = memfind(start, size, pattern, patSize); + + if (found == NULL) + break; + + // FIXME - This is throwing on Werror. + memcpy(found + offset, replace, repSize); + + u32 at = (u32)(found - start); + + if (at + patSize > size) + break; + + size -= at + patSize; + start = found + patSize; + } + + return i; +} + +size_t +strnlen(const char* string, size_t maxlen) +{ + size_t size; + + for (size = 0; *string && size < maxlen; string++, size++); + + return size; +} diff --git a/external/loader/source/memory.h b/external/loader/source/memory.h new file mode 100644 index 0000000..9eebaa7 --- /dev/null +++ b/external/loader/source/memory.h @@ -0,0 +1,10 @@ +#ifndef __MEMORY_H +#define __MEMORY_H + +int memcmp(const void* buf1, const void* buf2, u32 size); +u8* memfind(u8* startPos, u32 size, const void* pattern, u32 patternSize); +u32 patchMemory(u8* start, u32 size, const void* pattern, u32 patSize, int offset, + const void* replace, u32 repSize, u32 count); +size_t strnlen(const char* string, size_t maxlen); + +#endif diff --git a/external/loader/source/patch/block_cart_update.c b/external/loader/source/patch/block_cart_update.c index bf307c8..5ba83fe 100644 --- a/external/loader/source/patch/block_cart_update.c +++ b/external/loader/source/patch/block_cart_update.c @@ -10,4 +10,6 @@ disable_cart_updates(u64 progId, u8* code, u32 size) patchMemory(code, size, stopCartUpdatesPattern, sizeof(stopCartUpdatesPattern), 0, stopCartUpdatesPatch, sizeof(stopCartUpdatesPatch), 2); + + logstr("disable_cart_updates\n"); } diff --git a/external/loader/source/patch/block_eshop_update.c b/external/loader/source/patch/block_eshop_update.c index d240154..c0c4803 100644 --- a/external/loader/source/patch/block_eshop_update.c +++ b/external/loader/source/patch/block_eshop_update.c @@ -12,4 +12,6 @@ disable_eshop_updates(u64 progId, u8* code, u32 size) sizeof(skipEshopUpdateCheckPattern), 0, skipEshopUpdateCheckPatch, sizeof(skipEshopUpdateCheckPatch), 1); + + logstr("disable_eshop_updates\n"); } diff --git a/external/loader/source/patch/block_nim_update.c b/external/loader/source/patch/block_nim_update.c index eee7d53..c3753da 100644 --- a/external/loader/source/patch/block_nim_update.c +++ b/external/loader/source/patch/block_nim_update.c @@ -10,4 +10,6 @@ disable_nim_updates(u64 progId, u8* code, u32 size) patchMemory(code, size, blockAutoUpdatesPattern, sizeof(blockAutoUpdatesPattern), 0, blockAutoUpdatesPatch, sizeof(blockAutoUpdatesPatch), 1); + + logstr("disable_nim_updates\n"); } diff --git a/external/loader/source/patch/friends_ver.c b/external/loader/source/patch/friends_ver.c index fc50ecb..07a0e24 100644 --- a/external/loader/source/patch/friends_ver.c +++ b/external/loader/source/patch/friends_ver.c @@ -10,4 +10,6 @@ fake_friends_version(u64 progId, u8* code, u32 size) // Allow online access to work with old friends modules patchMemory(code, size, fpdVerPattern, sizeof(fpdVerPattern), 9, &fpdVerPatch, sizeof(fpdVerPatch), 1); + + logstr("fake_friends_version\n"); } diff --git a/external/loader/source/patch/mset_str.c b/external/loader/source/patch/mset_str.c index 9690879..f5ba815 100644 --- a/external/loader/source/patch/mset_str.c +++ b/external/loader/source/patch/mset_str.c @@ -9,4 +9,6 @@ settings_string(u64 progId, u8* code, u32 size) // Patch Ver. string patchMemory(code, size, verPattern, sizeof(verPattern) - sizeof(u16), 0, verPatch, sizeof(verPatch) - sizeof(u16), 1); + + logstr("settings_string\n"); } diff --git a/external/loader/source/patch/patch.h b/external/loader/source/patch/patch.h index a9ed7ed..de6c95d 100644 --- a/external/loader/source/patch/patch.h +++ b/external/loader/source/patch/patch.h @@ -3,6 +3,8 @@ #include <3ds.h> #include "../patcher.h" +#include "../memory.h" +#include "../logger.h" #ifndef PATH_MAX #define PATH_MAX 255 diff --git a/external/loader/source/patch/regionfree.c b/external/loader/source/patch/regionfree.c index a50a00b..6f9d505 100644 --- a/external/loader/source/patch/regionfree.c +++ b/external/loader/source/patch/regionfree.c @@ -11,4 +11,6 @@ region_patch(u64 progId, u8* code, u32 size) // Patch SMDH region checks patchMemory(code, size, regionFreePattern, sizeof(regionFreePattern), -16, regionFreePatch, sizeof(regionFreePatch), 1); + + logstr("region_patch\n"); } diff --git a/external/loader/source/patch/ro_sigs.c b/external/loader/source/patch/ro_sigs.c index c9985a2..76e5980 100644 --- a/external/loader/source/patch/ro_sigs.c +++ b/external/loader/source/patch/ro_sigs.c @@ -23,4 +23,6 @@ ro_sigpatch(u64 progId, u8* code, u32 size) patchMemory(code, size, sha256ChecksPattern2, sizeof(sha256ChecksPattern2), 0, stub, sizeof(stub), 1); + + logstr("ro_sigpatch\n"); } diff --git a/external/loader/source/patch/secinfo_sigs.c b/external/loader/source/patch/secinfo_sigs.c index c7bd706..52b62a1 100644 --- a/external/loader/source/patch/secinfo_sigs.c +++ b/external/loader/source/patch/secinfo_sigs.c @@ -11,4 +11,6 @@ secureinfo_sigpatch(u64 progId, u8* code, u32 size) patchMemory(code, size, secureinfoSigCheckPattern, sizeof(secureinfoSigCheckPattern), 0, secureinfoSigCheckPatch, sizeof(secureinfoSigCheckPatch), 1); + + logstr("secureinfo_sigpatch\n"); } diff --git a/external/loader/source/patcher.c b/external/loader/source/patcher.c index ad97176..d41fa17 100644 --- a/external/loader/source/patcher.c +++ b/external/loader/source/patcher.c @@ -2,6 +2,8 @@ #include "patcher.h" #include "fsldr.h" #include "internal.h" +#include "memory.h" +#include "logger.h" #ifndef PATH_MAX #define PATH_MAX 255 @@ -12,87 +14,7 @@ #include "patch/patch.h" -static int -memcmp(const void* buf1, const void* buf2, u32 size) -{ - const u8* buf1c = (const u8*)buf1; - const u8* buf2c = (const u8*)buf2; - - for (u32 i = 0; i < size; i++) { - int cmp = buf1c[i] - buf2c[i]; - if (cmp) - return cmp; - } - - return 0; -} - -// Quick Search algorithm, adapted from -// http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 -static u8* -memfind(u8* startPos, u32 size, const void* pattern, u32 patternSize) -{ - const u8* patternc = (const u8*)pattern; - - // Preprocessing - u32 table[256]; - - for (u32 i = 0; i < 256; ++i) - table[i] = patternSize + 1; - for (u32 i = 0; i < patternSize; ++i) - table[patternc[i]] = patternSize - i; - - // Searching - u32 j = 0; - - while (j <= size - patternSize) { - if (memcmp(patternc, startPos + j, patternSize) == 0) - return startPos + j; - j += table[startPos[j + patternSize]]; - } - - return NULL; -} - -u32 -patchMemory(u8* start, u32 size, const void* pattern, u32 patSize, int offset, - const void* replace, u32 repSize, u32 count) -{ - u32 i; - - for (i = 0; i < count; i++) { - u8* found = memfind(start, size, pattern, patSize); - - if (found == NULL) - break; - - // FIXME - This is throwing on Werror. - memcpy(found + offset, replace, repSize); - - u32 at = (u32)(found - start); - - if (at + patSize > size) - break; - - size -= at + patSize; - start = found + patSize; - } - - return i; -} - -static inline size_t -strnlen(const char* string, size_t maxlen) -{ - size_t size; - - for (size = 0; *string && size < maxlen; string++, size++) - ; - - return size; -} - -static int +int fileOpen(Handle* file, FS_ArchiveID id, const char* path, int flags) { FS_Path apath; @@ -149,6 +71,8 @@ load_config() failed_load_config = 0; + logstr("loaded config file\n"); + return; } @@ -210,6 +134,10 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) break; } } + + logstr("langemu cfg applied\n"); + logstr(path); + logstr("\n"); } return ret; } @@ -308,6 +236,8 @@ patchCfgGetLanguage(u8* code, u32 size, u8 languageId, 0xE3B00000; // (1 or 2 instructions) => movs // r0, 0 (result code) + logstr("patched language\n"); + // We're done return; } @@ -342,6 +272,8 @@ patchCfgGetRegion(u8* code, u32 size, u8 regionId, u32 CFGUHandleOffset) break; } } + + logstr("patched region\n"); } static void @@ -399,6 +331,8 @@ language_emu(u64 progId, u8* code, u32 size) } } } + + logstr("set up langemu\n"); } void diff --git a/external/loader/source/patcher.h b/external/loader/source/patcher.h index 085dc7b..6619e6f 100644 --- a/external/loader/source/patcher.h +++ b/external/loader/source/patcher.h @@ -13,8 +13,7 @@ u32 get_data_extend(u64 progId, u32 size_orig); void load_config(); -u32 patchMemory(u8* start, u32 size, const void* pattern, u32 patSize, - int offset, const void* replace, u32 repSize, u32 count); +int fileOpen(Handle* file, FS_ArchiveID id, const char* path, int flags); u8 get_cpumode(u64 progId);