Fix kernel memory read crashing sometimes
This commit is contained in:
parent
60df33bb23
commit
d06770063c
2
Makefile
2
Makefile
@ -59,7 +59,7 @@ MAKEFLAGS += --no-print-directory
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lz -liosuhax
|
||||
LIBS := -lz -liosuhax -lgd
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
|
@ -29,6 +29,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include "gx2_types.h"
|
||||
#include "../common/fs_defs.h"
|
||||
|
||||
void InitGX2FunctionPointers(void);
|
||||
|
||||
|
@ -95,4 +95,4 @@ extern int (*inet_aton)(const char *cp, struct in_addr *inp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __SOCKET_FUNCTIONS_H_
|
||||
#endif
|
@ -8,8 +8,7 @@ extern void my_PrepareTitle_hook(void);
|
||||
|
||||
static unsigned int origPrepareTitleInstr = 0;
|
||||
|
||||
static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len)
|
||||
{
|
||||
static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len) {
|
||||
/*
|
||||
* Setup a DBAT access with cache inhibited to write through and read directly from memory
|
||||
*/
|
||||
@ -31,16 +30,14 @@ static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len
|
||||
// we only need DBAT modification for addresses out of our own DBAT range
|
||||
// as our own DBAT is available everywhere for user and supervisor
|
||||
// since our own DBAT is on DBAT5 position we don't collide here
|
||||
if(addr < 0x00800000 || addr >= 0x01000000)
|
||||
{
|
||||
if (addr < 0x00800000 || addr >= 0x01000000) {
|
||||
target_dbatu0 = (addr & 0x00F00000) | 0xC0000000 | 0x1F;
|
||||
target_dbatl0 = (addr & 0xFFF00000) | 0x32;
|
||||
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
||||
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
||||
dst_p = (unsigned char *) ((addr & 0xFFFFFF) | 0xC0000000);
|
||||
}
|
||||
if(src < 0x00800000 || src >= 0x01000000)
|
||||
{
|
||||
if (src < 0x00800000 || src >= 0x01000000) {
|
||||
target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F;
|
||||
target_dbatl1 = (src & 0xFFF00000) | 0x32;
|
||||
|
||||
@ -52,11 +49,9 @@ static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len
|
||||
asm volatile("eieio; isync");
|
||||
|
||||
unsigned int i;
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
for (i = 0; i < len; i++) {
|
||||
// if we are on the edge to next chunk
|
||||
if((target_dbatu0 != 0) && (((unsigned int)dst_p & 0x00F00000) != (target_dbatu0 & 0x00F00000)))
|
||||
{
|
||||
if ((target_dbatu0 != 0) && (((unsigned int) dst_p & 0x00F00000) != (target_dbatu0 & 0x00F00000))) {
|
||||
target_dbatu0 = ((addr + i) & 0x00F00000) | 0xC0000000 | 0x1F;
|
||||
target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32;
|
||||
dst_p = (unsigned char *) (((addr + i) & 0xFFFFFF) | 0xC0000000);
|
||||
@ -66,8 +61,7 @@ static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len
|
||||
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
||||
asm volatile("eieio; isync");
|
||||
}
|
||||
if((target_dbatu1 != 0) && (((unsigned int)src_p & 0x00F00000) != (target_dbatu1 & 0x00F00000)))
|
||||
{
|
||||
if ((target_dbatu1 != 0) && (((unsigned int) src_p & 0x00F00000) != (target_dbatu1 & 0x00F00000))) {
|
||||
target_dbatu1 = ((src + i) & 0x00F00000) | 0xB0000000 | 0x1F;
|
||||
target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32;
|
||||
src_p = (unsigned char *) (((src + i) & 0xFFFFFF) | 0xB0000000);
|
||||
@ -95,8 +89,7 @@ static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len
|
||||
asm volatile("eieio; isync");
|
||||
}
|
||||
|
||||
static void KernelReadDBATs(bat_table_t * table)
|
||||
{
|
||||
static void KernelReadDBATs(bat_table_t *table) {
|
||||
u32 i = 0;
|
||||
|
||||
asm volatile("eieio; isync");
|
||||
@ -127,8 +120,7 @@ static void KernelReadDBATs(bat_table_t * table)
|
||||
asm volatile("mfspr %0, 575" : "=r" (table->bat[i].l));
|
||||
}
|
||||
|
||||
static void KernelWriteDBATs(bat_table_t * table)
|
||||
{
|
||||
static void KernelWriteDBATs(bat_table_t *table) {
|
||||
u32 i = 0;
|
||||
|
||||
asm volatile("eieio; isync");
|
||||
@ -162,8 +154,7 @@ static void KernelWriteDBATs(bat_table_t * table)
|
||||
}
|
||||
|
||||
/* Read a 32-bit word with kernel permissions */
|
||||
uint32_t __attribute__ ((noinline)) kern_read(const void *addr)
|
||||
{
|
||||
uint32_t __attribute__ ((noinline)) kern_read(const void *addr) {
|
||||
uint32_t result;
|
||||
asm volatile (
|
||||
"li 3,1\n"
|
||||
@ -189,8 +180,7 @@ uint32_t __attribute__ ((noinline)) kern_read(const void *addr)
|
||||
}
|
||||
|
||||
/* Write a 32-bit word with kernel permissions */
|
||||
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value)
|
||||
{
|
||||
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) {
|
||||
asm volatile (
|
||||
"li 3,1\n"
|
||||
"li 4,0\n"
|
||||
@ -211,8 +201,7 @@ void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value)
|
||||
);
|
||||
}
|
||||
|
||||
void KernelSetupSyscalls(void)
|
||||
{
|
||||
void KernelSetupSyscalls(void) {
|
||||
//! assign 1 so that this variable gets into the retained .data section
|
||||
static uint8_t ucSyscallsSetupRequired = 1;
|
||||
if (!ucSyscallsSetupRequired)
|
||||
@ -247,8 +236,7 @@ void KernelSetupSyscalls(void)
|
||||
}
|
||||
|
||||
|
||||
void KernelRestoreInstructions(void)
|
||||
{
|
||||
void KernelRestoreInstructions(void) {
|
||||
if (origPrepareTitleInstr != 0)
|
||||
SC0x25_KernelCopyData((u32) addr_PrepareTitle_hook, (u32) &origPrepareTitleInstr, 4);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
#include "common/kernel_defs.h"
|
||||
#include "../common/kernel_defs.h"
|
||||
|
||||
void KernelSetupSyscalls(void);
|
||||
|
22
src/main.c
22
src/main.c
@ -10,21 +10,28 @@
|
||||
#include "dynamic_libs/sys_functions.h"
|
||||
#include "dynamic_libs/vpad_functions.h"
|
||||
#include "dynamic_libs/socket_functions.h"
|
||||
#include "patcher/function_hooks.h"
|
||||
#include "kernel/kernel_functions.h"
|
||||
#include "system/memory.h"
|
||||
#include "common/common.h"
|
||||
#include "main.h"
|
||||
#include "code_handler.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/function_patcher.h"
|
||||
#include "patcher/function_patcher_gx2.h"
|
||||
|
||||
bool isCodeHandlerInstalled;
|
||||
|
||||
#define PRINT_TEXT2(x, y, ...) { snprintf(messageBuffer, 80, __VA_ARGS__); OSScreenPutFontEx(0, x, y, messageBuffer); OSScreenPutFontEx(1, x, y, messageBuffer); }
|
||||
|
||||
typedef enum {
|
||||
EXIT = 0x0, TCP_GECKO = 0x1
|
||||
EXIT,
|
||||
TCP_GECKO
|
||||
} LaunchMethod;
|
||||
|
||||
void applyFunctionPatches() {
|
||||
patchIndividualMethodHooks(method_hooks_gx2, method_hooks_size_gx2, method_calls_gx2);
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
int Menu_Main(void) {
|
||||
//!*******************************************************************
|
||||
@ -37,6 +44,10 @@ int Menu_Main(void) {
|
||||
InitVPadFunctionPointers();
|
||||
InitSysFunctionPointers();
|
||||
|
||||
log_init(COMPUTER_IP_ADDRESS);
|
||||
log_print("Patching functions\n");
|
||||
applyFunctionPatches();
|
||||
|
||||
if (strcasecmp("men.rpx", cosAppXmlInfoStruct.rpx_name) == 0) {
|
||||
return EXIT_RELAUNCH_ON_LOAD;
|
||||
} else if (strlen(cosAppXmlInfoStruct.rpx_name) > 0 &&
|
||||
@ -73,7 +84,7 @@ int Menu_Main(void) {
|
||||
);
|
||||
|
||||
SetupKernelCallback();
|
||||
PatchMethodHooks();
|
||||
// PatchMethodHooks();
|
||||
|
||||
memoryInitialize();
|
||||
|
||||
@ -143,7 +154,8 @@ int Menu_Main(void) {
|
||||
}
|
||||
|
||||
// Button pressed ?
|
||||
update_screen = (pressedButtons & (VPAD_BUTTON_LEFT | VPAD_BUTTON_RIGHT | VPAD_BUTTON_UP | VPAD_BUTTON_DOWN)) ? 1 : 0;
|
||||
update_screen = (pressedButtons & (VPAD_BUTTON_LEFT | VPAD_BUTTON_RIGHT | VPAD_BUTTON_UP | VPAD_BUTTON_DOWN))
|
||||
? 1 : 0;
|
||||
usleep(20 * 1000);
|
||||
}
|
||||
|
||||
@ -156,7 +168,7 @@ int Menu_Main(void) {
|
||||
memoryRelease();
|
||||
|
||||
if (launchMethod == EXIT) {
|
||||
RestoreInstructions();
|
||||
// RestoreInstructions();
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
SYSLaunchMenu();
|
||||
|
@ -9,8 +9,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define COMPUTER_IP_ADDRESS "192.168.2.103"
|
||||
|
||||
//! C wrapper for our C++ functions
|
||||
int Menu_Main(void);
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "common/common.h"
|
||||
#include "../dynamic_libs/os_functions.h"
|
||||
#include "../dynamic_libs/socket_functions.h"
|
||||
#include "function_hooks.h"
|
||||
#include "fs_logger.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
|
@ -1,141 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "../common/common.h"
|
||||
#include "../dynamic_libs/os_functions.h"
|
||||
#include "../kernel/kernel_functions.h"
|
||||
#include "function_hooks.h"
|
||||
#include "../dynamic_libs/gx2_types.h"
|
||||
|
||||
#define LIB_CODE_RW_BASE_OFFSET 0xC1000000
|
||||
#define CODE_RW_BASE_OFFSET 0x00000000
|
||||
|
||||
#define DECL(res, name, ...) \
|
||||
res (* real_ ## name)(__VA_ARGS__); \
|
||||
res my_ ## name(__VA_ARGS__)
|
||||
|
||||
/* *****************************************************************************
|
||||
* Creates function pointer array
|
||||
* ****************************************************************************/
|
||||
// #define MAKE_MAGIC(x, lib) { (unsigned int) my_ ## x, (unsigned int) &real_ ## x, lib, # x }
|
||||
|
||||
#define MAKE_MAGIC(x, lib, functionType) { (unsigned int) my_ ## x, (unsigned int) &real_ ## x, lib, # x,0,0,functionType,0}
|
||||
|
||||
DECL(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer,
|
||||
s32 scan_target) {
|
||||
// TODO Does not execute
|
||||
GX2Surface surface = colorBuffer->surface;
|
||||
u32 image_size = surface.image_size;
|
||||
char buffer[100] = {0};
|
||||
__os_snprintf(buffer, 100, "Image size: %i", image_size);
|
||||
OSFatal(buffer);
|
||||
|
||||
real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target);
|
||||
}
|
||||
|
||||
DECL(int, FSInit, void) {
|
||||
return real_FSInit();
|
||||
}
|
||||
|
||||
DECL(int, socket_lib_finish, void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hooks_magic_t {
|
||||
const unsigned int replaceAddr;
|
||||
const unsigned int replaceCall;
|
||||
const unsigned int library;
|
||||
const char functionName[50];
|
||||
unsigned int realAddr;
|
||||
unsigned int restoreInstruction;
|
||||
unsigned char functionType;
|
||||
unsigned char alreadyPatched;
|
||||
} method_hooks[] = {
|
||||
MAKE_MAGIC(FSInit, LIB_CORE_INIT, STATIC_FUNCTION),
|
||||
MAKE_MAGIC(socket_lib_finish, LIB_CORE_INIT, STATIC_FUNCTION),
|
||||
MAKE_MAGIC(GX2CopyColorBufferToScanBuffer, LIB_GX2, DYNAMIC_FUNCTION),
|
||||
};
|
||||
|
||||
//! 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];
|
||||
|
||||
void PatchMethodHooks(void) {
|
||||
restore_instructions_t *restore = 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 = method_hooks[i].replaceAddr;
|
||||
unsigned int call_addr = 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 {
|
||||
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_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), (u32) 4);
|
||||
ICInvalidateRange((void *) restore->data[i].addr, (u32) 4);
|
||||
}
|
||||
}
|
||||
restore->magic = 0;
|
||||
restore->instr_count = 0;
|
||||
|
||||
KernelRestoreDBATs(&table);
|
||||
KernelRestoreInstructions();
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#ifndef _FUNCTION_HOOKS_H_
|
||||
#define _FUNCTION_HOOKS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void PatchMethodHooks(void);
|
||||
void RestoreInstructions(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FS_H */
|
74
src/patcher/function_patcher_gx2.c
Normal file
74
src/patcher/function_patcher_gx2.c
Normal file
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2017 Maschell, BullyWiiPlaza
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdlib.h> // malloc()/free()
|
||||
#include <gd.h> // image library
|
||||
#include "../utils/function_patcher.h"
|
||||
#include "../utils/logger.h"
|
||||
#include "texture.h"
|
||||
#include <gd.h>
|
||||
|
||||
static volatile int executionCounter = 0;
|
||||
|
||||
declareFunctionHook(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, s32
|
||||
scan_target) {
|
||||
if (executionCounter > 120) {
|
||||
GX2Surface surface = colorBuffer->surface;
|
||||
/*s32 format = surface.format;
|
||||
|
||||
gdImagePtr gdImagePtr = 0;
|
||||
bool no_convert;
|
||||
u8 *image_data = NULL;
|
||||
int img_size = 0;
|
||||
if (format == 0x1A) {
|
||||
UnormR8G8B8A82Yuv420p(&image_data, surface.image_data, &img_size, surface.width, surface.height,
|
||||
surface.pitch);
|
||||
} else if (format == 0x19) {
|
||||
no_convert = true;
|
||||
UnormR8G8B8A8TogdImage(&gdImagePtr, surface.image_data, surface.width, surface.height, surface.pitch);
|
||||
} else {
|
||||
no_convert = true;
|
||||
}
|
||||
|
||||
u32 imd_size = 0;
|
||||
void *data = gdImageJpegPtr(gdImagePtr, &imd_size, 95);
|
||||
if (data) {
|
||||
JpegData jpeg;
|
||||
jpeg.img_size = imd_size;
|
||||
jpeg.img_data = data;
|
||||
jpeg.img_id = 0;
|
||||
}*/
|
||||
|
||||
log_printf("GX2CopyColorBufferToScanBuffer {surface width:%d, height:%d, image size:%d, image data:%x}\n",
|
||||
surface.width, surface.height, surface.image_size, surface.image_data);
|
||||
|
||||
executionCounter = 0;
|
||||
}
|
||||
|
||||
executionCounter++;
|
||||
|
||||
real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target);
|
||||
}
|
||||
|
||||
FunctionHook method_hooks_gx2[] __attribute__((section(".data"))) = {
|
||||
makeFunctionHook(GX2CopyColorBufferToScanBuffer, LIB_GX2, STATIC_FUNCTION)
|
||||
};
|
||||
|
||||
u32 method_hooks_size_gx2 __attribute__((section(".data"))) = sizeof(method_hooks_gx2) / sizeof(FunctionHook);
|
||||
|
||||
volatile unsigned int method_calls_gx2[sizeof(method_hooks_gx2) / sizeof(FunctionHook) *
|
||||
FUNCTION_PATCHER_METHOD_STORE_SIZE] __attribute__((section(".data")));
|
34
src/patcher/function_patcher_gx2.h
Normal file
34
src/patcher/function_patcher_gx2.h
Normal file
@ -0,0 +1,34 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2016 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef FUNCTION_PATCHER_EXAMPLE_GX2_FUNCTION_PATCHER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../utils/function_patcher.h"
|
||||
|
||||
extern FunctionHook method_hooks_gx2[];
|
||||
extern u32 method_hooks_size_gx2;
|
||||
extern volatile unsigned int method_calls_gx2[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
103
src/patcher/texture.h
Normal file
103
src/patcher/texture.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/fs_defs.h"
|
||||
#include "../utils/logger.h"
|
||||
#include "../dynamic_libs/os_functions.h"
|
||||
#include <gd.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 img_size;
|
||||
u32 img_id;
|
||||
void * img_data;
|
||||
} JpegData;
|
||||
|
||||
typedef struct _R8G8B8A8_COLOR {
|
||||
u8 R, G, B, A;
|
||||
} R8G8B8A8_COLOR;
|
||||
|
||||
void UnormR8G8B8A8TogdImage(gdImagePtr *gdImgTmp, void *image_data, u32 width, u32 rows, u32 pitch) {
|
||||
*gdImgTmp = gdImageCreateTrueColor(width / 2, rows / 2);
|
||||
|
||||
R8G8B8A8_COLOR *buffer = (R8G8B8A8_COLOR *) image_data;
|
||||
R8G8B8A8_COLOR val;
|
||||
for (u32 row = 0; row < rows; ++row) {
|
||||
for (u32 x = 0; x < width; ++x) {
|
||||
val = buffer[row * pitch + x];
|
||||
gdImageSetPixel(*gdImgTmp, x / 2, row / 2, gdTrueColor(val.R, val.G, val.B));
|
||||
++x;
|
||||
}
|
||||
++row;
|
||||
}
|
||||
}
|
||||
|
||||
void UnormR8G8B8A82Yuv420p(u8 **destination_, void *image_data, int *dest_img_size, u32 width, u32 height, u32 pitch) {
|
||||
u32 image_size = width * height;
|
||||
u32 upos = image_size;
|
||||
u32 vpos = upos + upos / 4;
|
||||
*dest_img_size = (vpos + upos / 4);
|
||||
if (*destination_) {
|
||||
free(destination_);
|
||||
}
|
||||
*destination_ = (u8 *) malloc(sizeof(u8) * *dest_img_size);
|
||||
u8 *destination = *destination_;
|
||||
if (!destination) {
|
||||
*dest_img_size = 0;
|
||||
return;
|
||||
}
|
||||
log_printf("allocated %d \n", *dest_img_size);
|
||||
|
||||
R8G8B8A8_COLOR *buffer = (R8G8B8A8_COLOR *) image_data;
|
||||
|
||||
u32 i = 0;
|
||||
|
||||
for (u32 line = 0; line < height; ++line) {
|
||||
if (!(line % 2)) {
|
||||
for (u32 x = 0; x < width; x += 2) {
|
||||
u8 r = buffer[line * pitch + x].R;
|
||||
u8 g = buffer[line * pitch + x].G;
|
||||
u8 b = buffer[line * pitch + x].B;
|
||||
|
||||
destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16;
|
||||
|
||||
destination[upos++] = ((-38 * r + -74 * g + 112 * b) >> 8) + 128;
|
||||
destination[vpos++] = ((112 * r + -94 * g + -18 * b) >> 8) + 128;
|
||||
|
||||
r = buffer[line * pitch + x].R;
|
||||
g = buffer[line * pitch + x].G;
|
||||
b = buffer[line * pitch + x].B;
|
||||
|
||||
destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16;
|
||||
}
|
||||
} else {
|
||||
for (u32 x = 0; x < width; x += 1) {
|
||||
u8 r = buffer[line * pitch + x].R;
|
||||
u8 g = buffer[line * pitch + x].G;
|
||||
u8 b = buffer[line * pitch + x].B;
|
||||
|
||||
destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
log_printf("done %d \n", *dest_img_size);
|
||||
}
|
||||
|
||||
void UnormR10G10B10A2TogdImage(gdImagePtr *gdImgTmp, void *image_data, u32 width, u32 rows, u32 pitch) {
|
||||
u32 *buffer = (u32 *) image_data;
|
||||
u32 val = 0;
|
||||
for (u32 row = 0; row < rows; ++row) {
|
||||
for (u32 x = 0; x < width; ++x) {
|
||||
/*
|
||||
R ((test >> 24) & 0xFF))
|
||||
G ((test >> 14) & 0xFF))
|
||||
B ((test >> 4) & 0xFF))
|
||||
alpha (test & 0x3);
|
||||
*/
|
||||
val = buffer[row * pitch + x];
|
||||
gdImageSetPixel(*gdImgTmp, x, row, gdTrueColor(((val >> 24) & 0xFF),
|
||||
((val >> 14) & 0xFF),
|
||||
((val >> 4) & 0xFF)));
|
||||
}
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ struct pygecko_bss_t {
|
||||
#define EWOULDBLOCK 6
|
||||
#define DATA_BUFFER_SIZE 0x5000
|
||||
// #define WRITE_SCREEN_MESSAGE_BUFFER_SIZE 100
|
||||
#define SERVER_VERSION "05/24/2017"
|
||||
#define SERVER_VERSION "06/02/2017"
|
||||
#define ONLY_ZEROS_READ 0xB0
|
||||
#define NON_ZEROS_READ 0xBD
|
||||
|
||||
@ -378,7 +378,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||
}
|
||||
case COMMAND_READ_MEMORY_KERNEL: {
|
||||
const unsigned char *startingAddress, *endingAddress, *useKernRead;
|
||||
ret = recvwait(bss, clientfd, buffer, 3 * 4);
|
||||
ret = recvwait(bss, clientfd, buffer, 3 * sizeof(int));
|
||||
CHECK_ERROR(ret < 0)
|
||||
startingAddress = ((const unsigned char **) buffer)[0];
|
||||
endingAddress = ((const unsigned char **) buffer)[1];
|
||||
@ -395,7 +395,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||
// Figure out if all bytes are zero to possibly avoid sending them
|
||||
int rangeIterationIndex = 0;
|
||||
for (; rangeIterationIndex < length; rangeIterationIndex++) {
|
||||
int character = useKernRead ? kern_read(startingAddress + rangeIterationIndex)
|
||||
int character = useKernRead ? readKernelMemory(startingAddress + rangeIterationIndex)
|
||||
: startingAddress[rangeIterationIndex];
|
||||
if (character != 0) {
|
||||
break;
|
||||
@ -407,11 +407,12 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||
ret = sendByte(bss, clientfd, ONLY_ZEROS_READ);
|
||||
CHECK_ERROR(ret < 0)
|
||||
} else {
|
||||
// Send the real bytes now
|
||||
buffer[0] = NON_ZEROS_READ;
|
||||
|
||||
if (useKernRead) {
|
||||
for (int offset = 0; offset < length; offset += 4) {
|
||||
*((int *) (buffer + 1) + offset / 4) = kern_read(startingAddress + offset);
|
||||
for (int offset = 0; offset < length; offset += sizeof(int)) {
|
||||
*((int *) (buffer + 1) + offset / sizeof(int)) = readKernelMemory(startingAddress + offset);
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer + 1, startingAddress, length);
|
||||
@ -601,26 +602,26 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||
}
|
||||
case COMMAND_KERNEL_WRITE: {
|
||||
void *ptr, *value;
|
||||
ret = recvwait(bss, clientfd, buffer, 8);
|
||||
ret = recvwait(bss, clientfd, buffer, sizeof(int) * 2);
|
||||
CHECK_ERROR(ret < 0)
|
||||
|
||||
ptr = ((void **) buffer)[0];
|
||||
value = ((void **) buffer)[1];
|
||||
|
||||
kern_write(ptr, (uint32_t) value);
|
||||
writeKernelMemory(ptr, (uint32_t) value);
|
||||
break;
|
||||
}
|
||||
case COMMAND_KERNEL_READ: {
|
||||
void *ptr, *value;
|
||||
ret = recvwait(bss, clientfd, buffer, 4);
|
||||
ret = recvwait(bss, clientfd, buffer, sizeof(int));
|
||||
CHECK_ERROR(ret < 0);
|
||||
|
||||
ptr = ((void **) buffer)[0];
|
||||
|
||||
value = (void *) kern_read(ptr);
|
||||
value = (void *) readKernelMemory(ptr);
|
||||
|
||||
*(void **) buffer = value;
|
||||
sendwait(bss, clientfd, buffer, 4);
|
||||
sendwait(bss, clientfd, buffer, sizeof(int));
|
||||
break;
|
||||
}
|
||||
case COMMAND_TAKE_SCREEN_SHOT: {
|
||||
@ -1271,7 +1272,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||
bufferIndex += sizeof(bool);
|
||||
bool write = buffer[bufferIndex];
|
||||
bufferIndex += sizeof(bool);
|
||||
setDataAddressBreakPointRegister(address, read, write);
|
||||
setDataBreakpoint(address, read, write);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1282,7 +1283,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
||||
|
||||
// Parse the address and set the breakpoint
|
||||
unsigned int address = ((unsigned int *) buffer)[0];
|
||||
setInstructionAddressBreakPointRegister(address);
|
||||
setInstructionBreakpoint(address);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -40,9 +40,10 @@ typedef struct OSContext {
|
||||
|
||||
#define CPU_STACK_TRACE_DEPTH 10
|
||||
|
||||
#define mfspr(_rn) \
|
||||
// http://elixir.free-electrons.com/linux/v2.6.24/source/include/asm-powerpc/reg.h#L713
|
||||
#define mfspr(spr) \
|
||||
({ register uint32_t _rval = 0; \
|
||||
asm volatile("mfspr %0," __stringify(_rn) \
|
||||
asm volatile("mfspr %0," __stringify(spr) \
|
||||
: "=r" (_rval));\
|
||||
_rval; \
|
||||
})
|
||||
|
404
src/utils/function_patcher.c
Normal file
404
src/utils/function_patcher.c
Normal file
@ -0,0 +1,404 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2016 Maschell
|
||||
* With code from chadderz and dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "../utils/logger.h"
|
||||
#include "../kernel/kernel_functions.h"
|
||||
#include "function_patcher.h"
|
||||
|
||||
#define CODE_RW_BASE_OFFSET 0x00000000
|
||||
#define DEBUG_LOG_DYN 1
|
||||
|
||||
void printFunctionHooks(FunctionHook *functionHooks, u32 functionHooksSize) {
|
||||
for (unsigned int functionHookIndex = 0; functionHookIndex < functionHooksSize; functionHookIndex++) {
|
||||
log_printf("Real address (%s): %08x\n", functionHooks[functionHookIndex].functionName,
|
||||
functionHooks[functionHookIndex].realAddress);
|
||||
}
|
||||
}
|
||||
|
||||
bool setRealAddress(FunctionHook functionHooks[], int functionHooksSize, const char *functionName, u32 address) {
|
||||
for (int functionHookIndex = 0; functionHookIndex < functionHooksSize; functionHookIndex++) {
|
||||
if (strncmp(functionName, functionHooks[functionHookIndex].functionName, 50) == 0) {
|
||||
functionHooks[functionHookIndex].realAddress = address;
|
||||
log_printf("Function %s defined with address %08x\n", functionHooks[functionHookIndex].functionName,
|
||||
functionHooks[functionHookIndex].realAddress);
|
||||
// printFunctionHooks(functionHooks, functionHooksSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Patches a function that is loaded at the start of each application. Its not required to restore, at least when they are really dynamic.
|
||||
* "normal" functions should be patch with the normal patcher. Current Code by Maschell with the help of dimok. Orignal code by Chadderz.
|
||||
*/
|
||||
void patchIndividualMethodHooks(FunctionHook *functionHook, int hook_information_size,
|
||||
volatile unsigned int *dynamic_method_calls) {
|
||||
log_printf("Patching %d given functions\n", hook_information_size);
|
||||
/* Patch branches to it. */
|
||||
volatile unsigned int *space = &dynamic_method_calls[0];
|
||||
|
||||
int method_hooks_count = hook_information_size;
|
||||
|
||||
u32 skipInstructionLength = 1;
|
||||
u32 myInstructionLength = 6;
|
||||
u32 instructionLength = myInstructionLength + skipInstructionLength;
|
||||
u32 flush_len = 4 * instructionLength;
|
||||
for (int functionIndex = 0; functionIndex < method_hooks_count; functionIndex++) {
|
||||
log_printf("Patching %s...\n", functionHook[functionIndex].functionName);
|
||||
if (functionHook[functionIndex].functionType == STATIC_FUNCTION &&
|
||||
functionHook[functionIndex].alreadyPatched == 1) {
|
||||
if (isDynamicFunction((u32) OSEffectiveToPhysical((void *) functionHook[functionIndex].realAddress))) {
|
||||
log_printf("The function %s is a dynamic function. Please fix that <3\n",
|
||||
functionHook[functionIndex].functionName);
|
||||
functionHook[functionIndex].functionType = DYNAMIC_FUNCTION;
|
||||
} else {
|
||||
log_printf("Skipping %s, its already patched\n", functionHook[functionIndex].functionName);
|
||||
space += instructionLength;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
u32 physical = 0;
|
||||
unsigned int replaceAddress = functionHook[functionIndex].replaceAddress;
|
||||
unsigned int callAddress = functionHook[functionIndex].replaceCall;
|
||||
|
||||
unsigned int realAddress = functionHook[functionIndex].realAddress;
|
||||
|
||||
if (realAddress == 0) {
|
||||
log_printf("The real address was NULL, we need to find it.\n");
|
||||
realAddress = getFunctionAddress(functionHook[functionIndex].library,
|
||||
functionHook[functionIndex].functionName);
|
||||
} else {
|
||||
log_printf("The real address was not NULL! We patch it by the given address.\n");
|
||||
}
|
||||
|
||||
if (realAddress == 0) {
|
||||
log_printf("[Patch] OSDynLoad_FindExport failed for %s\n", functionHook[functionIndex].functionName);
|
||||
space += instructionLength;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUG_LOG_DYN)log_printf("%s is located at %08X!\n", functionHook[functionIndex].functionName, realAddress);
|
||||
|
||||
physical = (u32) OSEffectiveToPhysical((void *) realAddress);
|
||||
if (!physical) {
|
||||
log_printf("Error. Something is wrong with the physical address\n");
|
||||
space += instructionLength;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUG_LOG_DYN)
|
||||
log_printf("%s physical is located at %08X!\n", functionHook[functionIndex].functionName, physical);
|
||||
|
||||
*(volatile unsigned int *) (callAddress) = (unsigned int) (space) - CODE_RW_BASE_OFFSET;
|
||||
|
||||
SC0x25_KernelCopyData((u32) space, physical, 4);
|
||||
space++;
|
||||
|
||||
//Only works if skip_instr == 1
|
||||
functionHook[functionIndex].realAddress = realAddress;
|
||||
functionHook[functionIndex].restoreInstruction = *(space - 1);
|
||||
if (DEBUG_LOG_DYN)log_printf("method_hooks[i].realAddr = %08X!\n", functionHook[functionIndex].realAddress);
|
||||
if (DEBUG_LOG_DYN)
|
||||
log_printf("method_hooks[i].restoreInstruction = %08X!\n", functionHook[functionIndex].restoreInstruction);
|
||||
|
||||
//adding jump to real function thx @ dimok for the assembler code
|
||||
/*
|
||||
90 61 ff e0 stw r3,-32(r1)
|
||||
3c 60 12 34 lis r3,4660
|
||||
60 63 56 78 ori r3,r3,22136
|
||||
7c 69 03 a6 mtctr r3
|
||||
80 61 ff e0 lwz r3,-32(r1)
|
||||
4e 80 04 20 bctr*/
|
||||
*space = 0x9061FFE0;
|
||||
space++;
|
||||
*space = 0x3C600000 | (((realAddress + (skipInstructionLength * 4)) >> 16) & 0x0000FFFF); // lis r3, real_addr@h
|
||||
space++;
|
||||
*space = 0x60630000 | ((realAddress + (skipInstructionLength * 4)) & 0x0000ffff); // ori r3, r3, real_addr@l
|
||||
space++;
|
||||
*space = 0x7C6903A6; // mtctr r3
|
||||
space++;
|
||||
*space = 0x8061FFE0; // lwz r3,-32(r1)
|
||||
space++;
|
||||
*space = 0x4E800420; // bctr
|
||||
space++;
|
||||
DCFlushRange((void *) (space - instructionLength), flush_len);
|
||||
ICInvalidateRange((unsigned char *) (space - instructionLength), flush_len);
|
||||
|
||||
//setting jump back
|
||||
unsigned int replace_instr = 0x48000002 | (replaceAddress & 0x03fffffc);
|
||||
DCFlushRange(&replace_instr, 4);
|
||||
|
||||
SC0x25_KernelCopyData(physical, (u32) OSEffectiveToPhysical(&replace_instr), 4);
|
||||
ICInvalidateRange((void *) (realAddress), 4);
|
||||
|
||||
functionHook[functionIndex].alreadyPatched = 1;
|
||||
log_printf("done!\n");
|
||||
}
|
||||
|
||||
log_print("Done with patching given functions!\n");
|
||||
}
|
||||
|
||||
void restoreIndividualInstructions(FunctionHook *functionHooks, int hook_information_size) {
|
||||
log_printf("Restoring given functions!\n");
|
||||
int method_hooks_count = hook_information_size;
|
||||
for (int functionIndex = 0; functionIndex < method_hooks_count; functionIndex++) {
|
||||
log_printf("Restoring %s... ", functionHooks[functionIndex].functionName);
|
||||
if (functionHooks[functionIndex].restoreInstruction == 0 || functionHooks[functionIndex].realAddress == 0) {
|
||||
log_printf("I don't have the information for the restore =( skip\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int realAddress = functionHooks[functionIndex].realAddress;
|
||||
|
||||
if (realAddress == 0) {
|
||||
log_printf("The real address was NULL, we need to find it.\n");
|
||||
realAddress = getFunctionAddress(functionHooks[functionIndex].library,
|
||||
functionHooks[functionIndex].functionName);
|
||||
} else {
|
||||
log_printf("The real address was not NULL! We patch it by the given address.\n");
|
||||
}
|
||||
|
||||
if (!realAddress) {
|
||||
log_printf("[Restore] OSDynLoad_FindExport failed for %s\n", functionHooks[functionIndex].functionName);
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 physical = (u32) OSEffectiveToPhysical((void *) realAddress);
|
||||
if (!physical) {
|
||||
log_printf("Something is wrong with the physical address\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDynamicFunction((unsigned int) physical)) {
|
||||
log_printf("Its a dynamic function. We don't need to restore it!\n",
|
||||
functionHooks[functionIndex].functionName);
|
||||
} else {
|
||||
physical = (u32) OSEffectiveToPhysical(
|
||||
(void *) functionHooks[functionIndex].realAddress); //When its an static function, we need to use the old location
|
||||
if (DEBUG_LOG_DYN)
|
||||
log_printf("Restoring %08X to %08X\n", (u32) functionHooks[functionIndex].restoreInstruction, physical);
|
||||
SC0x25_KernelCopyData(physical, (u32) &functionHooks[functionIndex].restoreInstruction, 4);
|
||||
if (DEBUG_LOG_DYN)log_printf("ICInvalidateRange %08X\n", (void *) functionHooks[functionIndex].realAddress);
|
||||
ICInvalidateRange((void *) functionHooks[functionIndex].realAddress, 4);
|
||||
log_printf("done\n");
|
||||
}
|
||||
functionHooks[functionIndex].alreadyPatched = 0; // In case a
|
||||
}
|
||||
|
||||
KernelRestoreInstructions();
|
||||
log_print("Done with restoring given functions!\n");
|
||||
}
|
||||
|
||||
bool isDynamicFunction(unsigned int physicalAddress) {
|
||||
return (physicalAddress & 0x80000000) == 0x80000000;
|
||||
}
|
||||
|
||||
unsigned int getRPLHandle(int library, const char *functionName) {
|
||||
unsigned int rplHandle = 0;
|
||||
|
||||
switch (library) {
|
||||
case LIB_CORE_INIT:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_CORE_INIT\n", functionName);
|
||||
if (coreinit_handle == 0) {
|
||||
log_print("LIB_CORE_INIT not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = coreinit_handle;
|
||||
break;
|
||||
|
||||
case LIB_GX2:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_GX2\n", functionName);
|
||||
unsigned int gx2_handle = 0;
|
||||
OSDynLoad_Acquire("gx2.rpl", &gx2_handle);
|
||||
if (gx2_handle == 0) {
|
||||
log_print("LIB_GX2 not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = gx2_handle;
|
||||
break;
|
||||
|
||||
/*case LIB_NSYSNET:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_NSYSNET\n", functionName);
|
||||
if (nsysnet_handle == 0) {
|
||||
log_print("LIB_NSYSNET not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = nsysnet_handle;
|
||||
break;
|
||||
|
||||
case LIB_AOC:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_AOC\n", functionName);
|
||||
if (aoc_handle == 0) {
|
||||
log_print("LIB_AOC not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = aoc_handle;
|
||||
break;
|
||||
|
||||
case LIB_AX:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_AX\n", functionName);
|
||||
if (sound_handle == 0) {
|
||||
log_print("LIB_AX not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = sound_handle;
|
||||
break;*/
|
||||
|
||||
case LIB_FS:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_FS\n", functionName);
|
||||
if (coreinit_handle == 0) {
|
||||
log_print("LIB_FS not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = coreinit_handle;
|
||||
break;
|
||||
|
||||
case LIB_OS:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_OS\n", functionName);
|
||||
if (coreinit_handle == 0) {
|
||||
log_print("LIB_OS not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = coreinit_handle;
|
||||
break;
|
||||
|
||||
/*
|
||||
case LIB_PADSCORE:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_PADSCORE\n", functionName);
|
||||
if (padscore_handle == 0) {
|
||||
log_print("LIB_PADSCORE not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = padscore_handle;
|
||||
break;
|
||||
|
||||
case LIB_SOCKET:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_SOCKET\n", functionName);
|
||||
if (nsysnet_handle == 0) {
|
||||
log_print("LIB_SOCKET not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = nsysnet_handle;
|
||||
break;
|
||||
|
||||
case LIB_SYS:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_SYS\n", functionName);
|
||||
if (sysapp_handle == 0) {
|
||||
log_print("LIB_SYS not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = sysapp_handle;
|
||||
break;
|
||||
|
||||
case LIB_VPAD:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_VPAD\n", functionName);
|
||||
if (vpad_handle == 0) {
|
||||
log_print("LIB_VPAD not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = vpad_handle;
|
||||
break;
|
||||
|
||||
case LIB_NN_ACP:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_NN_ACP\n", functionName);
|
||||
if (acp_handle == 0) {
|
||||
log_print("LIB_NN_ACP not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = acp_handle;
|
||||
break;
|
||||
|
||||
case LIB_SYSHID:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_SYSHID\n", functionName);
|
||||
if (syshid_handle == 0) {
|
||||
log_print("LIB_SYSHID not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = syshid_handle;
|
||||
break;
|
||||
|
||||
case LIB_VPADBASE:
|
||||
if (DEBUG_LOG_DYN)log_printf("FindExport of %s! From LIB_VPADBASE\n", functionName);
|
||||
if (vpadbase_handle == 0) {
|
||||
log_print("LIB_VPADBASE not acquired\n");
|
||||
return 0;
|
||||
}
|
||||
rplHandle = vpadbase_handle;
|
||||
break; */
|
||||
|
||||
default:;
|
||||
char messageBuffer[50];
|
||||
__os_snprintf(messageBuffer, 50, "Unhandled library %i", library);
|
||||
OSFatal(messageBuffer);
|
||||
break;
|
||||
}
|
||||
|
||||
return rplHandle;
|
||||
}
|
||||
|
||||
unsigned int getFunctionAddress(unsigned int library, const char *functionName) {
|
||||
unsigned int realAddress = 0;
|
||||
|
||||
if (strcmp(functionName, "OSDynLoad_Acquire") == 0) {
|
||||
memcpy(&realAddress, &OSDynLoad_Acquire, 4);
|
||||
return realAddress;
|
||||
} else if (strcmp(functionName, "LiWaitOneChunk") == 0) {
|
||||
realAddress = (unsigned int) addr_LiWaitOneChunk;
|
||||
return realAddress;
|
||||
} else if (strcmp(functionName, "LiBounceOneChunk") == 0) {
|
||||
//! not required on firmwares above 3.1.0
|
||||
if (OS_FIRMWARE >= 400)
|
||||
return 0;
|
||||
|
||||
unsigned int addr_LiBounceOneChunk = 0x010003A0;
|
||||
realAddress = addr_LiBounceOneChunk;
|
||||
return realAddress;
|
||||
}
|
||||
|
||||
unsigned int rpl_handle = getRPLHandle(library, functionName);
|
||||
|
||||
if (!rpl_handle) {
|
||||
log_printf("Failed to find the RPL handle for %s\n", functionName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSDynLoad_FindExport((u32) rpl_handle, 0, functionName, &realAddress);
|
||||
|
||||
if (!realAddress) {
|
||||
log_printf("[Get] OSDynLoad_FindExport failed for %s\n", functionName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((u32) (*(volatile unsigned int *) (realAddress) & 0x48000002) == 0x48000000) {
|
||||
unsigned int address_diff = (u32) (*(volatile unsigned int *) (realAddress) & 0x03FFFFFC);
|
||||
if ((address_diff & 0x03000000) == 0x03000000) {
|
||||
address_diff |= 0xFC000000;
|
||||
}
|
||||
realAddress += (int) address_diff;
|
||||
if ((u32) (*(volatile unsigned int *) (realAddress) & 0x48000002) == 0x48000000) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return realAddress;
|
||||
}
|
123
src/utils/function_patcher.h
Normal file
123
src/utils/function_patcher.h
Normal file
@ -0,0 +1,123 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2016 Maschell
|
||||
* With code from chadderz and dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _FUNCTION_HOOKS_H_
|
||||
#define _FUNCTION_HOOKS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
#include "../common/common.h" // OS_FIRMWARE
|
||||
|
||||
// Library handles
|
||||
#include "../dynamic_libs/aoc_functions.h"
|
||||
#include "../dynamic_libs/ax_functions.h"
|
||||
#include "../dynamic_libs/fs_functions.h"
|
||||
#include "../dynamic_libs/gx2_functions.h"
|
||||
#include "../dynamic_libs/os_functions.h"
|
||||
#include "../dynamic_libs/padscore_functions.h"
|
||||
#include "../dynamic_libs/socket_functions.h"
|
||||
#include "../dynamic_libs/sys_functions.h"
|
||||
#include "../dynamic_libs/vpad_functions.h"
|
||||
/*#include "../dynamic_libs/acp_functions.h"
|
||||
#include "../dynamic_libs/syshid_functions.h"*/
|
||||
|
||||
/* Macros for libs */
|
||||
#define LIB_CORE_INIT 0
|
||||
#define LIB_NSYSNET 1
|
||||
#define LIB_GX2 2
|
||||
#define LIB_AOC 3
|
||||
#define LIB_AX 4
|
||||
#define LIB_FS 5
|
||||
#define LIB_OS 6
|
||||
#define LIB_PADSCORE 7
|
||||
#define LIB_SOCKET 8
|
||||
#define LIB_SYS 9
|
||||
#define LIB_VPAD 10
|
||||
#define LIB_NN_ACP 11
|
||||
#define LIB_SYSHID 12
|
||||
#define LIB_VPADBASE 13
|
||||
|
||||
// functions types
|
||||
#define STATIC_FUNCTION 0
|
||||
#define DYNAMIC_FUNCTION 1
|
||||
|
||||
/*enum Library {
|
||||
LIB_CORE_INIT,
|
||||
LIB_NSYSNET,
|
||||
LIB_GX2,
|
||||
LIB_AOC,
|
||||
LIB_AX,
|
||||
LIB_FS,
|
||||
LIB_OS,
|
||||
LIB_PADSCORE,
|
||||
LIB_SOCKET,
|
||||
LIB_SYS,
|
||||
LIB_VPAD,
|
||||
LIB_NN_ACP,
|
||||
LIB_SYSHID,
|
||||
LIB_VPADBASE
|
||||
};
|
||||
|
||||
enum FunctionTypes {
|
||||
STATIC_FUNCTION,
|
||||
DYNAMIC_FUNCTION
|
||||
};*/
|
||||
|
||||
// Original code by Chadderz
|
||||
#define declareFunctionHook(returnType, functionName, ...) \
|
||||
returnType (* real_ ## functionName)(__VA_ARGS__) __attribute__((section(".data"))); \
|
||||
returnType my_ ## functionName(__VA_ARGS__)
|
||||
|
||||
#define declareGameFunctionHook(functionName) { (unsigned int) my_ ## functionName, (unsigned int) &real_ ## functionName, 0, # functionName,0,0,1,0}
|
||||
|
||||
#define makeFunctionHook(functionName, library, functionType) { (unsigned int) my_ ## functionName, (unsigned int) &real_ ## functionName, library, # functionName,0,0,functionType,0}
|
||||
|
||||
#define FUNCTION_PATCHER_METHOD_STORE_SIZE 7
|
||||
|
||||
typedef struct {
|
||||
const unsigned int replaceAddress;
|
||||
const unsigned int replaceCall;
|
||||
const unsigned int library;
|
||||
const char functionName[50];
|
||||
unsigned int realAddress;
|
||||
unsigned int restoreInstruction;
|
||||
unsigned char functionType;
|
||||
unsigned char alreadyPatched;
|
||||
} FunctionHook;
|
||||
|
||||
void printFunctionHooks(FunctionHook *functionHooks, u32 functionHooksSize);
|
||||
|
||||
bool setRealAddress(FunctionHook functionHooks[], int functionHooksSize, const char *functionName, u32 address);
|
||||
|
||||
void patchIndividualMethodHooks(FunctionHook *functionHook, int hook_information_size,
|
||||
volatile unsigned int *dynamic_method_calls);
|
||||
|
||||
void restoreIndividualInstructions(FunctionHook *functionHooks, int hook_information_size);
|
||||
|
||||
unsigned int getFunctionAddress(unsigned int library, const char *functionName);
|
||||
|
||||
bool isDynamicFunction(unsigned int physicalAddress);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOGGER 1
|
||||
#define COMPUTER_IP_ADDRESS "192.168.2.103"
|
||||
|
||||
#ifdef DEBUG_LOGGER
|
||||
void log_init(const char * ip);
|
||||
|
BIN
tcpgecko.elf
BIN
tcpgecko.elf
Binary file not shown.
Loading…
Reference in New Issue
Block a user