--- /dev/null
+ * Attempt to create a replacement handler for Service 0x3D, AKA OutputDebugString(void const, int) to log to a file on SD.
case 0x0004013000008002LL: // NS
{
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.
+ adjust_cpu_settings(progId, text, orig_size);
break;
}
PATH := $(PATH):$(DEVKITARM)/bin
-all: 7b.bin
+all: 7b.bin stub.bin
%.o: %.s
arm-none-eabi-as -o $@ $<
--- /dev/null
+// This is not intended to be built, but is what a stub service's code is
+.section .text
+.global _start
+_start:
+ ldr r0, =0xf8c007f4
+ bx lr
#include "firm/fcram.h"
#include "firm/firm.h"
-extern void flush_cache();
-
-extern firm_h *firm_loc;
-extern exefs_h *firm_p9_exefs;
-
-extern firm_h *twl_firm_loc;
-extern exefs_h *twl_firm_p9_exefs;
+// Yes, this is EXACTLY what it looks like. We dynamically link and
+// load patches as binaries; they use functions from corbenik to do
+// the work, and therefore must have a function table in them.
-extern firm_h *agb_firm_loc;
-extern exefs_h *agb_firm_p9_exefs;
+// See vco/template for how this magic works.
-firm_h* __attribute__((optimize("O0"))) get_firm() {
- return firm_loc;
-}
+// This ensures relatively small patches while also having incredible
+// flexibility unlike a 'patch format'.
-exefs_h* __attribute__((optimize("O0"))) get_firm_proc9_exefs() {
+extern exefs_h* firm_p9_exefs;
+exefs_h* get_firm_proc9_exefs() {
return firm_p9_exefs;
}
-firm_h* __attribute__((optimize("O0"))) get_agb() {
- return agb_firm_loc;
+extern exefs_h* twl_firm_p9_exefs;
+exefs_h* get_twl_proc9_exefs() {
+ return twl_firm_p9_exefs;
}
-exefs_h* __attribute__((optimize("O0"))) get_agb_proc9_exefs() {
+extern exefs_h* agb_firm_p9_exefs;
+exefs_h* get_agb_proc9_exefs() {
return agb_firm_p9_exefs;
}
-firm_h* __attribute__((optimize("O0"))) get_twl() {
- return twl_firm_loc;
-}
-
-exefs_h* __attribute__((optimize("O0"))) get_twl_proc9_exefs() {
- return twl_firm_p9_exefs;
-}
-
-// Yes, this is EXACTLY what it looks like. We dynamically link and
-// load patches as binaries; they use functions from corbenik to do
-// the work, and therefore must have a function table in them.
-
-// See vco/template for how this magic works.
-
-// This ensures relatively small patches while also having incredible
-// flexibility unlike a 'patch format'.
-
int execp(char* path) {
int basename = 0;
for(basename=strlen(path); basename > 0; basename--)
break;
basename++;
- fprintf(stderr, "Executing patchbin: %s\n", &path[basename]);
+ fprintf(stderr, "Exec: %s\n", &path[basename]);
struct system_patch patch;
fclose(f);
fprintf(stderr, "[s]");
- // Now then...find the magical number.
- uint8_t magic[] = { 0xc0, 0x9b, 0xe5, 0x1c };
- uint32_t* link_table = (uint32_t*)memfind((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, patch.patch_size, magic, 4);
- if (link_table == NULL) {
- fprintf(stderr, "\n Table missing. Abort.\n");
- return 1;
- }
+ uint32_t* link_table = (uint32_t*)(FCRAM_PATCHBIN_EXEC_LOC+4);
fprintf(stderr, "[r]");
link_table[26] = (uint32_t)fprintf;
// Get functions
- link_table[28] = (uint32_t)get_firm;
- link_table[30] = (uint32_t)get_firm_proc9_exefs;
+ link_table[28] = (uint32_t)get_firm_proc9_exefs;
- link_table[32] = (uint32_t)get_agb;
- link_table[34] = (uint32_t)get_agb_proc9_exefs;
+ link_table[30] = (uint32_t)get_agb_proc9_exefs;
- link_table[36] = (uint32_t)get_twl;
- link_table[38] = (uint32_t)get_twl_proc9_exefs;
+ link_table[32] = (uint32_t)get_twl_proc9_exefs;
fprintf(stderr, "[b]\n");
#include "../config.h"
#include "../common.h"
+// Do you like examples?
+
int patch_test() {
fprintf(stderr, "Testing, testing, 1, 2, 3, 4..\n");
#include "../config.h"
#include "../common.h"
+// This patch applies the FIRM protection code needed for safe a9lh usage.
+
int patch_firmprot() {
uint8_t *firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
uint32_t size = firm_p9_exefs->fileHeaders[0].size;
#include "../config.h"
#include "../common.h"
+// This patch is responsible for fixing signature checks for the firmware.
+
int patch_signatures() {
//Look for signature checks
#include "../config.h"
#include "../common.h"
+// This patch handles replacement of services. This includes backdoor, but not just backdoor.
+// Any service can be replaced provided there's enough space within the exception page.
+
+// Please note that the actual code for services is in `external/service`.
+
uint32_t *getSvcAndExceptions(uint8_t *pos, uint32_t size, uint32_t **exceptionsPage) {
uint8_t pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
+++ /dev/null
-../../template/src/link_table.s
\ No newline at end of file
-/* This memory map is mainly to assist in doing stuff in code.
-MEMORY
-{
- INSTRUCTION_TCM (rw) : ORIGIN = 0x00000000, LENGTH = 0x08000000
- ARM_INTERNAL (rw) : ORIGIN = 0x08000000, LENGTH = 0x00100000
- NEW_INTERNAL (rw) : ORIGIN = 0x08100000, LENGTH = 0x00080000
- IO_MEMORY (rw) : ORIGIN = 0x10000000, LENGTH = 0x08000000
- VRAM (rw) : ORIGIN = 0x18000000, LENGTH = 0x00600000
- DSP_MEMORY (rw) : ORIGIN = 0x1FF00000, LENGTH = 0x00080000
- AXI_WRAM (rw) : ORIGIN = 0x1FF80000, LENGTH = 0x00080000
- FCRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x08000000
- NEW_FCRAM (rwx) : ORIGIN = 0x28000000, LENGTH = 0x08000000
- DATA_TCM (rw) : ORIGIN = 0xFFF00000, LENGTH = 0x00004000
- BOOTROM (rw) : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000
-} */
-
ENTRY(_start)
SECTIONS
{
}
START_SECTION_END = .;
- TABLE_SECTION = .;
- .text.table : {
- *(.text.table)
- }
- TABLE_SECTION_END = .;
-
TEXT_SECTION = .;
.text : {
*(.text)
+++ /dev/null
-.section .text.table
-.align 4
-
-.macro stub name
- .global \name
- \name :
- ldr pc, [pc, #-4] // Load the data after this to the PC. return will be before this call.
- bx lr // Fall through in case of error.
-.endm
-
-// (int) [0]
-.global MAGIC_START
-MAGIC_START:
- .byte 0xc0
- .byte 0x9b
- .byte 0xe5
- .byte 0x1c
-
-// Exported functions.
-
-// memory.c
-// (int) [3]
-stub strlen
-// (int) [5]
-stub isprint
-// (int) [7]
-stub memcpy
-// (int) [9]
-stub memmove
-// (int) [11]
-stub memset
-// (int) [13]
-stub memcmp
-// (int) [15]
-stub strncpy
-// (int) [17]
-stub strncmp
-// (int) [19]
-stub atoi
-// (int) [21]
-stub memfind
-
-// draw.c
-// (int) [23]
-stub putc
-// (int) [25]
-stub puts
-// (int) [27]
-stub fprintf
-
-// Wrappers to get shit.
-
-// Gets NATIVE_FIRM memory offset as (firm_h*)
-stub get_firm
-
-// Get NATIVE_FIRM process9
-stub get_firm_proc9_exefs
-
-// Gets AGB_FIRM.
-stub get_agb
-
-// Get AGB_FIRM process9 exefs
-stub get_agb_proc9_exefs
-
-// Gets TWL_FIRM.
-stub get_twl
-
-// Get TWL_FIRM process9 exefs
-stub get_twl_proc9_exefs
.global _start
_start:
b main
-_die:
- b _die // I have no clue how one would end up here.
+
+.macro stub name
+ .global \name
+ \name :
+ ldr pc, [pc, #-4] // Load the data after this to the PC. return will be before this call.
+ bx lr // Fall through in case of error.
+.endm
+
+// memory.c
+stub strlen
+stub isprint
+stub memcpy
+stub memmove
+stub memset
+stub memcmp
+stub strncpy
+stub strncmp
+stub atoi
+stub memfind
+
+// draw.c
+stub putc
+stub puts
+stub fprintf
+
+// Wrappers to get shit.
+
+// Get NATIVE_FIRM process9
+stub get_firm_proc9_exefs
+
+// Get AGB_FIRM process9 exefs
+stub get_agb_proc9_exefs
+
+// Get TWL_FIRM process9 exefs
+stub get_twl_proc9_exefs