saviine/src/patcher/function_hooks.c

135 lines
4.8 KiB
C

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "common/common.h"
#include "common/fs_defs.h"
#include "common/loader_defs.h"
#include "game/rpx_rpl_table.h"
#include "dynamic_libs/fs_functions.h"
#include "dynamic_libs/os_functions.h"
#include "kernel/kernel_functions.h"
#include "function_hooks.h"
#include "discdumper.h"
#define LIB_CODE_RW_BASE_OFFSET 0xC1000000
#define CODE_RW_BASE_OFFSET 0x00000000
#define USE_EXTRA_LOG_FUNCTIONS 0
#define DECL(res, name, ...) \
res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".data"))); \
res my_ ## name(__VA_ARGS__)
/* *****************************************************************************
* Creates function pointer array
* ****************************************************************************/
#define MAKE_MAGIC(x, lib) { (unsigned int) my_ ## x, (unsigned int) &real_ ## x, lib, # x }
static const struct hooks_magic_t {
const unsigned int replaceAddr;
const unsigned int replaceCall;
const unsigned int library;
const char functionName[30];
} method_hooks[] = {
// LOADER function
//MAKE_MAGIC(LiWaitOneChunk, LIB_LOADER),
};
//! buffer to store our 2 instructions needed for our replacements
//! the code will be placed in the address of that buffer - CODE_RW_BASE_OFFSET
//! avoid this buffer to be placed in BSS and reset on start up
volatile unsigned int fs_method_calls[sizeof(method_hooks) / sizeof(struct hooks_magic_t) * 2] __attribute__((section(".data")));
void PatchMethodHooks(void)
{
restore_instructions_t * restore = (restore_instructions_t *)(RESTORE_INSTR_ADDR);
//! check if it is already patched
if(restore->magic == RESTORE_INSTR_MAGIC)
return;
restore->magic = RESTORE_INSTR_MAGIC;
restore->instr_count = 0;
bat_table_t table;
KernelSetDBATs(&table);
/* Patch branches to it. */
volatile unsigned int *space = &fs_method_calls[0];
int method_hooks_count = sizeof(method_hooks) / sizeof(struct hooks_magic_t);
for(int i = 0; i < method_hooks_count; i++)
{
unsigned int repl_addr = (unsigned int)method_hooks[i].replaceAddr;
unsigned int call_addr = (unsigned int)method_hooks[i].replaceCall;
unsigned int real_addr = 0;
if(strcmp(method_hooks[i].functionName, "OSDynLoad_Acquire") == 0)
{
memcpy(&real_addr, &OSDynLoad_Acquire, 4);
}
else if(strcmp(method_hooks[i].functionName, "LiWaitOneChunk") == 0)
{
memcpy(&real_addr, &addr_LiWaitOneChunk, 4);
}
else
{
OSDynLoad_FindExport(coreinit_handle, 0, method_hooks[i].functionName, &real_addr);
}
// fill the restore instruction section
restore->data[restore->instr_count].addr = real_addr;
restore->data[restore->instr_count].instr = *(volatile unsigned int *)(LIB_CODE_RW_BASE_OFFSET + real_addr);
restore->instr_count++;
// set pointer to the real function
*(volatile unsigned int *)(call_addr) = (unsigned int)(space) - CODE_RW_BASE_OFFSET;
DCFlushRange((void*)(call_addr), 4);
// fill the instruction of the real function
*space = *(volatile unsigned int*)(LIB_CODE_RW_BASE_OFFSET + real_addr);
space++;
// jump to real function skipping the first/replaced instruction
*space = 0x48000002 | ((real_addr + 4) & 0x03fffffc);
space++;
DCFlushRange((void*)(space - 2), 8);
ICInvalidateRange((unsigned char*)(space - 2) - CODE_RW_BASE_OFFSET, 8);
unsigned int replace_instr = 0x48000002 | (repl_addr & 0x03fffffc);
*(volatile unsigned int *)(LIB_CODE_RW_BASE_OFFSET + real_addr) = replace_instr;
DCFlushRange((void*)(LIB_CODE_RW_BASE_OFFSET + real_addr), 4);
ICInvalidateRange((void*)(real_addr), 4);
}
KernelRestoreDBATs(&table);
}
/* ****************************************************************** */
/* RESTORE ORIGINAL INSTRUCTIONS */
/* ****************************************************************** */
void RestoreInstructions(void)
{
bat_table_t table;
KernelSetDBATs(&table);
restore_instructions_t * restore = (restore_instructions_t *)(RESTORE_INSTR_ADDR);
if(restore->magic == RESTORE_INSTR_MAGIC)
{
for(unsigned int i = 0; i < restore->instr_count; i++)
{
*(volatile unsigned int *)(LIB_CODE_RW_BASE_OFFSET + restore->data[i].addr) = restore->data[i].instr;
DCFlushRange((void*)(LIB_CODE_RW_BASE_OFFSET + restore->data[i].addr), 4);
ICInvalidateRange((void*)restore->data[i].addr, 4);
}
}
restore->magic = 0;
restore->instr_count = 0;
KernelRestoreDBATs(&table);
KernelRestoreInstructions();
}