#ifndef __INTERP_H
#define __INTERP_H
-int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len);
+int execb(uint64_t tid, uint8_t* search_mem, uint32_t search_len);
#endif
if (progId == 0x0004013000008002LL)
adjust_cpu_settings(progId, text, orig_size);
- execb(PATH_PATCHES "/block_nim_update.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/block_eshop_update.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/block_cart_update.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/errdisp.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/friends_ver.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/mset_str.vco", progId, text, orig_size);
-// execb(PATH_PATCHES "/ns_force_menu.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/regionfree.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/secinfo_sigs.vco", progId, text, orig_size);
- execb(PATH_PATCHES "/ro_sigs.vco", progId, text, orig_size);
+ execb(progId, text, orig_size);
language_emu(progId, text, orig_size);
}
break;
case OP_NEXT:
bytecode = code + 1;
+#ifndef LOADER
set_mode = 3;
current_mode = &modes[set_mode];
+#endif
offset = 0;
test_was_false = 0;
code = bytecode;
}
#ifdef LOADER
-int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len) {
+int execb(uint64_t tid, uint8_t* search_mem, uint32_t search_len) {
#else
int execb(char* filename) {
#endif
uint32_t patch_len;
- struct system_patch* patch;
#ifdef LOADER
- log(" check ");
- log(filename);
- log("\n");
+ char cache_path[] = PATH_LOADER_CACHE "/0000000000000000";
+ int len = strlen(cache_path) - 16;
- uint8_t patch_dat2[MAX_PATCHSIZE];
- uint8_t *patch_dat = patch_dat2;
+ uint8_t* title_buf = (uint8_t*)&tid;
- patch = (struct system_patch*)patch_dat;
+ for(int j = 0; j < 8; j++) {
+ cache_path[len+(j*2)] = ("0123456789ABCDEF")[(title_buf[j] >> 4) & 0x0f];
+ cache_path[len+(j*2)+1] = ("0123456789ABCDEF")[ title_buf[j] & 0x0f];
+ }
+
+ static uint8_t patch_dat[MAX_PATCHSIZE];
Handle file;
u32 total;
// Open file.
- if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, filename, FS_OPEN_READ))) {
+ if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, cache_path, FS_OPEN_READ))) {
// Failed to open.
- return 1;
+ return 0; // No patches.
}
+ log(" patch: ");
+ log(cache_path);
+ log("\n");
+
u64 file_size;
if (!R_SUCCEEDED(FSFILE_GetSize(file, &file_size))) {
modes[18].memory = search_mem;
modes[18].size = search_len;
- // Check magic.
- if (memcmp(patch->magic, "AIDA", 4)) {
- log(" magic wrong\n");
-
- return 1; // Incorrect patch magic.
- }
-
- // Check TID supported.
- if (patch->titles == 0) {
- return 0; // Not an error - this patch isn't meant for us.
- }
-
- log(" checking tid\n");
-
- uint8_t* title_buf = patch_dat + sizeof(struct system_patch);
-
- int apply = 0;
-
- for(uint32_t i=0; i < patch->titles; i++, title_buf += 8) {
- if(!memcmp(title_buf, (uint8_t*)&tid, 8)) {
- // Applicable patch found.
- log(" applicable\n");
- apply = 1;
- break;
- }
- }
-
- if (!apply) {
- // Not meant for us.
- return 0;
- }
-
- // Patch is relevant to us, so we'll apply it.
-
log(" exec\n");
- uint8_t* patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8);
- patch_len = patch->size;
+ uint8_t* patch_mem = (uint8_t*)patch_dat;
+ patch_len = file_size;
#else
+ struct system_patch* patch;
uint8_t* patch_mem;
// Read patch to scrap memory.
return 1;
}
+ patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8);
+ patch_len = patch->size;
+
if (patch->titles != 0) {
// Not an error, per se, but it means this patch is meant for loader, not us.
// Patches intended for use during boot will always be applied to zero titles.
// We should generate a cache for loader in a file intended for titleid.
+ uint8_t* title_buf = (uint8_t*)patch + sizeof(struct system_patch);
+
+ for(uint32_t i=0; i < patch->titles; i++, title_buf += 8) {
+ // FIXME - This is outputting once per boot. We need to detect and nuke the cache.
+ char cache_path[] = PATH_LOADER_CACHE "/0000000000000000";
+ int len = strlen(cache_path) - 16;
+
+ for(int j = 0; j < 8; j++) {
+ cache_path[len+(j*2)] = ("0123456789ABCDEF")[(title_buf[j] >> 4) & 0x0f];
+ cache_path[len+(j*2)+1] = ("0123456789ABCDEF")[ title_buf[j] & 0x0f];
+ }
+
+ char reset = 0xFF;
+
+ FILE* cache = fopen(cache_path, "w");
+ fseek(cache, 0, SEEK_END);
+ fwrite(patch_mem, 1, patch_len, cache);
+ fwrite(&reset, 1, 1, cache);
+ fclose(cache);
+ // Add to cache.
+ }
+
return 0;
}
fprintf(stderr, "Patch: %s\n", patch->name);
- patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8);
- patch_len = patch->size;
#endif
return exec_bytecode(patch_mem, patch_len, 0);
}
+++ /dev/null
-#include "patch_file.h"
-
-PATCH(aadowngrade)
-{
- execb(PATH_PATCHES "/aadowngrade.vco");
-
- return 0;
-}
+++ /dev/null
-#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)
-{
- execb(PATH_PATCHES "/memexec.vco");
-
- return 0;
-}
+++ /dev/null
-#include "patch_file.h"
-
-// This patch applies the FIRM protection code needed for safe a9lh usage.
-
-PATCH(firmprot)
-{
- execb(PATH_PATCHES "/prot.vco");
-
- return 0;
-}
+++ /dev/null
-#include "patch_file.h"
-
-// This patch is responsible for fixing signature checks for the firmware.
-
-PATCH(signatures)
-{
- execb(PATH_PATCHES "/sig.vco");
-
- return 0;
-}
+++ /dev/null
-#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)
-{
- execb(PATH_PATCHES "/unitinfo.vco");
-
- return 0;
-}
#define PATH_FIRMWARES PATH_CFW "/lib/firmware" // Firmware folder.
#define PATH_MODULES PATH_CFW "/lib/module" // Sysmodule location
#define PATH_SERVICES PATH_CFW "/lib/service" // Service code location.
+
+#define PATH_LOADER_CACHE PATH_CFW "/lib/loader" // Cached patch bytecode for loader.
+
#define PATH_TEMP \
PATH_CFW "/tmp" // Files that are transient (user can delete them and they
// will be regenerated)
#include "firm/firm.h"
#include "config.h"
#include "common.h"
+#include "interp.h"
// TODO - Basically all this needs to move to patcher programs.
uint32_t wait_key();
-extern int patch_signatures();
-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;
int
patch_firm_all()
{
- // Use builtin signature patcher?
-
- if (config.options[OPTION_SIGPATCH]) {
- // TODO - Patch menu. This is okay-ish for now.
- // if(execp(PATH_PATCHES "/signatures.vco")) {
- if (patch_signatures()) {
- abort("Fatal. Sigpatch has failed.");
- }
-
- wait();
- }
-
- if (config.options[OPTION_FIRMPROT]) {
- if (patch_firmprot()) {
- abort("Fatal. Firmprot has failed.");
- }
-
- wait();
- }
+ // Remove cache
+ f_unlink(PATH_LOADER_CACHE);
+ f_mkdir(PATH_LOADER_CACHE);
+
+ // Loader only uses TID cache bytecode, so run through these.
+ execb(PATH_PATCHES "/block_nim_update.vco");
+ execb(PATH_PATCHES "/block_eshop_update.vco");
+ execb(PATH_PATCHES "/block_cart_update.vco");
+ execb(PATH_PATCHES "/errdisp.vco");
+ execb(PATH_PATCHES "/friends_ver.vco");
+ execb(PATH_PATCHES "/mset_str.vco");
+// execb(PATH_PATCHES "/ns_force_menu.vco");
+ execb(PATH_PATCHES "/regionfree.vco");
+ execb(PATH_PATCHES "/secinfo_sigs.vco");
+ execb(PATH_PATCHES "/ro_sigs.vco");
// Replace loader?
if (config.options[OPTION_LOADER]) {
wait();
}
+ // Use builtin signature patcher?
+ if (config.options[OPTION_SIGPATCH]) {
+ // TODO - Patch menu. This is okay-ish for now.
+ if(execb(PATH_PATCHES "/sig.vco")) {
+ abort("Fatal. Sigpatch has failed.");
+ }
+
+ wait();
+ }
+
+ if (config.options[OPTION_FIRMPROT]) {
+ if(execb(PATH_PATCHES "/prot.vco")) {
+ abort("Fatal. Firmprot has failed.");
+ }
+
+ wait();
+ }
+
if (config.options[OPTION_AADOWNGRADE]) {
- if (patch_aadowngrade()) {
+ if(execb(PATH_PATCHES "/aadowngrade.vco")) {
abort("Anti-anti-downgrade patch failed.");
}
}
if (config.options[OPTION_UNITINFO]) {
- if (patch_unitinfo()) {
+ if(execb(PATH_PATCHES "/unitinfo.vco")) {
abort("UNITINFO patch failed.");
}
}
if (config.options[OPTION_MEMEXEC]) {
- if (patch_memexec()) {
+ if(execb(PATH_PATCHES "/memexec.vco")) {
abort("MPU execution patch failed.");
}