Skip to content

Instantly share code, notes, and snippets.

@patois
Created April 12, 2015 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patois/2dc6bf727a07b8bcdcd7 to your computer and use it in GitHub Desktop.
Save patois/2dc6bf727a07b8bcdcd7 to your computer and use it in GitHub Desktop.
#pragma once
#include "firm.h"
int get_section_by_address (void *address) {
int i;
struct firm_section_header volatile *sh;
for (i=0; i < FIRM_MAX_SECTION_COUNT; i++) {
sh = &firm->section_headers[i];
if ((sh->address <= address) && (address < (sh->address + sh->size))) {
return i;
}
}
return -1;
}
/* this could/should be added a few more checks */
int is_valid_firm (void) {
return (firm->magic == FIRM_MAGIC);
}
void dump_section_header (int index) {
struct firm_section_header volatile *sh;
sh = &firm->section_headers[index];
Debug("Section %02d/%02d (ARM%s):", index, FIRM_MAX_SECTION_COUNT, sh->type ? "11" : "9");
Debug("%08X - %08X", sh->address, sh->address + sh->size);
Debug("");
return;
}
#pragma once
#include "common.h"
int get_section_by_address (void *address);
int is_valid_firm (void);
void dump_section_header (int index);
#define PA_FIRM_IMAGE 0x24000000
#define FIRM_MAGIC 0x4D524946
#define FIRM_MAX_SECTION_COUNT 0x4
typedef struct firm_section_header {
u32 offset;
void *address;
u32 size;
u32 type;
u8 hash[0x20];
} _firm_section_header;
typedef struct firm_header {
u32 magic;
u32 reserved1;
void *arm11_ep;
void *arm9_ep;
u8 reserved2[0x30];
struct firm_section_header section_headers[4];
u8 rsa_sig[0x100];
} _firm_header;
static struct firm_header volatile *const firm = (struct firm_header *)PA_FIRM_IMAGE;
#include "draw.h"
#include "hid.h"
u32 InputWait() {
u32 pad_state_old = HID_STATE;
while (true) {
u32 pad_state = HID_STATE;
if (pad_state ^ pad_state_old)
return ~pad_state;
}
}
u32 wait_key (char *msg) {
if (msg) {
Debug("");
Debug("%s", msg);
}
return InputWait();
}
#pragma once
#include "common.h"
u32 InputWait();
u32 wait_key (char *msg);
#define HID_STATE (*(volatile u32*)0x10146000)
#define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1)
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7)
#define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "draw.h"
#include "hid.h"
#include "firm.h"
void ClearTop (void) {
ClearScreen(TOP_SCREEN0, RGB(255, 255, 255));
ClearScreen(TOP_SCREEN1, RGB(255, 255, 255));
current_y = 0;
return;
}
int patch (void *address, u8 *sig, u32 size) {
int result = 0;
if (address && sig && size) {
memcpy(address, sig, size);
result = 1;
}
return result;
}
void *find_signature (void *start_addr, void *end_addr, u8 *sig, u32 size) {
u8 *p = start_addr;
void *max_addr = 0;
if (sig &&
(u32)start_addr < (u32)end_addr &&
(u32)end_addr > size) {
max_addr = end_addr - size;
while (p < (u8 *)max_addr) {
if ((*p == *sig) && (memcmp(p, sig, size) == 0)) {
return p;
}
p++;
}
}
return 0;
}
void fatal(void) {
Debug("Signature not found! Please Turn off your 3DS");
while (1)
;
}
int main (void) {
ClearTop();
Debug("");
int sect;
u8 *sig_addr = 0;
u32 key;
u8 sig[32] = {
0x20,0xA0,0xDA,0xE5, 0x07,0xE0,0x09,0xE2,
0x1B,0x0E,0x1A,0xE1, 0x31,0xA0,0xDD,0xE5,
0xEA,0xFF,0xFF,0x0A, 0x00,0x00,0x5A,0xE3,
0x0D,0x00,0x00,0x0A, 0x00,0xE0,0xA0,0xE3};
u8 sig_patch[32] = {
0x20,0xA0,0xDA,0xE5, 0x07,0xE0,0x09,0xE2,
0x1B,0x0E,0x1A,0xE1, 0x31,0xA0,0xDD,0xE5,
0x00,0xF0,0x20,0xE3, 0x00,0x00,0x5A,0xE3,
0x00,0xF0,0x20,0xE3, 0x00,0xE0,0xA0,0xE3};
Debug("Simple memory patcher example");
Debug("=============================");
Debug("");
Debug("Finds a byte signature in memory and");
Debug("replaces it with a new signature");
Debug("");
if (is_valid_firm()) {
sect = get_section_by_address(firm->arm11_ep);
if (sect != -1) {
Debug("ARM11 entry point found in:");
dump_section_header(sect);
if (wait_key("Press START to find signature in memory") & BUTTON_START) {
sig_addr = firm->section_headers[sect].address;
while ((sig_addr = find_signature(sig_addr,
firm->section_headers[sect].address +
firm->section_headers[sect].size,
(u8 *)&sig,
sizeof(sig))) != 0) {
ClearTop();
Debug("Signature found at %08X", sig_addr);
Debug("X : Confirm patch (at your own risk)");
Debug("B : Skip/Cancel");
while (1) {
key = wait_key("");
if (key & BUTTON_X) {
patch(sig_addr, (u8 *)&sig_patch, sizeof(sig_patch));
Debug("Signature patched");
break;
} else if (key & BUTTON_B) {
break;
}
}
sig_addr++;
}
} else {
Debug("Aborted");
}
} else { /* ARM11 entry point outside of section headers */
fatal();
}
} else { /* invalid FIRM header */
fatal();
}
wait_key("Press any key to launch firm.");
// return control to FIRM ARM9 code (performs firmlaunch)
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment