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
|
# 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
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
@ -29,6 +29,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gx2_types.h"
|
#include "gx2_types.h"
|
||||||
|
#include "../common/fs_defs.h"
|
||||||
|
|
||||||
void InitGX2FunctionPointers(void);
|
void InitGX2FunctionPointers(void);
|
||||||
|
|
||||||
|
@ -95,4 +95,4 @@ extern int (*inet_aton)(const char *cp, struct in_addr *inp);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // __SOCKET_FUNCTIONS_H_
|
#endif
|
@ -8,8 +8,7 @@ extern void my_PrepareTitle_hook(void);
|
|||||||
|
|
||||||
static unsigned int origPrepareTitleInstr = 0;
|
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
|
* Setup a DBAT access with cache inhibited to write through and read directly from memory
|
||||||
*/
|
*/
|
||||||
@ -25,52 +24,47 @@ static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len
|
|||||||
unsigned int target_dbatu1 = 0;
|
unsigned int target_dbatu1 = 0;
|
||||||
unsigned int target_dbatl1 = 0;
|
unsigned int target_dbatl1 = 0;
|
||||||
|
|
||||||
unsigned char *dst_p = (unsigned char*)addr;
|
unsigned char *dst_p = (unsigned char *) addr;
|
||||||
unsigned char *src_p = (unsigned char*)src;
|
unsigned char *src_p = (unsigned char *) src;
|
||||||
|
|
||||||
// we only need DBAT modification for addresses out of our own DBAT range
|
// we only need DBAT modification for addresses out of our own DBAT range
|
||||||
// as our own DBAT is available everywhere for user and supervisor
|
// as our own DBAT is available everywhere for user and supervisor
|
||||||
// since our own DBAT is on DBAT5 position we don't collide here
|
// 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_dbatu0 = (addr & 0x00F00000) | 0xC0000000 | 0x1F;
|
||||||
target_dbatl0 = (addr & 0xFFF00000) | 0x32;
|
target_dbatl0 = (addr & 0xFFF00000) | 0x32;
|
||||||
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
||||||
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
||||||
dst_p = (unsigned char*)((addr & 0xFFFFFF) | 0xC0000000);
|
dst_p = (unsigned char *) ((addr & 0xFFFFFF) | 0xC0000000);
|
||||||
}
|
}
|
||||||
if(src < 0x00800000 || src >= 0x01000000)
|
if (src < 0x00800000 || src >= 0x01000000) {
|
||||||
{
|
|
||||||
target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F;
|
target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F;
|
||||||
target_dbatl1 = (src & 0xFFF00000) | 0x32;
|
target_dbatl1 = (src & 0xFFF00000) | 0x32;
|
||||||
|
|
||||||
asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1));
|
asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1));
|
||||||
asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1));
|
asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1));
|
||||||
src_p = (unsigned char*)((src & 0xFFFFFF) | 0xB0000000);
|
src_p = (unsigned char *) ((src & 0xFFFFFF) | 0xB0000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
asm volatile("eieio; isync");
|
asm volatile("eieio; isync");
|
||||||
|
|
||||||
unsigned int i;
|
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 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_dbatu0 = ((addr + i) & 0x00F00000) | 0xC0000000 | 0x1F;
|
||||||
target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32;
|
target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32;
|
||||||
dst_p = (unsigned char*)(((addr + i) & 0xFFFFFF) | 0xC0000000);
|
dst_p = (unsigned char *) (((addr + i) & 0xFFFFFF) | 0xC0000000);
|
||||||
|
|
||||||
asm volatile("eieio; isync");
|
asm volatile("eieio; isync");
|
||||||
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0));
|
||||||
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0));
|
||||||
asm volatile("eieio; isync");
|
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_dbatu1 = ((src + i) & 0x00F00000) | 0xB0000000 | 0x1F;
|
||||||
target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32;
|
target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32;
|
||||||
src_p = (unsigned char*)(((src + i) & 0xFFFFFF) | 0xB0000000);
|
src_p = (unsigned char *) (((src + i) & 0xFFFFFF) | 0xB0000000);
|
||||||
|
|
||||||
asm volatile("eieio; isync");
|
asm volatile("eieio; isync");
|
||||||
asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1));
|
asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1));
|
||||||
@ -95,8 +89,7 @@ static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len
|
|||||||
asm volatile("eieio; isync");
|
asm volatile("eieio; isync");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void KernelReadDBATs(bat_table_t * table)
|
static void KernelReadDBATs(bat_table_t *table) {
|
||||||
{
|
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
|
|
||||||
asm volatile("eieio; isync");
|
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));
|
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;
|
u32 i = 0;
|
||||||
|
|
||||||
asm volatile("eieio; isync");
|
asm volatile("eieio; isync");
|
||||||
@ -162,8 +154,7 @@ static void KernelWriteDBATs(bat_table_t * table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read a 32-bit word with kernel permissions */
|
/* 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;
|
uint32_t result;
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"li 3,1\n"
|
"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 */
|
/* 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 (
|
asm volatile (
|
||||||
"li 3,1\n"
|
"li 3,1\n"
|
||||||
"li 4,0\n"
|
"li 4,0\n"
|
||||||
@ -211,44 +201,42 @@ 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
|
//! assign 1 so that this variable gets into the retained .data section
|
||||||
static uint8_t ucSyscallsSetupRequired = 1;
|
static uint8_t ucSyscallsSetupRequired = 1;
|
||||||
if(!ucSyscallsSetupRequired)
|
if (!ucSyscallsSetupRequired)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ucSyscallsSetupRequired = 0;
|
ucSyscallsSetupRequired = 0;
|
||||||
|
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x36 * 4)), (unsigned int)KernelReadDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl1 + (0x36 * 4)), (unsigned int) KernelReadDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x36 * 4)), (unsigned int)KernelReadDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl2 + (0x36 * 4)), (unsigned int) KernelReadDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x36 * 4)), (unsigned int)KernelReadDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl3 + (0x36 * 4)), (unsigned int) KernelReadDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x36 * 4)), (unsigned int)KernelReadDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl4 + (0x36 * 4)), (unsigned int) KernelReadDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x36 * 4)), (unsigned int)KernelReadDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl5 + (0x36 * 4)), (unsigned int) KernelReadDBATs);
|
||||||
|
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x37 * 4)), (unsigned int)KernelWriteDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl1 + (0x37 * 4)), (unsigned int) KernelWriteDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x37 * 4)), (unsigned int)KernelWriteDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl2 + (0x37 * 4)), (unsigned int) KernelWriteDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x37 * 4)), (unsigned int)KernelWriteDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl3 + (0x37 * 4)), (unsigned int) KernelWriteDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x37 * 4)), (unsigned int)KernelWriteDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl4 + (0x37 * 4)), (unsigned int) KernelWriteDBATs);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x37 * 4)), (unsigned int)KernelWriteDBATs);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl5 + (0x37 * 4)), (unsigned int) KernelWriteDBATs);
|
||||||
|
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl1 + (0x25 * 4)), (unsigned int) KernelCopyData);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl2 + (0x25 * 4)), (unsigned int) KernelCopyData);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl3 + (0x25 * 4)), (unsigned int) KernelCopyData);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl4 + (0x25 * 4)), (unsigned int) KernelCopyData);
|
||||||
kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x25 * 4)), (unsigned int)KernelCopyData);
|
kern_write((void *) (OS_SPECIFICS->addr_KernSyscallTbl5 + (0x25 * 4)), (unsigned int) KernelCopyData);
|
||||||
|
|
||||||
//! write our hook to the
|
//! write our hook to the
|
||||||
u32 addr_my_PrepareTitle_hook = ((u32)my_PrepareTitle_hook) | 0x48000003;
|
u32 addr_my_PrepareTitle_hook = ((u32) my_PrepareTitle_hook) | 0x48000003;
|
||||||
DCFlushRange(&addr_my_PrepareTitle_hook, sizeof(addr_my_PrepareTitle_hook));
|
DCFlushRange(&addr_my_PrepareTitle_hook, sizeof(addr_my_PrepareTitle_hook));
|
||||||
|
|
||||||
SC0x25_KernelCopyData((u32)&origPrepareTitleInstr, (u32)addr_PrepareTitle_hook, 4);
|
SC0x25_KernelCopyData((u32) &origPrepareTitleInstr, (u32) addr_PrepareTitle_hook, 4);
|
||||||
SC0x25_KernelCopyData((u32)addr_PrepareTitle_hook, (u32)OSEffectiveToPhysical(&addr_my_PrepareTitle_hook), 4);
|
SC0x25_KernelCopyData((u32) addr_PrepareTitle_hook, (u32) OSEffectiveToPhysical(&addr_my_PrepareTitle_hook), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void KernelRestoreInstructions(void)
|
void KernelRestoreInstructions(void) {
|
||||||
{
|
if (origPrepareTitleInstr != 0)
|
||||||
if(origPrepareTitleInstr != 0)
|
SC0x25_KernelCopyData((u32) addr_PrepareTitle_hook, (u32) &origPrepareTitleInstr, 4);
|
||||||
SC0x25_KernelCopyData((u32)addr_PrepareTitle_hook, (u32)&origPrepareTitleInstr, 4);
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gctypes.h>
|
#include <gctypes.h>
|
||||||
#include "common/kernel_defs.h"
|
|
||||||
#include "../common/kernel_defs.h"
|
#include "../common/kernel_defs.h"
|
||||||
|
|
||||||
void KernelSetupSyscalls(void);
|
void KernelSetupSyscalls(void);
|
||||||
|
22
src/main.c
22
src/main.c
@ -10,21 +10,28 @@
|
|||||||
#include "dynamic_libs/sys_functions.h"
|
#include "dynamic_libs/sys_functions.h"
|
||||||
#include "dynamic_libs/vpad_functions.h"
|
#include "dynamic_libs/vpad_functions.h"
|
||||||
#include "dynamic_libs/socket_functions.h"
|
#include "dynamic_libs/socket_functions.h"
|
||||||
#include "patcher/function_hooks.h"
|
|
||||||
#include "kernel/kernel_functions.h"
|
#include "kernel/kernel_functions.h"
|
||||||
#include "system/memory.h"
|
#include "system/memory.h"
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "code_handler.h"
|
#include "code_handler.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/function_patcher.h"
|
||||||
|
#include "patcher/function_patcher_gx2.h"
|
||||||
|
|
||||||
bool isCodeHandlerInstalled;
|
bool isCodeHandlerInstalled;
|
||||||
|
|
||||||
#define PRINT_TEXT2(x, y, ...) { snprintf(messageBuffer, 80, __VA_ARGS__); OSScreenPutFontEx(0, x, y, messageBuffer); OSScreenPutFontEx(1, x, y, messageBuffer); }
|
#define PRINT_TEXT2(x, y, ...) { snprintf(messageBuffer, 80, __VA_ARGS__); OSScreenPutFontEx(0, x, y, messageBuffer); OSScreenPutFontEx(1, x, y, messageBuffer); }
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EXIT = 0x0, TCP_GECKO = 0x1
|
EXIT,
|
||||||
|
TCP_GECKO
|
||||||
} LaunchMethod;
|
} LaunchMethod;
|
||||||
|
|
||||||
|
void applyFunctionPatches() {
|
||||||
|
patchIndividualMethodHooks(method_hooks_gx2, method_hooks_size_gx2, method_calls_gx2);
|
||||||
|
}
|
||||||
|
|
||||||
/* Entry point */
|
/* Entry point */
|
||||||
int Menu_Main(void) {
|
int Menu_Main(void) {
|
||||||
//!*******************************************************************
|
//!*******************************************************************
|
||||||
@ -37,6 +44,10 @@ int Menu_Main(void) {
|
|||||||
InitVPadFunctionPointers();
|
InitVPadFunctionPointers();
|
||||||
InitSysFunctionPointers();
|
InitSysFunctionPointers();
|
||||||
|
|
||||||
|
log_init(COMPUTER_IP_ADDRESS);
|
||||||
|
log_print("Patching functions\n");
|
||||||
|
applyFunctionPatches();
|
||||||
|
|
||||||
if (strcasecmp("men.rpx", cosAppXmlInfoStruct.rpx_name) == 0) {
|
if (strcasecmp("men.rpx", cosAppXmlInfoStruct.rpx_name) == 0) {
|
||||||
return EXIT_RELAUNCH_ON_LOAD;
|
return EXIT_RELAUNCH_ON_LOAD;
|
||||||
} else if (strlen(cosAppXmlInfoStruct.rpx_name) > 0 &&
|
} else if (strlen(cosAppXmlInfoStruct.rpx_name) > 0 &&
|
||||||
@ -73,7 +84,7 @@ int Menu_Main(void) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
SetupKernelCallback();
|
SetupKernelCallback();
|
||||||
PatchMethodHooks();
|
// PatchMethodHooks();
|
||||||
|
|
||||||
memoryInitialize();
|
memoryInitialize();
|
||||||
|
|
||||||
@ -143,7 +154,8 @@ int Menu_Main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Button pressed ?
|
// 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);
|
usleep(20 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +168,7 @@ int Menu_Main(void) {
|
|||||||
memoryRelease();
|
memoryRelease();
|
||||||
|
|
||||||
if (launchMethod == EXIT) {
|
if (launchMethod == EXIT) {
|
||||||
RestoreInstructions();
|
// RestoreInstructions();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
SYSLaunchMenu();
|
SYSLaunchMenu();
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define COMPUTER_IP_ADDRESS "192.168.2.103"
|
|
||||||
|
|
||||||
//! C wrapper for our C++ functions
|
//! C wrapper for our C++ functions
|
||||||
int Menu_Main(void);
|
int Menu_Main(void);
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "../dynamic_libs/os_functions.h"
|
#include "../dynamic_libs/os_functions.h"
|
||||||
#include "../dynamic_libs/socket_functions.h"
|
#include "../dynamic_libs/socket_functions.h"
|
||||||
#include "function_hooks.h"
|
|
||||||
#include "fs_logger.h"
|
#include "fs_logger.h"
|
||||||
#include "utils/utils.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 EWOULDBLOCK 6
|
||||||
#define DATA_BUFFER_SIZE 0x5000
|
#define DATA_BUFFER_SIZE 0x5000
|
||||||
// #define WRITE_SCREEN_MESSAGE_BUFFER_SIZE 100
|
// #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 ONLY_ZEROS_READ 0xB0
|
||||||
#define NON_ZEROS_READ 0xBD
|
#define NON_ZEROS_READ 0xBD
|
||||||
|
|
||||||
@ -378,7 +378,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
}
|
}
|
||||||
case COMMAND_READ_MEMORY_KERNEL: {
|
case COMMAND_READ_MEMORY_KERNEL: {
|
||||||
const unsigned char *startingAddress, *endingAddress, *useKernRead;
|
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)
|
CHECK_ERROR(ret < 0)
|
||||||
startingAddress = ((const unsigned char **) buffer)[0];
|
startingAddress = ((const unsigned char **) buffer)[0];
|
||||||
endingAddress = ((const unsigned char **) buffer)[1];
|
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
|
// Figure out if all bytes are zero to possibly avoid sending them
|
||||||
int rangeIterationIndex = 0;
|
int rangeIterationIndex = 0;
|
||||||
for (; rangeIterationIndex < length; rangeIterationIndex++) {
|
for (; rangeIterationIndex < length; rangeIterationIndex++) {
|
||||||
int character = useKernRead ? kern_read(startingAddress + rangeIterationIndex)
|
int character = useKernRead ? readKernelMemory(startingAddress + rangeIterationIndex)
|
||||||
: startingAddress[rangeIterationIndex];
|
: startingAddress[rangeIterationIndex];
|
||||||
if (character != 0) {
|
if (character != 0) {
|
||||||
break;
|
break;
|
||||||
@ -407,11 +407,12 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
ret = sendByte(bss, clientfd, ONLY_ZEROS_READ);
|
ret = sendByte(bss, clientfd, ONLY_ZEROS_READ);
|
||||||
CHECK_ERROR(ret < 0)
|
CHECK_ERROR(ret < 0)
|
||||||
} else {
|
} else {
|
||||||
|
// Send the real bytes now
|
||||||
buffer[0] = NON_ZEROS_READ;
|
buffer[0] = NON_ZEROS_READ;
|
||||||
|
|
||||||
if (useKernRead) {
|
if (useKernRead) {
|
||||||
for (int offset = 0; offset < length; offset += 4) {
|
for (int offset = 0; offset < length; offset += sizeof(int)) {
|
||||||
*((int *) (buffer + 1) + offset / 4) = kern_read(startingAddress + offset);
|
*((int *) (buffer + 1) + offset / sizeof(int)) = readKernelMemory(startingAddress + offset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(buffer + 1, startingAddress, length);
|
memcpy(buffer + 1, startingAddress, length);
|
||||||
@ -601,26 +602,26 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
}
|
}
|
||||||
case COMMAND_KERNEL_WRITE: {
|
case COMMAND_KERNEL_WRITE: {
|
||||||
void *ptr, *value;
|
void *ptr, *value;
|
||||||
ret = recvwait(bss, clientfd, buffer, 8);
|
ret = recvwait(bss, clientfd, buffer, sizeof(int) * 2);
|
||||||
CHECK_ERROR(ret < 0)
|
CHECK_ERROR(ret < 0)
|
||||||
|
|
||||||
ptr = ((void **) buffer)[0];
|
ptr = ((void **) buffer)[0];
|
||||||
value = ((void **) buffer)[1];
|
value = ((void **) buffer)[1];
|
||||||
|
|
||||||
kern_write(ptr, (uint32_t) value);
|
writeKernelMemory(ptr, (uint32_t) value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_KERNEL_READ: {
|
case COMMAND_KERNEL_READ: {
|
||||||
void *ptr, *value;
|
void *ptr, *value;
|
||||||
ret = recvwait(bss, clientfd, buffer, 4);
|
ret = recvwait(bss, clientfd, buffer, sizeof(int));
|
||||||
CHECK_ERROR(ret < 0);
|
CHECK_ERROR(ret < 0);
|
||||||
|
|
||||||
ptr = ((void **) buffer)[0];
|
ptr = ((void **) buffer)[0];
|
||||||
|
|
||||||
value = (void *) kern_read(ptr);
|
value = (void *) readKernelMemory(ptr);
|
||||||
|
|
||||||
*(void **) buffer = value;
|
*(void **) buffer = value;
|
||||||
sendwait(bss, clientfd, buffer, 4);
|
sendwait(bss, clientfd, buffer, sizeof(int));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_TAKE_SCREEN_SHOT: {
|
case COMMAND_TAKE_SCREEN_SHOT: {
|
||||||
@ -1271,7 +1272,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
bufferIndex += sizeof(bool);
|
bufferIndex += sizeof(bool);
|
||||||
bool write = buffer[bufferIndex];
|
bool write = buffer[bufferIndex];
|
||||||
bufferIndex += sizeof(bool);
|
bufferIndex += sizeof(bool);
|
||||||
setDataAddressBreakPointRegister(address, read, write);
|
setDataBreakpoint(address, read, write);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1282,7 +1283,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
|
|||||||
|
|
||||||
// Parse the address and set the breakpoint
|
// Parse the address and set the breakpoint
|
||||||
unsigned int address = ((unsigned int *) buffer)[0];
|
unsigned int address = ((unsigned int *) buffer)[0];
|
||||||
setInstructionAddressBreakPointRegister(address);
|
setInstructionBreakpoint(address);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,10 @@ typedef struct OSContext {
|
|||||||
|
|
||||||
#define CPU_STACK_TRACE_DEPTH 10
|
#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; \
|
({ register uint32_t _rval = 0; \
|
||||||
asm volatile("mfspr %0," __stringify(_rn) \
|
asm volatile("mfspr %0," __stringify(spr) \
|
||||||
: "=r" (_rval));\
|
: "=r" (_rval));\
|
||||||
_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
|
#endif
|
||||||
|
|
||||||
#define DEBUG_LOGGER 1
|
#define DEBUG_LOGGER 1
|
||||||
|
#define COMPUTER_IP_ADDRESS "192.168.2.103"
|
||||||
|
|
||||||
#ifdef DEBUG_LOGGER
|
#ifdef DEBUG_LOGGER
|
||||||
void log_init(const char * ip);
|
void log_init(const char * ip);
|
||||||
|
BIN
tcpgecko.elf
BIN
tcpgecko.elf
Binary file not shown.
Loading…
Reference in New Issue
Block a user