Fix kernel memory read crashing sometimes

This commit is contained in:
BullyWiiPlaza 2017-06-02 16:46:14 +02:00
parent 60df33bb23
commit d06770063c
19 changed files with 960 additions and 378 deletions

View File

@ -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

View File

@ -29,6 +29,7 @@ extern "C" {
#endif
#include "gx2_types.h"
#include "../common/fs_defs.h"
void InitGX2FunctionPointers(void);

View File

@ -95,4 +95,4 @@ extern int (*inet_aton)(const char *cp, struct in_addr *inp);
}
#endif
#endif // __SOCKET_FUNCTIONS_H_
#endif

View File

@ -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);
}

View File

@ -6,7 +6,6 @@ extern "C" {
#endif
#include <gctypes.h>
#include "common/kernel_defs.h"
#include "../common/kernel_defs.h"
void KernelSetupSyscalls(void);

View File

@ -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();

View File

@ -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);

View File

@ -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"

View File

@ -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();
}

View File

@ -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 */

View 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")));

View 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
View 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)));
}
}
}

View File

@ -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;
}

View File

@ -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; \
})

View 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;
}

View 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

View File

@ -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);

Binary file not shown.