From 8ed239d471fa16b78f77fe304b85d9a99eacce6d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 16 May 2016 22:27:28 -0400 Subject: [PATCH] Relocation is sort-of-working, but sigpatch is broken due to (maybe) compiler black magic or arm icache --- Makefile | 7 +- asm/backdoor.s | 2 + copy.sh | 8 +- patchbins/README.txt | 27 --- patchbins/firmprot/src/exported.h | 25 --- patchbins/firmprot/src/link_table.s | 43 ----- patchbins/firmprot/src/main.c | 36 ---- patchbins/firmprot/src/patcher.c | 171 ------------------ patchbins/firmprot/src/start.s | 6 - patchbins/firmprot/tool/compile_header.c | 91 ---------- patchbins/signatures/Makefile | 60 ------ patchbins/signatures/linker.ld | 59 ------ patchbins/signatures/src/link_table.s | 43 ----- patchbins/signatures/src/main.c | 36 ---- patchbins/signatures/src/start.s | 6 - patchbins/template/Makefile | 60 ------ patchbins/template/linker.ld | 59 ------ patchbins/template/meta/cfw_version | 1 - patchbins/template/meta/deps | 1 - patchbins/template/meta/desc | 1 - patchbins/template/meta/name | 1 - patchbins/template/meta/patch_version | 1 - patchbins/template/meta/title | 1 - patchbins/template/meta/uuid | 1 - patchbins/template/src/exported.h | 25 --- patchbins/template/src/link_table.s | 53 ------ patchbins/template/src/start.s | 8 - patchbins/template/tool/compile_header.c | 91 ---------- source/firm/firm.c | 33 ++-- source/linker.c | 119 +++++++++--- source/patch_format.h | 6 +- source/patcher.c | 57 ++---- source/start.s | 25 +-- source/std/draw.c | 148 ++++++++------- vco/Makefile | 25 +++ vco/README.txt | 44 +++++ vco/signatures/Makefile | 1 + vco/signatures/linker.ld | 1 + .../signatures}/meta/cfw_version | 0 .../firmprot => vco/signatures}/meta/deps | 0 {patchbins => vco}/signatures/meta/desc | 0 {patchbins => vco}/signatures/meta/name | 0 .../signatures}/meta/patch_version | 0 .../firmprot => vco/signatures}/meta/title | 0 .../firmprot => vco/signatures}/meta/uuid | 0 vco/signatures/src/exported.h | 1 + vco/signatures/src/headers.h | 1 + vco/signatures/src/link_table.s | 1 + vco/signatures/src/main.c | 54 ++++++ vco/signatures/src/start.s | 1 + vco/signatures/tool | 1 + {patchbins/firmprot => vco/template}/Makefile | 2 +- .../firmprot => vco/template}/linker.ld | 0 .../template}/meta/cfw_version | 0 .../signatures => vco/template}/meta/deps | 0 .../firmprot => vco/template}/meta/desc | 0 .../firmprot => vco/template}/meta/name | 0 .../template}/meta/patch_version | 0 .../signatures => vco/template}/meta/title | 0 .../signatures => vco/template}/meta/uuid | 0 .../template}/src/exported.h | 16 +- vco/template/src/headers.h | 1 + vco/template/src/link_table.s | 69 +++++++ {patchbins => vco}/template/src/main.c | 0 vco/template/src/start.s | 7 + .../template}/tool/compile_header.c | 9 +- 66 files changed, 457 insertions(+), 1088 deletions(-) delete mode 100644 patchbins/README.txt delete mode 100644 patchbins/firmprot/src/exported.h delete mode 100644 patchbins/firmprot/src/link_table.s delete mode 100644 patchbins/firmprot/src/main.c delete mode 100644 patchbins/firmprot/src/patcher.c delete mode 100644 patchbins/firmprot/src/start.s delete mode 100644 patchbins/firmprot/tool/compile_header.c delete mode 100644 patchbins/signatures/Makefile delete mode 100644 patchbins/signatures/linker.ld delete mode 100644 patchbins/signatures/src/link_table.s delete mode 100644 patchbins/signatures/src/main.c delete mode 100644 patchbins/signatures/src/start.s delete mode 100644 patchbins/template/Makefile delete mode 100644 patchbins/template/linker.ld delete mode 100644 patchbins/template/meta/cfw_version delete mode 100644 patchbins/template/meta/deps delete mode 100644 patchbins/template/meta/desc delete mode 100644 patchbins/template/meta/name delete mode 100644 patchbins/template/meta/patch_version delete mode 100644 patchbins/template/meta/title delete mode 100644 patchbins/template/meta/uuid delete mode 100644 patchbins/template/src/exported.h delete mode 100644 patchbins/template/src/link_table.s delete mode 100644 patchbins/template/src/start.s delete mode 100644 patchbins/template/tool/compile_header.c create mode 100644 vco/Makefile create mode 100644 vco/README.txt create mode 120000 vco/signatures/Makefile create mode 120000 vco/signatures/linker.ld rename {patchbins/firmprot => vco/signatures}/meta/cfw_version (100%) rename {patchbins/firmprot => vco/signatures}/meta/deps (100%) rename {patchbins => vco}/signatures/meta/desc (100%) rename {patchbins => vco}/signatures/meta/name (100%) rename {patchbins/firmprot => vco/signatures}/meta/patch_version (100%) rename {patchbins/firmprot => vco/signatures}/meta/title (100%) rename {patchbins/firmprot => vco/signatures}/meta/uuid (100%) create mode 120000 vco/signatures/src/exported.h create mode 120000 vco/signatures/src/headers.h create mode 120000 vco/signatures/src/link_table.s create mode 100644 vco/signatures/src/main.c create mode 120000 vco/signatures/src/start.s create mode 120000 vco/signatures/tool rename {patchbins/firmprot => vco/template}/Makefile (97%) rename {patchbins/firmprot => vco/template}/linker.ld (100%) rename {patchbins/signatures => vco/template}/meta/cfw_version (100%) rename {patchbins/signatures => vco/template}/meta/deps (100%) rename {patchbins/firmprot => vco/template}/meta/desc (100%) rename {patchbins/firmprot => vco/template}/meta/name (100%) rename {patchbins/signatures => vco/template}/meta/patch_version (100%) rename {patchbins/signatures => vco/template}/meta/title (100%) rename {patchbins/signatures => vco/template}/meta/uuid (100%) rename {patchbins/signatures => vco/template}/src/exported.h (74%) create mode 120000 vco/template/src/headers.h create mode 100644 vco/template/src/link_table.s rename {patchbins => vco}/template/src/main.c (100%) create mode 100644 vco/template/src/start.s rename {patchbins/signatures => vco/template}/tool/compile_header.c (95%) diff --git a/Makefile b/Makefile index 4b3c691..5344ae6 100644 --- a/Makefile +++ b/Makefile @@ -28,13 +28,18 @@ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(call rwildcard, $(dir_source), *.s *.c))) .PHONY: all -all: a9lh +all: a9lh vco + +.PHONY: vco +vco: + make -C vco .PHONY: a9lh a9lh: $(dir_out)/arm9loaderhax.bin .PHONY: clean clean: + make -C vco clean rm -rf $(dir_out) $(dir_build) .PHONY: $(dir_out)/arm9loaderhax.bin diff --git a/asm/backdoor.s b/asm/backdoor.s index bcd09e1..3450322 100644 --- a/asm/backdoor.s +++ b/asm/backdoor.s @@ -1,6 +1,8 @@ // 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. bic r1, sp, #0xff orr r1, r1, #0xf00 add r1, r1, #0x28 diff --git a/copy.sh b/copy.sh index 2ae94e8..4cb3f7f 100644 --- a/copy.sh +++ b/copy.sh @@ -1,4 +1,6 @@ #!/bin/bash -mount /dev/sdb1 /media/sd -cp out/arm9loaderhax.bin /media/sd/anim/boot/a.bin -umount /media/sd +mount /dev/sdb1 /media/cd || exit 0 +cp out/arm9loaderhax.bin /media/cd/anim/boot/a.bin || exit 0 +cp -r out/corbenik /media/cd/ || exit 0 +umount /media/cd || exit 0 +eject /dev/sdb || exit 0 diff --git a/patchbins/README.txt b/patchbins/README.txt deleted file mode 100644 index 21b6567..0000000 --- a/patchbins/README.txt +++ /dev/null @@ -1,27 +0,0 @@ -You're probably wondering what the heck corbenik does differently from cakes, -considering it seems similar. - -Patches are actually code for whatever processor they're intended to run on. -They're loaded to a static offset in memory, and executed. - -Patches should have a declaration of this sort somewhere in them: - { 0xc0, 0x9b, 0xe5, 0x1c } -Followed by a table large enough to fill with all usable functions. - -See template/ for how this works. - -When the loader finds that magic value, it fills the table with -the offsets of important variables and functions for use by the patcher, much -like how an ELF loader sets up references. In other words; patches are binaries -that are relocated relative to a 'standard library'. - -There's some key differences, obviously, from running just arm9loader code. -Namely: - 1) Patches must not clobber the previous state. - 2) Patches must properly return. - 3) Patches must have a symbol table with the appropriate magic. - 4) Patches shouldn't do anything aside from change data. - 5) _start must be at offset 0x24400000. - -Basically, don't get fancy in _start. Just do a bl main; bx lr. You can implement -shit yourself, but it's an utter waste of memory. Try not to. diff --git a/patchbins/firmprot/src/exported.h b/patchbins/firmprot/src/exported.h deleted file mode 100644 index 9c102ae..0000000 --- a/patchbins/firmprot/src/exported.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EXPORTED_H -#define EXPORTED_H - -#define stdout (void*)0 -#define stderr (void*)1 - -extern uint8_t* memory_offset; -extern uint32_t* memory_len; - -extern int strlen(const char *string); -extern int isprint(char c); -extern void memcpy(void *dest, const void *src, size_t size); -extern void memmove(void *dest, const void *src, size_t size); -extern void memset(void *dest, const int filler, size_t size); -extern int memcmp(const void *buf1, const void *buf2, const size_t size); -extern void strncpy(void *dest, const void *src, const size_t size); -extern int strncmp(const void *buf1, const void *buf2, const size_t size); -extern int atoi(const char *str); -extern uint8_t* memfind (uint8_t *string, uint32_t stringlen, uint8_t *pat, uint32_t patlen); - -extern void putc(void* buf, const int c); -extern void puts(void* buf, const char *string); -extern void fprintf(void* channel, const char* format, ...); - -#endif diff --git a/patchbins/firmprot/src/link_table.s b/patchbins/firmprot/src/link_table.s deleted file mode 100644 index 6774354..0000000 --- a/patchbins/firmprot/src/link_table.s +++ /dev/null @@ -1,43 +0,0 @@ -.section .text.table -.align 4 - -.macro stub name - .global \name - \name : - .byte 0 - .byte 0 - .byte 0 - .byte 0 -.endm - -.global MAGIC_START -MAGIC_START: - .byte 0xc0 - .byte 0x9b - .byte 0xe5 - .byte 0x1c - -// Memory to patch as specified by the header. (uint8_t*) -stub memory_offset - -// Size of memory offset. (uint32_t*) -stub memory_len - -// Exported functions. - -// 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 diff --git a/patchbins/firmprot/src/main.c b/patchbins/firmprot/src/main.c deleted file mode 100644 index 93c2b77..0000000 --- a/patchbins/firmprot/src/main.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include "exported.h" - -int main() { - //Look for signature checks - uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7}; - uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C}; - - uint8_t *firm_mem = (uint8_t*)memory_offset; - uint32_t size = *(uint32_t*)memory_len; - - uint8_t *off = memfind(firm_mem, size, pat1, 4); - uint8_t *off2 = memfind(firm_mem, size, pat2, 4) - 1; - - if (off == NULL) { - fprintf(stderr, "Signature patch failed on P0.\n"); - return 1; // Failed to find sigpatch. Ugh. - } - - if (off2 == NULL) { - fprintf(stderr, "Signature patch failed on P1.\n"); - return 2; // Failed to find sigpatch. Ugh. - } - - fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off); - fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2); - - uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47}; - - memcpy(off, sigpatch, 2); - memcpy(off2, sigpatch, 4); - fprintf(stderr, "Signature patch succeded.\n"); - - return 0; -} diff --git a/patchbins/firmprot/src/patcher.c b/patchbins/firmprot/src/patcher.c deleted file mode 100644 index e5cf3c7..0000000 --- a/patchbins/firmprot/src/patcher.c +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include "std/unused.h" -#include "std/memory.h" -#include "firm/firm.h" -#include "config.h" -#include "common.h" - -uint32_t wait_key(); - -// A portion of this file is inherited from Luma3DS. -/* -u16 *getFirmWrite(u8 *pos, u32 size) { - //Look for FIRM writing code - u8 *const off = memsearch(pos, "exe:", size, 4); - const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; - - return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4); -} - -u16 *getFirmWriteSafe(u8 *pos, u32 size) { - //Look for FIRM writing code - const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; - - return (u16 *)memsearch(pos, pattern, size, 4); -} - -u32 getLoader(u8 *pos, u32 *loaderSize) { - u8 *off = pos; - u32 size; - - while(1) - { - size = *(u32 *)(off + 0x104) * 0x200; - if(*(u32 *)(off + 0x200) == 0x64616F6C) break; - off += size; - } - - *loaderSize = size; - - return (u32)(off - pos); -} - - -// patch_location = (void *)((uintptr_t)firm + section->offset + (version->offset - section->address)); - -u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) -{ - u8 *off = memsearch(pos, "ess9", size, 4); - - *process9Size = *(u32 *)(off - 0x60) * 0x200; - *process9MemAddr = *(u32 *)(off + 0xC); - - //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) - return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200; -} -*/ - -int patch_signatures() { - //Look for signature checks - - uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7}; - uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C}; - - 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; - - uint8_t *off = memfind(firm_mem, size, pat1, 4); - uint8_t *off2 = memfind(firm_mem, size, pat2, 4) - 1; - - if (off == NULL) { - fprintf(stderr, "Signature patch failed on P0.\n"); - return 1; // Failed to find sigpatch. Ugh. - } - - if (off2 == NULL) { - fprintf(stderr, "Signature patch failed on P1.\n"); - return 2; // Failed to find sigpatch. Ugh. - } - - fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off); - fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2); - - uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47}; - - memcpy(off, sigpatch, 2); - memcpy(off2, sigpatch, 4); - fprintf(stderr, "Signature patch succeded.\n"); - - return 0; -} - -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; - - //Look for FIRM writing code - uint8_t* off = memfind(firm_mem, size, (uint8_t*)"exe:", 4); - - if(off == NULL) { - fprintf(stderr, "Couldn't find 'exe:' string.\n"); - return 1; - } - - fprintf(stderr, "Firmprot: 'exe:' string @ %x\n", (uint32_t)off); - - uint8_t pattern[] = {0x00, 0x28, 0x01, 0xDA}; - - uint8_t* firmprot = memfind(off - 0x100, 0x100, pattern, 4); - - if(firmprot == NULL) { - fprintf(stderr, "Couldn't find firmprot code.\n"); - return 2; - } - - fprintf(stderr, "Firmprot: %x\n", (uint32_t)firmprot); - - uint8_t patch[] = {0x00, 0x20, 0xC0, 0x46}; - memcpy(firmprot, patch, 4); - - fprintf(stderr, "Applied firmprot patch.\n"); - - return 0; -} - -void wait() { - if (config.options[OPTION_TRACE]) { - fprintf(stderr, "Pausing because trace is on.\n"); - wait_key(); - } -} - -int patch_firm_all() { - // Use builtin signature patcher? - - 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]) { - if(patch_signatures()) { - abort("Fatal. Sigpatch has failed."); - } - } - - wait(); - - if (config.options[OPTION_FIRMPROT]) { - if(patch_firmprot()) { - abort("Fatal. Firmprot has failed."); - } - } - - wait(); - - // Replace loader? - if (config.options[OPTION_LOADER]) { - // Yes. - - // This requires OPTION_SIGPATCH. - } - - // Use ARM9 hook thread? - if (config.options[OPTION_ARM9THREAD]) { - // Yes. - - // FIXME - NYI - } - - return 0; -} diff --git a/patchbins/firmprot/src/start.s b/patchbins/firmprot/src/start.s deleted file mode 100644 index 33e1695..0000000 --- a/patchbins/firmprot/src/start.s +++ /dev/null @@ -1,6 +0,0 @@ -.section .text.start -.align 4 -.global _start -_start: - bl main - bx lr @ return from patch. diff --git a/patchbins/firmprot/tool/compile_header.c b/patchbins/firmprot/tool/compile_header.c deleted file mode 100644 index bf8b2ad..0000000 --- a/patchbins/firmprot/tool/compile_header.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../../../source/patch_format.h" - -void read_file_u64(char* name, uint64_t* to) { - FILE* hdl = fopen(name, "rb"); - fscanf(hdl, "%llu", to); - fclose(hdl); -} - - -void read_file_u32(char* name, uint32_t* to) { - FILE* hdl = fopen(name, "rb"); - fscanf(hdl, "%u", to); - fclose(hdl); -} - -void read_str(char* name, char* to, size_t len) { - FILE* hdl = fopen(name, "rb"); - int r = fread(to, 1, len-1, hdl); - fclose(hdl); -} - -uint32_t size = 0; - -uint8_t* read_file_mem(char* name) { - FILE* hdl = fopen(name, "rb"); - - fseek(hdl, 0, SEEK_END); - size = ftell(hdl); - rewind(hdl); - - uint8_t* mem = malloc(size); - memset(mem, 0, size); - - int r = fread(mem, 1, size, hdl); - fclose(hdl); - - printf("%d\n", size); - - return mem; -} - -int main(int c, char** v) { - struct system_patch patch; - int at = 0; - - memset(&patch, 0, sizeof(patch)); - - // Set magic. - patch.magic[0] = 'A'; - patch.magic[1] = 'I'; - patch.magic[2] = 'D'; - patch.magic[3] = 'A'; - - read_file_u32("meta/patch_version", & patch.patch_ver); - read_file_u32("meta/cfw_version", & patch.load_ver); - - read_file_u64("meta/uuid", & patch.patch_id); - read_file_u64("meta/title", & patch.tid); - - read_str("meta/name", patch.name, sizeof(patch.name)); - read_str("meta/desc", patch.desc, sizeof(patch.desc)); - - uint8_t* code = read_file_mem("out/patch.bin"); - - patch.patch_size = size; - - FILE* out = fopen("out/patch.vco", "wb"); - fwrite(&patch, 1, sizeof(patch), out); - fwrite(code, 1, patch.patch_size, out); - fclose(out); - - free(code); - - printf("Ver: %u\n" - "CFW: %u\n" - "UUID: %llu\n" - "TID: %llu\n" - "Name: %s\n" - "Desc: %s\n" - "Size: %u\n", - patch.patch_ver, patch.load_ver, patch.patch_id, - patch.tid, patch.name, patch.desc, patch.patch_size); - - return 0; -} diff --git a/patchbins/signatures/Makefile b/patchbins/signatures/Makefile deleted file mode 100644 index 7205e8a..0000000 --- a/patchbins/signatures/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) - -PATH := $(PATH):$(DEVKITARM)/bin - -HOST_CC := gcc - -CC := arm-none-eabi-gcc -AS := arm-none-eabi-as -LD := arm-none-eabi-ld -OC := arm-none-eabi-objcopy - -dir_source := src -dir_build := build -dir_out := out - -ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te -CFLAGS := -MMD -MP -Wall -Wextra -Werror -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\" -FLAGS := dir_out=$(abspath $(dir_out)) --no-print-directory -LDFLAGS := -nostdlib -Wl,-z,defs -lgcc - -objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ - $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ - $(call rwildcard, $(dir_source), *.s *.c))) - -.PHONY: all -all: patchbin - -.PHONY: patchbin -patchbin: tool $(dir_out)/patch.bin - ./compile_header - -.PHONY: tool -tool: - $(HOST_CC) -o compile_header tool/compile_header.c - - -.PHONY: clean -clean: - rm -rf $(dir_out) $(dir_build) compile_header - -.PHONY: $(dir_out)/patch.bin -$(dir_out)/patch.bin: $(dir_build)/main.bin - @mkdir -p "$(dir_out)" - @cp -av $< $@ - -$(dir_build)/main.bin: $(dir_build)/main.elf - $(OC) -S -O binary $< $@ - -$(dir_build)/main.elf: $(objects_cfw) - $(CC) -T linker.ld $(OUTPUT_OPTION) $^ $(LDFLAGS) - -$(dir_build)/%.o: $(dir_source)/%.c - @mkdir -p "$(@D)" - $(COMPILE.c) $(OUTPUT_OPTION) $< - -$(dir_build)/%.o: $(dir_source)/%.s - @mkdir -p "$(@D)" - $(COMPILE.s) $(OUTPUT_OPTION) $< - -include $(call rwildcard, $(dir_build), *.d) diff --git a/patchbins/signatures/linker.ld b/patchbins/signatures/linker.ld deleted file mode 100644 index 7d6129b..0000000 --- a/patchbins/signatures/linker.ld +++ /dev/null @@ -1,59 +0,0 @@ -/* 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 -{ - . = 0x24400000; - - START_SECTION = .; - .text.start : { - *(.text.start) - } - START_SECTION_END = .; - - TABLE_SECTION = .; - .text.table : { - *(.text.table) - } - TABLE_SECTION_END = .; - - TEXT_SECTION = .; - .text : { - *(.text) - } - TEXT_SECTION_END = .; - - DATA_SECTION = .; - .data : { - *(.data) - } - DATA_SECTION_END = .; - - BSS_SECTION = .; - .bss : { - *(.bss COMMON) - } - BSS_SECTION_END = .; - - RODATA_SECTION = .; - .rodata : { - *(.rodata) - } - RODATA_SECTION_END = .; - - . = ALIGN(4); -} diff --git a/patchbins/signatures/src/link_table.s b/patchbins/signatures/src/link_table.s deleted file mode 100644 index 6774354..0000000 --- a/patchbins/signatures/src/link_table.s +++ /dev/null @@ -1,43 +0,0 @@ -.section .text.table -.align 4 - -.macro stub name - .global \name - \name : - .byte 0 - .byte 0 - .byte 0 - .byte 0 -.endm - -.global MAGIC_START -MAGIC_START: - .byte 0xc0 - .byte 0x9b - .byte 0xe5 - .byte 0x1c - -// Memory to patch as specified by the header. (uint8_t*) -stub memory_offset - -// Size of memory offset. (uint32_t*) -stub memory_len - -// Exported functions. - -// 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 diff --git a/patchbins/signatures/src/main.c b/patchbins/signatures/src/main.c deleted file mode 100644 index 93c2b77..0000000 --- a/patchbins/signatures/src/main.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include "exported.h" - -int main() { - //Look for signature checks - uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7}; - uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C}; - - uint8_t *firm_mem = (uint8_t*)memory_offset; - uint32_t size = *(uint32_t*)memory_len; - - uint8_t *off = memfind(firm_mem, size, pat1, 4); - uint8_t *off2 = memfind(firm_mem, size, pat2, 4) - 1; - - if (off == NULL) { - fprintf(stderr, "Signature patch failed on P0.\n"); - return 1; // Failed to find sigpatch. Ugh. - } - - if (off2 == NULL) { - fprintf(stderr, "Signature patch failed on P1.\n"); - return 2; // Failed to find sigpatch. Ugh. - } - - fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off); - fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2); - - uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47}; - - memcpy(off, sigpatch, 2); - memcpy(off2, sigpatch, 4); - fprintf(stderr, "Signature patch succeded.\n"); - - return 0; -} diff --git a/patchbins/signatures/src/start.s b/patchbins/signatures/src/start.s deleted file mode 100644 index 33e1695..0000000 --- a/patchbins/signatures/src/start.s +++ /dev/null @@ -1,6 +0,0 @@ -.section .text.start -.align 4 -.global _start -_start: - bl main - bx lr @ return from patch. diff --git a/patchbins/template/Makefile b/patchbins/template/Makefile deleted file mode 100644 index 758faed..0000000 --- a/patchbins/template/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) - -PATH := $(PATH):$(DEVKITARM)/bin - -HOST_CC := gcc - -CC := arm-none-eabi-gcc -AS := arm-none-eabi-as -LD := arm-none-eabi-ld -OC := arm-none-eabi-objcopy - -dir_source := src -dir_build := build -dir_out := out - -ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te -CFLAGS := -MMD -MP -Wall -Wextra -Werror -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\" -FLAGS := dir_out=$(abspath $(dir_out)) --no-print-directory -LDFLAGS := -nostdlib -Wl,-z,defs - -objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ - $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ - $(call rwildcard, $(dir_source), *.s *.c))) - -.PHONY: all -all: patchbin - -.PHONY: patchbin -patchbin: tool $(dir_out)/patch.bin - ./compile_header - -.PHONY: tool -tool: - $(HOST_CC) -o compile_header tool/compile_header.c - - -.PHONY: clean -clean: - rm -rf $(dir_out) $(dir_build) compile_header - -.PHONY: $(dir_out)/patch.bin -$(dir_out)/patch.bin: $(dir_build)/main.bin - @mkdir -p "$(dir_out)" - @cp -av $< $@ - -$(dir_build)/main.bin: $(dir_build)/main.elf - $(OC) -S -O binary $< $@ - -$(dir_build)/main.elf: $(objects_cfw) - $(CC) -T linker.ld $(OUTPUT_OPTION) $^ $(LDFLAGS) - -$(dir_build)/%.o: $(dir_source)/%.c - @mkdir -p "$(@D)" - $(COMPILE.c) $(OUTPUT_OPTION) $< - -$(dir_build)/%.o: $(dir_source)/%.s - @mkdir -p "$(@D)" - $(COMPILE.s) $(OUTPUT_OPTION) $< - -include $(call rwildcard, $(dir_build), *.d) diff --git a/patchbins/template/linker.ld b/patchbins/template/linker.ld deleted file mode 100644 index 7d6129b..0000000 --- a/patchbins/template/linker.ld +++ /dev/null @@ -1,59 +0,0 @@ -/* 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 -{ - . = 0x24400000; - - START_SECTION = .; - .text.start : { - *(.text.start) - } - START_SECTION_END = .; - - TABLE_SECTION = .; - .text.table : { - *(.text.table) - } - TABLE_SECTION_END = .; - - TEXT_SECTION = .; - .text : { - *(.text) - } - TEXT_SECTION_END = .; - - DATA_SECTION = .; - .data : { - *(.data) - } - DATA_SECTION_END = .; - - BSS_SECTION = .; - .bss : { - *(.bss COMMON) - } - BSS_SECTION_END = .; - - RODATA_SECTION = .; - .rodata : { - *(.rodata) - } - RODATA_SECTION_END = .; - - . = ALIGN(4); -} diff --git a/patchbins/template/meta/cfw_version b/patchbins/template/meta/cfw_version deleted file mode 100644 index 573541a..0000000 --- a/patchbins/template/meta/cfw_version +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/patchbins/template/meta/deps b/patchbins/template/meta/deps deleted file mode 100644 index b0047fa..0000000 --- a/patchbins/template/meta/deps +++ /dev/null @@ -1 +0,0 @@ -None diff --git a/patchbins/template/meta/desc b/patchbins/template/meta/desc deleted file mode 100644 index adf29f1..0000000 --- a/patchbins/template/meta/desc +++ /dev/null @@ -1 +0,0 @@ -Prints "Hello World!" diff --git a/patchbins/template/meta/name b/patchbins/template/meta/name deleted file mode 100644 index e3dac2c..0000000 --- a/patchbins/template/meta/name +++ /dev/null @@ -1 +0,0 @@ -Example Patch diff --git a/patchbins/template/meta/patch_version b/patchbins/template/meta/patch_version deleted file mode 100644 index d00491f..0000000 --- a/patchbins/template/meta/patch_version +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/patchbins/template/meta/title b/patchbins/template/meta/title deleted file mode 100644 index 8380236..0000000 --- a/patchbins/template/meta/title +++ /dev/null @@ -1 +0,0 @@ -Native diff --git a/patchbins/template/meta/uuid b/patchbins/template/meta/uuid deleted file mode 100644 index d00491f..0000000 --- a/patchbins/template/meta/uuid +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/patchbins/template/src/exported.h b/patchbins/template/src/exported.h deleted file mode 100644 index 9c102ae..0000000 --- a/patchbins/template/src/exported.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EXPORTED_H -#define EXPORTED_H - -#define stdout (void*)0 -#define stderr (void*)1 - -extern uint8_t* memory_offset; -extern uint32_t* memory_len; - -extern int strlen(const char *string); -extern int isprint(char c); -extern void memcpy(void *dest, const void *src, size_t size); -extern void memmove(void *dest, const void *src, size_t size); -extern void memset(void *dest, const int filler, size_t size); -extern int memcmp(const void *buf1, const void *buf2, const size_t size); -extern void strncpy(void *dest, const void *src, const size_t size); -extern int strncmp(const void *buf1, const void *buf2, const size_t size); -extern int atoi(const char *str); -extern uint8_t* memfind (uint8_t *string, uint32_t stringlen, uint8_t *pat, uint32_t patlen); - -extern void putc(void* buf, const int c); -extern void puts(void* buf, const char *string); -extern void fprintf(void* channel, const char* format, ...); - -#endif diff --git a/patchbins/template/src/link_table.s b/patchbins/template/src/link_table.s deleted file mode 100644 index 9bdd5be..0000000 --- a/patchbins/template/src/link_table.s +++ /dev/null @@ -1,53 +0,0 @@ -.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. - .byte 0 // Read; pc relative in arm mode is pc+8, so pc-4 is the correct offset - .byte 0 - .byte 0 - .byte 0 -.endm - -.macro ref name - .global \name - \name : - .byte 0 - .byte 0 - .byte 0 - .byte 0 -.endm - -.global MAGIC_START -MAGIC_START: - .byte 0xc0 - .byte 0x9b - .byte 0xe5 - .byte 0x1c - -// Memory to patch as specified by the header. (uint8_t*) -ref memory_offset - -// Size of memory offset. (uint32_t*) -ref memory_len - -// Exported functions. - -// 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 diff --git a/patchbins/template/src/start.s b/patchbins/template/src/start.s deleted file mode 100644 index 713b650..0000000 --- a/patchbins/template/src/start.s +++ /dev/null @@ -1,8 +0,0 @@ -.section .text.start -.align 4 -.global _start -_start: - stmdb sp!, {lr} - bl main - ldmia sp!, {lr} - bx lr // return from patch. diff --git a/patchbins/template/tool/compile_header.c b/patchbins/template/tool/compile_header.c deleted file mode 100644 index bf8b2ad..0000000 --- a/patchbins/template/tool/compile_header.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../../../source/patch_format.h" - -void read_file_u64(char* name, uint64_t* to) { - FILE* hdl = fopen(name, "rb"); - fscanf(hdl, "%llu", to); - fclose(hdl); -} - - -void read_file_u32(char* name, uint32_t* to) { - FILE* hdl = fopen(name, "rb"); - fscanf(hdl, "%u", to); - fclose(hdl); -} - -void read_str(char* name, char* to, size_t len) { - FILE* hdl = fopen(name, "rb"); - int r = fread(to, 1, len-1, hdl); - fclose(hdl); -} - -uint32_t size = 0; - -uint8_t* read_file_mem(char* name) { - FILE* hdl = fopen(name, "rb"); - - fseek(hdl, 0, SEEK_END); - size = ftell(hdl); - rewind(hdl); - - uint8_t* mem = malloc(size); - memset(mem, 0, size); - - int r = fread(mem, 1, size, hdl); - fclose(hdl); - - printf("%d\n", size); - - return mem; -} - -int main(int c, char** v) { - struct system_patch patch; - int at = 0; - - memset(&patch, 0, sizeof(patch)); - - // Set magic. - patch.magic[0] = 'A'; - patch.magic[1] = 'I'; - patch.magic[2] = 'D'; - patch.magic[3] = 'A'; - - read_file_u32("meta/patch_version", & patch.patch_ver); - read_file_u32("meta/cfw_version", & patch.load_ver); - - read_file_u64("meta/uuid", & patch.patch_id); - read_file_u64("meta/title", & patch.tid); - - read_str("meta/name", patch.name, sizeof(patch.name)); - read_str("meta/desc", patch.desc, sizeof(patch.desc)); - - uint8_t* code = read_file_mem("out/patch.bin"); - - patch.patch_size = size; - - FILE* out = fopen("out/patch.vco", "wb"); - fwrite(&patch, 1, sizeof(patch), out); - fwrite(code, 1, patch.patch_size, out); - fclose(out); - - free(code); - - printf("Ver: %u\n" - "CFW: %u\n" - "UUID: %llu\n" - "TID: %llu\n" - "Name: %s\n" - "Desc: %s\n" - "Size: %u\n", - patch.patch_ver, patch.load_ver, patch.patch_id, - patch.tid, patch.name, patch.desc, patch.patch_size); - - return 0; -} diff --git a/source/firm/firm.c b/source/firm/firm.c index 29187ec..1e66922 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -135,7 +135,7 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint int firmware_changed = 0; if (read_file(dest, path, *size)) { - fprintf(BOTTOM_SCREEN, "Failed to read FIRM from SD\n"); + fprintf(BOTTOM_SCREEN, " Failed to read FIRM.\n"); // Only whine about this if it's NATIVE_FIRM, which is important. if (firm_title == NATIVE_FIRM_TITLEID) { @@ -155,17 +155,18 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint if (firm_title == NATIVE_FIRM_TITLEID) { fprintf(BOTTOM_SCREEN, "Failed to decrypt firmware.\n" "This is fatal. Aborting.\n"); + status = 1; + goto exit_error; } - goto exit_error; } firmware_changed = 1; // Decryption performed. } else { - fprintf(BOTTOM_SCREEN, "FIRM not encrypted\n"); + fprintf(BOTTOM_SCREEN, " FIRM not encrypted\n"); } struct firm_signature* fsig = get_firm_info(dest); - fprintf(BOTTOM_SCREEN, "FIRM version: %s\n", fsig->version_string); + fprintf(BOTTOM_SCREEN, " FIRM version: %s\n", fsig->version_string); // The N3DS firm has an additional encryption layer for ARM9 if (fsig->console == console_n3ds) { @@ -192,7 +193,7 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint } firmware_changed = 1; // Decryption of arm9bin performed. } else { - fprintf(BOTTOM_SCREEN, "ARM9 FIRM binary not encrypted\n"); + fprintf(BOTTOM_SCREEN, " ARM9 FIRM binary not encrypted\n"); if (firm_title == NATIVE_FIRM_TITLEID && fsig->version > 0x0F) { slot0x11key96_init(); // This has to be loaded regardless, otherwise boot will fail. } @@ -206,13 +207,12 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint // Save firmware.bin if decryption was done. if (firmware_changed) { - fprintf(BOTTOM_SCREEN, "Saving decrypted FIRM\n"); + fprintf(BOTTOM_SCREEN, " Saving decrypted FIRM\n"); write_file(dest, path, *size); } - if (fsig->console == console_n3ds) - { - fprintf(BOTTOM_SCREEN, "Fixing arm9 entrypoint\n"); + if (fsig->console == console_n3ds) { + fprintf(BOTTOM_SCREEN, " Fixing arm9 entrypoint\n"); // Patch the entrypoint to skip arm9loader if (firm_title == NATIVE_FIRM_TITLEID) { @@ -261,6 +261,9 @@ void boot_firm() { fprintf(BOTTOM_SCREEN, "Updated keyX keyslots\n"); } + fumount(); // Unmount SD. No longer needed. + fprintf(BOTTOM_SCREEN, "SD Unmounted.\n"); + for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4 && section->address != 0; section++) { memcpy((void *)section->address, (void *)firm_loc + section->offset, section->size); @@ -293,7 +296,7 @@ int find_proc9(firm_h* firm, firm_section_h* process9, exefs_h** p9exefs) { process9->address = p9exheader->sci.textCodeSet.address; process9->size = (*p9exefs)->fileHeaders[0].size; process9->offset = (void*)((*p9exefs) + 1) - (void*)firm; - fprintf(BOTTOM_SCREEN, "Found Process9 for FIRM.\n"); + fprintf(BOTTOM_SCREEN, " Found Process9 for FIRM.\n"); return 0; } } @@ -301,12 +304,12 @@ int find_proc9(firm_h* firm, firm_section_h* process9, exefs_h** p9exefs) { } } } - fprintf(BOTTOM_SCREEN, "Couldn't find Process9 for FIRM?\n"); + fprintf(BOTTOM_SCREEN, " Couldn't find Process9?\n"); return 1; } int load_firms() { - fprintf(TOP_SCREEN, "[Loading FIRM]"); + fprintf(TOP_SCREEN, "[Loading FIRM]\n"); fprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n"); if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, NATIVE_FIRM_TITLEID) != 0) @@ -315,13 +318,13 @@ int load_firms() { fprintf(BOTTOM_SCREEN, "Loading TWL_FIRM\n"); if(load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, &twl_firm_size, TWL_FIRM_TITLEID)) - fprintf(BOTTOM_SCREEN, "TWL_FIRM failed to load.\n"); + fprintf(BOTTOM_SCREEN, " TWL_FIRM failed to load.\n"); else find_proc9(twl_firm_loc, &twl_firm_proc9, &twl_firm_p9_exefs); fprintf(BOTTOM_SCREEN, "Loading AGB_FIRM\n"); if(load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, &agb_firm_size, AGB_FIRM_TITLEID)) - fprintf(BOTTOM_SCREEN, "AGB_FIRM failed to load.\n"); + fprintf(BOTTOM_SCREEN, " AGB_FIRM failed to load.\n"); else find_proc9(agb_firm_loc, &agb_firm_proc9, &agb_firm_p9_exefs); @@ -329,7 +332,7 @@ int load_firms() { } void boot_cfw() { - fprintf(TOP_SCREEN, "[Patching]"); + fprintf(TOP_SCREEN, "Applying patches...\n"); if (patch_firm_all() != 0) return; diff --git a/source/linker.c b/source/linker.c index b727142..4ec769e 100644 --- a/source/linker.c +++ b/source/linker.c @@ -1,57 +1,122 @@ #include "common.h" #include "firm/fcram.h" +#include "firm/firm.h" -int link_and_load_patchbin(char* path) { - fprintf(stderr, "Prep to relocate and execute patch.\n"); +extern void flush_cache(); - struct system_patch patch; +extern firm_h *firm_loc; +extern exefs_h *firm_p9_exefs; + +extern firm_h *twl_firm_loc; +extern exefs_h *twl_firm_p9_exefs; + +extern firm_h *agb_firm_loc; +extern exefs_h *agb_firm_p9_exefs; + +firm_h* __attribute__((optimize("O0"))) get_firm() { + return firm_loc; +} + +exefs_h* __attribute__((optimize("O0"))) get_firm_proc9_exefs() { + return firm_p9_exefs; +} - fprintf(stderr, "Loading patch vco.\n"); +firm_h* __attribute__((optimize("O0"))) get_agb() { + return agb_firm_loc; +} + +exefs_h* __attribute__((optimize("O0"))) 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--) + if (path[basename] == '/') + break; + basename++; + + fprintf(stderr, "Executing patchbin: %s\n", &path[basename]); + + struct system_patch patch; // Load patch from path. FILE* f = fopen(path, "r"); fread(&patch, 1, sizeof(patch), f); - fprintf(stderr, "Patch payload is %d bytes.\n", patch.patch_size); + fprintf(stderr, " [h]"); fread((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, 1, patch.patch_size, f); + fprintf(stderr, "[x]"); + fclose(f); - fprintf(stderr, "Finding relocation table.\n"); + fprintf(stderr, "[s]"); // Now then...find the magical number. uint8_t magic[] = { 0xc0, 0x9b, 0xe5, 0x1c }; - uint8_t* off = memfind((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, patch.patch_size, magic, 4); + uint32_t* link_table = (uint32_t*)memfind((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, patch.patch_size, magic, 4); - if (off == NULL) { - fprintf(stderr, "Relocation table missing. Abort.\n"); + if (link_table == NULL) { + fprintf(stderr, "\n Table missing. Abort.\n"); return 1; } - fprintf(stderr, "Relocation table is at %x\n", (uint32_t)off); + fprintf(stderr, "[r]"); - uint32_t* link_table = (uint32_t*)(off + 4); + // 0 - magic // memory.c - link_table[3] = (uint32_t)strlen; - link_table[5] = (uint32_t)isprint; - link_table[7] = (uint32_t)memcpy; - link_table[9] = (uint32_t)memmove; - link_table[11] = (uint32_t)memset; - link_table[13] = (uint32_t)memcmp; - link_table[15] = (uint32_t)strncpy; - link_table[17] = (uint32_t)strncmp; - link_table[19] = (uint32_t)atoi; - link_table[21] = (uint32_t)memfind; + link_table[2] = (uint32_t)strlen; + link_table[4] = (uint32_t)isprint; + link_table[6] = (uint32_t)memcpy; + link_table[8] = (uint32_t)memmove; + link_table[10] = (uint32_t)memset; + link_table[12] = (uint32_t)memcmp; + link_table[14] = (uint32_t)strncpy; + link_table[16] = (uint32_t)strncmp; + link_table[18] = (uint32_t)atoi; + link_table[20] = (uint32_t)memfind; // draw.c - link_table[23] = (uint32_t)putc; - link_table[25] = (uint32_t)puts; - link_table[27] = (uint32_t)fprintf; + link_table[22] = (uint32_t)putc; + link_table[24] = (uint32_t)puts; + 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[32] = (uint32_t)get_agb; + link_table[34] = (uint32_t)get_agb_proc9_exefs; + + link_table[36] = (uint32_t)get_twl; + link_table[38] = (uint32_t)get_twl_proc9_exefs; + + fprintf(stderr, "[b]\n"); + + int (*patch_loc)() = (void*)FCRAM_PATCHBIN_EXEC_LOC ; - fprintf(stderr, "Copied relocations. Running binary.\n"); + int ret = (*patch_loc)(); - int (*exec)() = (void*)FCRAM_PATCHBIN_EXEC_LOC ; + fprintf(stderr, " Exit: %d\n", ret); - return (*exec)(); + return ret; } diff --git a/source/patch_format.h b/source/patch_format.h index 64f3a2a..301f4e8 100644 --- a/source/patch_format.h +++ b/source/patch_format.h @@ -22,8 +22,8 @@ #define PATH_LOCEMU PATH_CFW "/locale.conf" // Locale emulation config #define PATH_CPU_CFG PATH_CFW "/cpu.conf" // CPU settings config -#define PATH_FIRMWARES PATH_CFW "/firmware" // Firmware folder. -#define PATH_PATCHES PATH_CFW "/patches" // Patches folder. +#define PATH_FIRMWARES PATH_CFW "/firm" // Firmware folder. +#define PATH_PATCHES PATH_CFW "/bin" // Patch binary folder. #define PATH_TEMP PATH_CFW "/temp" // Files that are transient (user can delete them and they will be regenerated) #define PATH_KEYS PATH_CFW "/keys" // Keyfiles will be loaded from this dir, and additionally the root if not found. #define PATH_EXEFS PATH_CFW "/exefs" // ExeFS overrides, named like '.exefs' @@ -41,7 +41,7 @@ #define PATH_AGB_CETK PATH_KEYS "/agb.cetk" #define PATH_AGB_FIRMKEY PATH_KEYS "/agb.key" -#define PATH_SLOT0X11KEY96 PATH_KEYS "/0x11.key" +#define PATH_SLOT0X11KEY96 PATH_KEYS "/11.key" #define PATH_ALT_SLOT0X11KEY96 "/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up paths. diff --git a/source/patcher.c b/source/patcher.c index 6bd196d..7e38394 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -5,27 +5,13 @@ #include "config.h" #include "common.h" +// TODO - Basically all this needs to move to patcher programs. + uint32_t wait_key(); -int link_and_load_patchbin(char* path); +int execp(char* path); // A portion of this file is inherited from Luma3DS. -/* -u16 *getFirmWrite(u8 *pos, u32 size) { - //Look for FIRM writing code - u8 *const off = memsearch(pos, "exe:", size, 4); - const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; - - return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4); -} - -u16 *getFirmWriteSafe(u8 *pos, u32 size) { - //Look for FIRM writing code - const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; - - return (u16 *)memsearch(pos, pattern, size, 4); -} - -u32 getLoader(u8 *pos, u32 *loaderSize) { +/*u32 getLoader(u8 *pos, u32 *loaderSize) { u8 *off = pos; u32 size; @@ -40,32 +26,22 @@ u32 getLoader(u8 *pos, u32 *loaderSize) { return (u32)(off - pos); } - - -// patch_location = (void *)((uintptr_t)firm + section->offset + (version->offset - section->address)); - -u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) -{ - u8 *off = memsearch(pos, "ess9", size, 4); - - *process9Size = *(u32 *)(off - 0x60) * 0x200; - *process9MemAddr = *(u32 *)(off + 0xC); - - //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) - return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200; -} */ -int patch_signatures() { +/* int patch_signatures() { //Look for signature checks uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7}; uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C}; + // The code segment. 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; uint8_t *off = memfind(firm_mem, size, pat1, 4); + + // We're subbing one because the code goes back 1. + // Unique patterns, etc. uint8_t *off2 = memfind(firm_mem, size, pat2, 4) - 1; if (off == NULL) { @@ -81,20 +57,22 @@ int patch_signatures() { fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off); fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2); + // See asm/sigpatches.s for the code here uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47}; memcpy(off, sigpatch, 2); memcpy(off2, sigpatch, 4); + fprintf(stderr, "Signature patch succeded.\n"); return 0; -} +} */ 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; - //Look for FIRM writing code + // We look for 'exe:' first; this string is close to what we patch uint8_t* off = memfind(firm_mem, size, (uint8_t*)"exe:", 4); if(off == NULL) { @@ -125,25 +103,28 @@ int patch_firmprot() { void wait() { if (config.options[OPTION_TRACE]) { - fprintf(stderr, "Pausing because trace is on.\n"); + fprintf(stderr, "[press key]\n"); wait_key(); } } int patch_firm_all() { - link_and_load_patchbin(PATH_PATCHES "/patch.vco"); + // FIXME - Linker is bork at the moment. + execp(PATH_PATCHES "/example.vco"); wait(); // 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]) { - if(patch_signatures()) { + // TODO - Patch menu. This is okay-ish for now. + if(execp(PATH_PATCHES "/signatures.vco")) { abort("Fatal. Sigpatch has failed."); } } diff --git a/source/start.s b/source/start.s index 23253e7..0877155 100644 --- a/source/start.s +++ b/source/start.s @@ -2,15 +2,15 @@ .align 4 .global _start _start: - @ Change the stack pointer + // Change the stack pointer mov sp, #0x27000000 - @ Give read/write access to all the memory regions + // Give read/write access to all the memory regions ldr r5, =0x33333333 mcr p15, 0, r5, c5, c0, 2 @ write data access mcr p15, 0, r5, c5, c0, 3 @ write instruction access - @ Sets MPU permissions and cache settings + // Sets MPU permissions and cache settings ldr r0, =0xFFFF001D @ ffff0000 32k ldr r1, =0x01FF801D @ 01ff8000 32k ldr r2, =0x08000027 @ 08000000 1M @@ -30,24 +30,11 @@ _start: mcr p15, 0, r5, c6, c5, 0 mcr p15, 0, r6, c6, c6, 0 mcr p15, 0, r7, c6, c7, 0 - mcr p15, 0, r10, c3, c0, 0 @ Write bufferable 0, 2, 5 - mcr p15, 0, r11, c2, c0, 0 @ Data cacheable 0, 2, 5 - mcr p15, 0, r12, c2, c0, 1 @ Inst cacheable 0, 2, 5 - @ Enable caches - mrc p15, 0, r4, c1, c0, 0 @ read control register - orr r4, r4, #(1<<12) @ - instruction cache enable - orr r4, r4, #(1<<2) @ - data cache enable - orr r4, r4, #(1<<0) @ - mpu enable - mcr p15, 0, r4, c1, c0, 0 @ write control register + // Yes, you're reading correctly. We are NOT enabling instruction caching. + // It causes issues with the linker, which is why it is left off. - @ Flush caches - mov r5, #0 - mcr p15, 0, r5, c7, c5, 0 @ flush I-cache - mcr p15, 0, r5, c7, c6, 0 @ flush D-cache - mcr p15, 0, r5, c7, c10, 4 @ drain write buffer - - @ Fixes mounting of SDMC + // Fixes mounting of SDMC ldr r0, =0x10000020 mov r1, #0x340 str r1, [r0] diff --git a/source/std/draw.c b/source/std/draw.c index a87b767..312878e 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -12,11 +12,11 @@ static unsigned int top_cursor_x = 0, top_cursor_y = 0; static unsigned int bottom_cursor_x = 0, bottom_cursor_y = 0; -static char text_buffer_top [TEXT_TOP_SIZE]; -static char text_buffer_bottom [TEXT_BOTTOM_SIZE]; +static char text_buffer_top [TEXT_TOP_HEIGHT*TEXT_TOP_WIDTH+1]; +static char text_buffer_bottom [TEXT_BOTTOM_HEIGHT*TEXT_BOTTOM_WIDTH+1]; -static char color_buffer_top [TEXT_TOP_SIZE]; -static char color_buffer_bottom [TEXT_BOTTOM_SIZE]; +static char color_buffer_top [TEXT_TOP_HEIGHT*TEXT_TOP_WIDTH+1]; +static char color_buffer_bottom [TEXT_BOTTOM_HEIGHT*TEXT_BOTTOM_WIDTH+1]; static uint32_t colors[16] = { 0x000000, // Black @@ -37,11 +37,21 @@ static uint32_t colors[16] = { 0xffffff // White }; -void clear_screen(uint8_t* screen) { - uint32_t size = 0; - char* buffer = 0; - uint32_t buffer_size = 0; +void clear_disp(uint8_t* screen) { + if (screen == TOP_SCREEN) + screen = framebuffers->top_left; + else if (screen == BOTTOM_SCREEN) + screen = framebuffers->bottom; + + if(screen == framebuffers->top_left || + screen == framebuffers->top_right) { + memset(screen, 0, SCREEN_TOP_SIZE); + } else if(screen == framebuffers->bottom) { + memset(screen, 0, SCREEN_BOTTOM_SIZE); + } +} +void clear_text(uint8_t* screen) { if (screen == TOP_SCREEN) screen = framebuffers->top_left; else if (screen == BOTTOM_SCREEN) @@ -49,23 +59,21 @@ void clear_screen(uint8_t* screen) { if(screen == framebuffers->top_left || screen == framebuffers->top_right) { - size = SCREEN_TOP_SIZE; - buffer = text_buffer_top; - buffer_size = TEXT_TOP_SIZE; - top_cursor_x = 0; - top_cursor_y = 0; + for(int i=0; i < TEXT_TOP_HEIGHT; i++) { + text_buffer_top[i*TEXT_TOP_WIDTH] = 0; + color_buffer_top[i*TEXT_TOP_WIDTH] = 0; + } } else if(screen == framebuffers->bottom) { - size = SCREEN_BOTTOM_SIZE; - buffer = text_buffer_bottom; - buffer_size = TEXT_BOTTOM_SIZE; - bottom_cursor_x = 0; - bottom_cursor_y = 0; - } else { - return; // Invalid buffer. + for(int i=0; i < TEXT_BOTTOM_HEIGHT; i++) { + text_buffer_bottom[i*TEXT_BOTTOM_WIDTH] = 0; + color_buffer_bottom[i*TEXT_BOTTOM_WIDTH] = 0; + } } +} - memset(screen, 0, size); - memset(buffer, 0, buffer_size); +void clear_screen(uint8_t* screen) { + clear_disp(screen); + clear_text(screen); } void set_cursor(void* channel, unsigned int x, unsigned int y) { @@ -129,75 +137,73 @@ void putc(void* buf, const int c) { if (buf == stdout || buf == stderr) { unsigned int width = 0; _UNUSED unsigned int height = 0; - unsigned int size = 0; - unsigned int cursor_x; - unsigned int cursor_y; - char* colorbuf; - char* strbuf; + unsigned int *cursor_x; + unsigned int *cursor_y; + char *colorbuf; + char *strbuf; unsigned char* color = NULL; if (buf == TOP_SCREEN) { width = TEXT_TOP_WIDTH; height = TEXT_TOP_HEIGHT; - size = TEXT_TOP_SIZE; colorbuf = color_buffer_top; strbuf = text_buffer_top; - cursor_x = top_cursor_x; - cursor_y = top_cursor_y; + cursor_x = &top_cursor_x; + cursor_y = &top_cursor_y; color = &color_top; } else if (buf == BOTTOM_SCREEN) { width = TEXT_BOTTOM_WIDTH; height = TEXT_BOTTOM_HEIGHT; - size = TEXT_BOTTOM_SIZE; colorbuf = color_buffer_bottom; strbuf = text_buffer_bottom; - cursor_x = bottom_cursor_x; - cursor_y = bottom_cursor_y; + cursor_x = &bottom_cursor_x; + cursor_y = &bottom_cursor_y; color = &color_bottom; } - unsigned int offset = width * cursor_y + cursor_x; + if (cursor_x[0] >= width) { + cursor_x[0] = 0; + cursor_y[0]++; + } - if (offset >= size) { - // Scroll a line back. This involves memcpy. - // Yes, memcpy overwrites part of the buffer it is reading. - memcpy(strbuf, strbuf+width, size-width); - memcpy(colorbuf, colorbuf+width, size-width); - cursor_y -= 1; - offset = width * cursor_y + cursor_x; - } + while (cursor_y[0] >= height) { + // Scroll. + for(unsigned int y=0; y < height-1; y++) { + memset(&strbuf[y*width], 0, width); + memset(&colorbuf[y*width], 0, width); + strncpy(&strbuf[y*width], &strbuf[(y+1)*width], width); + strncpy(&colorbuf[y*width], &colorbuf[(y+1)*width], width); + } + memset(&strbuf[(height-1)*width], 0, width); + memset(&colorbuf[(height-1)*width], 0, width); - if (offset >= size) { - // So if we're being real, this won't ever happen. - return; - } + cursor_y[0]--; + + clear_disp(buf); // Clear screen. + } switch(c) { case '\n': - cursor_y++; // Increment line. - cursor_x = 0; - break; + strbuf[cursor_y[0]*width+cursor_x[0]] = 0; + colorbuf[cursor_y[0]*width+cursor_x[0]] = 0; + cursor_y[0]++; + // Fall through intentional. case '\r': - cursor_x = 0; // Reset to beginning of line. + cursor_x[0] = 0; // Reset to beginning of line. break; default: - strbuf[offset] = c; - colorbuf[offset] = *color; // White on black. - cursor_x++; - if (cursor_x >= width) { - cursor_y++; - cursor_x = 0; - } - break; - } + strbuf[cursor_y[0]*width+cursor_x[0]] = c; + colorbuf[cursor_y[0]*width+cursor_x[0]] = *color; + + if (cursor_x[0] + 1 < width) { + strbuf[cursor_y[0]*width+cursor_x[0]+1] = 0; // Terminate. + colorbuf[cursor_y[0]*width+cursor_x[0]+1] = 0; + } + + cursor_x[0]++; - if (buf == TOP_SCREEN) { - top_cursor_x = cursor_x; - top_cursor_y = cursor_y; - } else if (buf == BOTTOM_SCREEN) { - bottom_cursor_x = cursor_x; - bottom_cursor_y = cursor_y; + break; } } else { // FILE*, not stdin or stdout. @@ -284,18 +290,22 @@ void put_int(void* channel, int n, int length) { void fflush(void* channel) { if (channel == TOP_SCREEN) { - for(int x=0; x < TEXT_TOP_WIDTH; x++) { - for(int y=0; y < TEXT_TOP_HEIGHT; y++) { + for(int y=0; y < TEXT_TOP_HEIGHT; y++) { + for(int x=0; x < TEXT_TOP_WIDTH; x++) { char c = text_buffer_top[y*TEXT_TOP_WIDTH+x]; + if (c == 0) + break; uint32_t color_fg = colors[((color_buffer_top[y*TEXT_TOP_WIDTH+x] >> 4) & 0x0f)]; uint32_t color_bg = colors[(color_buffer_top[y*TEXT_TOP_WIDTH+x] & 0x0f)]; draw_character(framebuffers->top_left, c, x, y, color_fg, color_bg); } } } else if (channel == BOTTOM_SCREEN) { - for(int x=0; x < TEXT_BOTTOM_WIDTH; x++) { - for(int y=0; y < TEXT_BOTTOM_HEIGHT; y++) { + for(int y=0; y < TEXT_BOTTOM_HEIGHT; y++) { + for(int x=0; x < TEXT_BOTTOM_WIDTH; x++) { char c = text_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x]; + if (c == 0) + break; uint32_t color_fg = colors[((color_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x] >> 4) & 0x0f)]; uint32_t color_bg = colors[(color_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x] & 0x0f)]; draw_character(framebuffers->bottom, c, x, y, color_fg, color_bg); diff --git a/vco/Makefile b/vco/Makefile new file mode 100644 index 0000000..a9afaaa --- /dev/null +++ b/vco/Makefile @@ -0,0 +1,25 @@ +.PHONY: all copyout +all: template signatures + mkdir -p ../out/corbenik/bin + cp template/out/patch.vco ../out/corbenik/bin/example.vco + cp signatures/out/patch.vco ../out/corbenik/bin/signatures.vco + +.PHONY: clean +clean: clean_template clean_signatures + rm -rf ../out/corbenik/bin + +.PHONY: template +template: + make -C template + +.PHONY: signatures +signatures: + make -C signatures + +.PHONY: clean_template +clean_template: + make -C template clean + +.PHONY: clean_signatures +clean_signatures: + make -C signatures clean diff --git a/vco/README.txt b/vco/README.txt new file mode 100644 index 0000000..8ca7465 --- /dev/null +++ b/vco/README.txt @@ -0,0 +1,44 @@ +Corbenik patch binaries +---------------------------------- + +This directory contains the source for vco files - the patcher executables. + +You're probably wondering what the heck corbenik does differently from cakes, +considering it seems similar in many ways. + +Patches are actually code for whatever processor they're intended to run on, +be it ARM9 or ARM11. They're loaded to a static offset in memory, and executed +from there with relocations to corbenik's internal functions. This keeps patches +relatively small, and allows complete control over behavior. + +Patches should have a declaration of this sort somewhere in them: + { 0xc0, 0x9b, 0xe5, 0x1c } +Followed by a table large enough to fill with all usable functions. + +The loader is subject to change at any moment's notice; the ABI is not yet +stable. It may become an ELF loader at some point. I don't know. + +You may want to consult src/loader.c to see what functions are exported, or +simply base your code on the generic example in the 'template' folder instead. + +There's some key differences here, obviously, from running just arm9loader code. Namely: + + 1) Patches must not clobber the previous state. Meaning; start does nothing but + chain to main. + + 2) Patches must properly return, and also return a value. Return code 0 is + success; keep this in mind. Corbenik will attempt to reset after a non- + zero return code. If you don't know how to return; you're looking for + 'bx lr'. + + 3) Patches must have a symbol table with the appropriate magic. + No symbol table? No load. This might be relaxed in future versions + to allow patches to be marked static, but IDK. + + 4) Don't code a patch that does too fancy stuff. Patches are not intended to + be 65k binaries. Seriously. + + 5) _start must be at offset 0x24400000. This is where you are in memory. + +You can implement shit yourself, but it's an utter waste of memory. Try to use +the linker exports unless you have a good reason not to. diff --git a/vco/signatures/Makefile b/vco/signatures/Makefile new file mode 120000 index 0000000..25eaf27 --- /dev/null +++ b/vco/signatures/Makefile @@ -0,0 +1 @@ +../template/Makefile \ No newline at end of file diff --git a/vco/signatures/linker.ld b/vco/signatures/linker.ld new file mode 120000 index 0000000..6577326 --- /dev/null +++ b/vco/signatures/linker.ld @@ -0,0 +1 @@ +../template/linker.ld \ No newline at end of file diff --git a/patchbins/firmprot/meta/cfw_version b/vco/signatures/meta/cfw_version similarity index 100% rename from patchbins/firmprot/meta/cfw_version rename to vco/signatures/meta/cfw_version diff --git a/patchbins/firmprot/meta/deps b/vco/signatures/meta/deps similarity index 100% rename from patchbins/firmprot/meta/deps rename to vco/signatures/meta/deps diff --git a/patchbins/signatures/meta/desc b/vco/signatures/meta/desc similarity index 100% rename from patchbins/signatures/meta/desc rename to vco/signatures/meta/desc diff --git a/patchbins/signatures/meta/name b/vco/signatures/meta/name similarity index 100% rename from patchbins/signatures/meta/name rename to vco/signatures/meta/name diff --git a/patchbins/firmprot/meta/patch_version b/vco/signatures/meta/patch_version similarity index 100% rename from patchbins/firmprot/meta/patch_version rename to vco/signatures/meta/patch_version diff --git a/patchbins/firmprot/meta/title b/vco/signatures/meta/title similarity index 100% rename from patchbins/firmprot/meta/title rename to vco/signatures/meta/title diff --git a/patchbins/firmprot/meta/uuid b/vco/signatures/meta/uuid similarity index 100% rename from patchbins/firmprot/meta/uuid rename to vco/signatures/meta/uuid diff --git a/vco/signatures/src/exported.h b/vco/signatures/src/exported.h new file mode 120000 index 0000000..0cbf2cf --- /dev/null +++ b/vco/signatures/src/exported.h @@ -0,0 +1 @@ +../../template/src/exported.h \ No newline at end of file diff --git a/vco/signatures/src/headers.h b/vco/signatures/src/headers.h new file mode 120000 index 0000000..0be6138 --- /dev/null +++ b/vco/signatures/src/headers.h @@ -0,0 +1 @@ +../../template/src/headers.h \ No newline at end of file diff --git a/vco/signatures/src/link_table.s b/vco/signatures/src/link_table.s new file mode 120000 index 0000000..501d0b2 --- /dev/null +++ b/vco/signatures/src/link_table.s @@ -0,0 +1 @@ +../../template/src/link_table.s \ No newline at end of file diff --git a/vco/signatures/src/main.c b/vco/signatures/src/main.c new file mode 100644 index 0000000..e343842 --- /dev/null +++ b/vco/signatures/src/main.c @@ -0,0 +1,54 @@ +#include +#include +#include "exported.h" + +uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7}; +uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C}; + +// See asm/sigpatches.s for the code here +uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47}; + +uint8_t *firm_mem, *off, *off2; +uint32_t size = 0; +exefs_h* firm_p9_exefs; + +int main() { + //Look for signature checks + fprintf(stderr, "Applying signature patch\n"); + + firm_p9_exefs = get_firm_proc9_exefs(); + + fprintf(stderr, "ExeFS: 0x%x\n", firm_p9_exefs); + + // The code segment. + firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; + size = firm_p9_exefs->fileHeaders[0].size; + + fprintf(stderr, "Search, P0.\n"); + off = memfind(firm_mem, size, pat1, 4); + + if (off == NULL) { + fprintf(stderr, "Failed, P0.\n"); + return 1; // Failed to find sigpatch. Ugh. + } + + // We're subbing one because the code goes back 1. + // Unique patterns, etc. + fprintf(stderr, "Search, P1.\n"); + off2 = memfind(firm_mem, size, pat2, 4) - 1; + + if (off2 == NULL) { + fprintf(stderr, "Failed, P1.\n"); + return 2; // Failed to find sigpatch. Ugh. + } + + fprintf(stderr, "Signatures, P0, 0x%x\n", (uint32_t)off); + memcpy(off, sigpatch, 2); + + fprintf(stderr, "Signatures, P1, 0x%x\n", (uint32_t)off2); + memcpy(off2, sigpatch, 4); + + fprintf(stderr, "Succeded.\n"); + + return 0; +} diff --git a/vco/signatures/src/start.s b/vco/signatures/src/start.s new file mode 120000 index 0000000..e408660 --- /dev/null +++ b/vco/signatures/src/start.s @@ -0,0 +1 @@ +../../template/src/start.s \ No newline at end of file diff --git a/vco/signatures/tool b/vco/signatures/tool new file mode 120000 index 0000000..37fac4b --- /dev/null +++ b/vco/signatures/tool @@ -0,0 +1 @@ +../template/tool/ \ No newline at end of file diff --git a/patchbins/firmprot/Makefile b/vco/template/Makefile similarity index 97% rename from patchbins/firmprot/Makefile rename to vco/template/Makefile index e2f940b..8a9bca2 100644 --- a/patchbins/firmprot/Makefile +++ b/vco/template/Makefile @@ -14,7 +14,7 @@ dir_build := build dir_out := out ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te -CFLAGS := -MMD -MP -Wall -Wextra -Werror -O0 $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\" +CFLAGS := -MMD -MP -Wall -Wextra -Werror -O0 $(ASFLAGS) -fno-builtin -std=c11 -marm FLAGS := dir_out=$(abspath $(dir_out)) --no-print-directory LDFLAGS := -nostdlib -Wl,-z,defs -lgcc diff --git a/patchbins/firmprot/linker.ld b/vco/template/linker.ld similarity index 100% rename from patchbins/firmprot/linker.ld rename to vco/template/linker.ld diff --git a/patchbins/signatures/meta/cfw_version b/vco/template/meta/cfw_version similarity index 100% rename from patchbins/signatures/meta/cfw_version rename to vco/template/meta/cfw_version diff --git a/patchbins/signatures/meta/deps b/vco/template/meta/deps similarity index 100% rename from patchbins/signatures/meta/deps rename to vco/template/meta/deps diff --git a/patchbins/firmprot/meta/desc b/vco/template/meta/desc similarity index 100% rename from patchbins/firmprot/meta/desc rename to vco/template/meta/desc diff --git a/patchbins/firmprot/meta/name b/vco/template/meta/name similarity index 100% rename from patchbins/firmprot/meta/name rename to vco/template/meta/name diff --git a/patchbins/signatures/meta/patch_version b/vco/template/meta/patch_version similarity index 100% rename from patchbins/signatures/meta/patch_version rename to vco/template/meta/patch_version diff --git a/patchbins/signatures/meta/title b/vco/template/meta/title similarity index 100% rename from patchbins/signatures/meta/title rename to vco/template/meta/title diff --git a/patchbins/signatures/meta/uuid b/vco/template/meta/uuid similarity index 100% rename from patchbins/signatures/meta/uuid rename to vco/template/meta/uuid diff --git a/patchbins/signatures/src/exported.h b/vco/template/src/exported.h similarity index 74% rename from patchbins/signatures/src/exported.h rename to vco/template/src/exported.h index 9c102ae..495cf31 100644 --- a/patchbins/signatures/src/exported.h +++ b/vco/template/src/exported.h @@ -1,11 +1,10 @@ #ifndef EXPORTED_H #define EXPORTED_H -#define stdout (void*)0 -#define stderr (void*)1 +#include "headers.h" -extern uint8_t* memory_offset; -extern uint32_t* memory_len; +#define stdout ((void*)0) +#define stderr ((void*)2) extern int strlen(const char *string); extern int isprint(char c); @@ -22,4 +21,13 @@ extern void putc(void* buf, const int c); extern void puts(void* buf, const char *string); extern void fprintf(void* channel, const char* format, ...); +extern firm_h* get_firm(); +extern exefs_h* get_firm_proc9_exefs(); + +extern firm_h* get_agb(); +extern exefs_h* get_agb_proc9_exefs(); + +extern firm_h* get_twl(); +extern exefs_h* get_twl_proc9_exefs(); + #endif diff --git a/vco/template/src/headers.h b/vco/template/src/headers.h new file mode 120000 index 0000000..0214d8a --- /dev/null +++ b/vco/template/src/headers.h @@ -0,0 +1 @@ +../../../source/firm/headers.h \ No newline at end of file diff --git a/vco/template/src/link_table.s b/vco/template/src/link_table.s new file mode 100644 index 0000000..0c459b5 --- /dev/null +++ b/vco/template/src/link_table.s @@ -0,0 +1,69 @@ +.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 diff --git a/patchbins/template/src/main.c b/vco/template/src/main.c similarity index 100% rename from patchbins/template/src/main.c rename to vco/template/src/main.c diff --git a/vco/template/src/start.s b/vco/template/src/start.s new file mode 100644 index 0000000..441e530 --- /dev/null +++ b/vco/template/src/start.s @@ -0,0 +1,7 @@ +.section .text.start +.align 4 +.global _start +_start: + b main +_die: + b _die // I have no clue how one would end up here. diff --git a/patchbins/signatures/tool/compile_header.c b/vco/template/tool/compile_header.c similarity index 95% rename from patchbins/signatures/tool/compile_header.c rename to vco/template/tool/compile_header.c index bf8b2ad..049ff7d 100644 --- a/patchbins/signatures/tool/compile_header.c +++ b/vco/template/tool/compile_header.c @@ -23,6 +23,13 @@ void read_str(char* name, char* to, size_t len) { FILE* hdl = fopen(name, "rb"); int r = fread(to, 1, len-1, hdl); fclose(hdl); + + for(int i=len-1; i >= 0; i--) { + if (to[i] == '\n') { + to[i] = 0; + break; + } + } } uint32_t size = 0; @@ -40,8 +47,6 @@ uint8_t* read_file_mem(char* name) { int r = fread(mem, 1, size, hdl); fclose(hdl); - printf("%d\n", size); - return mem; } -- 2.39.5