First iteration of the WUPS-Backend as a .rpx/module for the SetupPayload

- Function replacements are not implemented yet
- Serveral features like the config menu are missing

Still WIP
This commit is contained in:
Maschell
2020-04-29 18:02:36 +02:00
parent a83d11379e
commit 2705a91c13
188 changed files with 7644 additions and 27184 deletions

159
source/utils/ElfUtils.cpp Normal file
View File

@@ -0,0 +1,159 @@
#include <stdio.h>
#include <string.h>
#include <coreinit/cache.h>
#include "utils/logger.h"
#include "elfio/elfio.hpp"
#include "ElfUtils.h"
// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length, RelocationType reloc_type, uint8_t trampolinId) {
if(type == R_PPC_NONE) {
return true;
}
auto target = destination + offset;
auto value = symbol_addr + addend;
auto relValue = value - static_cast<uint32_t>(target);
switch (type) {
case R_PPC_NONE:
break;
case R_PPC_ADDR32:
*((uint32_t *)(target)) = value;
break;
case R_PPC_ADDR16_LO:
*((uint16_t *)(target)) = static_cast<uint16_t>(value & 0xFFFF);
break;
case R_PPC_ADDR16_HI:
*((uint16_t *)(target)) = static_cast<uint16_t>(value >> 16);
break;
case R_PPC_ADDR16_HA:
*((uint16_t *)(target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
break;
case R_PPC_DTPMOD32:
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
//*((int32_t *)(target)) = tlsModuleIndex;
break;
case R_PPC_DTPREL32:
*((uint32_t *)(target)) = value;
break;
case R_PPC_GHS_REL16_HA:
*((uint16_t *)(target)) = static_cast<uint16_t>((relValue + 0x8000) >> 16);
break;
case R_PPC_GHS_REL16_HI:
*((uint16_t *)(target)) = static_cast<uint16_t>(relValue >> 16);
break;
case R_PPC_GHS_REL16_LO:
*((uint16_t *)(target)) = static_cast<uint16_t>(relValue & 0xFFFF);
break;
case R_PPC_REL14: {
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x7FFC || distance < -0x7FFC) {
DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.");
return false;
}
if (distance & 3) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
return false;
}
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
(distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
return false;
}
*(int32_t *)target = (*(int32_t *)target & 0xFFBF0003) | (distance & 0x0000fffc);
break;
}
case R_PPC_REL24: {
// if (isWeakSymbol && !symbolValue) {
// symbolValue = static_cast<uint32_t>(target);
// value = symbolValue + addend;
// }
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
if(trampolin_data == NULL) {
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin isn't provided\n");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
return false;
} else {
relocation_trampolin_entry_t * freeSlot = NULL;
for(uint32_t i = 0; i < trampolin_data_length; i++) {
// We want to override "old" relocations of imports
// Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS.
// When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE
// so they can be overridden/updated/reused on the next application launch.
//
// Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded.
if(trampolin_data[i].status == RELOC_TRAMP_FREE ||
trampolin_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
freeSlot = &(trampolin_data[i]);
break;
}
}
if(freeSlot != NULL) {
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin data list is full\n");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
return false;
}
if(target - (uint32_t)&(freeSlot->trampolin[0]) > 0x1FFFFFC) {
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
return false;
}
DEBUG_FUNCTION_LINE("freeSlot = %08X", freeSlot);
freeSlot->trampolin[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h
freeSlot->trampolin[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
freeSlot->trampolin[2] = 0x7D6903A6; // mtctr r11
freeSlot->trampolin[3] = 0x4E800420; // bctr
DCFlushRange((void*)freeSlot->trampolin, sizeof(freeSlot->trampolin));
ICInvalidateRange((unsigned char*)freeSlot->trampolin, sizeof(freeSlot->trampolin));
freeSlot->id = trampolinId;
DCFlushRange((void*)&freeSlot->id, sizeof(freeSlot->id));
ICInvalidateRange((unsigned char*)&freeSlot->id, sizeof(freeSlot->id));
if(reloc_type == RELOC_TYPE_FIXED) {
freeSlot->status = RELOC_TRAMP_FIXED;
} else {
// Relocations for the imports may be overridden
freeSlot->status = RELOC_TRAMP_IMPORT_IN_PROGRESS;
}
uint32_t symbolValue = (uint32_t)&(freeSlot->trampolin[0]);
value = symbolValue + addend;
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
DEBUG_FUNCTION_LINE("Created tramp\n");
}
}
if (distance & 3) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
return false;
}
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
return false;
}
if (distance >= 0 && (distance & 0xFE000000)) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
return false;
}
*(int32_t *)target = (*(int32_t *)target & 0xfc000003) | (distance & 0x03fffffc);
break;
}
default:
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
return false;
}
return true;
}

50
source/utils/ElfUtils.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#include <stdint.h>
#include "common/relocation_defines.h"
#ifdef __cplusplus
extern "C" {
#endif
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t * sizeOut);
uint32_t load_loader_elf_from_sd(unsigned char* baseAddress, const char* relativePath);
uint32_t load_loader_elf(unsigned char* baseAddress, char * elf_data, uint32_t fileSize);
#define R_PPC_NONE 0
#define R_PPC_ADDR32 1
#define R_PPC_ADDR16_LO 4
#define R_PPC_ADDR16_HI 5
#define R_PPC_ADDR16_HA 6
#define R_PPC_REL24 10
#define R_PPC_REL14 11
#define R_PPC_DTPMOD32 68
#define R_PPC_DTPREL32 78
#define R_PPC_EMB_SDA21 109
#define R_PPC_EMB_RELSDA 116
#define R_PPC_DIAB_SDA21_LO 180
#define R_PPC_DIAB_SDA21_HI 181
#define R_PPC_DIAB_SDA21_HA 182
#define R_PPC_DIAB_RELSDA_LO 183
#define R_PPC_DIAB_RELSDA_HI 184
#define R_PPC_DIAB_RELSDA_HA 185
#define R_PPC_GHS_REL16_HA 251
#define R_PPC_GHS_REL16_HI 252
#define R_PPC_GHS_REL16_LO 253
// Masks for manipulating Power PC relocation targets
#define PPC_WORD32 0xFFFFFFFF
#define PPC_WORD30 0xFFFFFFFC
#define PPC_LOW24 0x03FFFFFC
#define PPC_LOW14 0x0020FFFC
#define PPC_HALF16 0xFFFF
#ifdef __cplusplus
}
#endif
class ElfUtils {
public:
static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length, RelocationType reloc_type, uint8_t trampolinId);
};

View File

@@ -0,0 +1,211 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <vector>
#include <string>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <strings.h>
#include <wut_types.h>
#include <stdio.h>
#include <utils/StringTools.h>
BOOL StringTools::EndsWith(const std::string& a, const std::string& b) {
if (b.size() > a.size())
return false;
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
}
const char * StringTools::byte_to_binary(int32_t x) {
static char b[9];
b[0] = '\0';
int32_t z;
for (z = 128; z > 0; z >>= 1) {
strcat(b, ((x & z) == z) ? "1" : "0");
}
return b;
}
std::string StringTools::removeCharFromString(std::string& input,char toBeRemoved) {
std::string output = input;
size_t position;
while(1) {
position = output.find(toBeRemoved);
if(position == std::string::npos)
break;
output.erase(position, 1);
}
return output;
}
const char * StringTools::fmt(const char * format, ...) {
static char strChar[512];
strChar[0] = 0;
va_list va;
va_start(va, format);
if((vsprintf(strChar, format, va) >= 0)) {
va_end(va);
return (const char *) strChar;
}
va_end(va);
return NULL;
}
const wchar_t * StringTools::wfmt(const char * format, ...) {
static char tmp[512];
static wchar_t strWChar[512];
strWChar[0] = 0;
tmp[0] = 0;
if(!format)
return (const wchar_t *) strWChar;
if(strcmp(format, "") == 0)
return (const wchar_t *) strWChar;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
int bt;
int32_t strlength = strlen(tmp);
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512 );
if(bt > 0) {
strWChar[bt] = 0;
return (const wchar_t *) strWChar;
}
}
va_end(va);
return NULL;
}
int32_t StringTools::strprintf(std::string &str, const char * format, ...) {
static char tmp[512];
tmp[0] = 0;
int32_t result = 0;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
str = tmp;
result = str.size();
}
va_end(va);
return result;
}
std::string StringTools::strfmt(const char * format, ...) {
std::string str;
static char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
str = tmp;
}
va_end(va);
return str;
}
BOOL StringTools::char2wchar_t(const char * strChar, wchar_t * dest) {
if(!strChar || !dest)
return false;
int bt;
bt = mbstowcs(dest, strChar, strlen(strChar));
if (bt > 0) {
dest[bt] = 0;
return true;
}
return false;
}
int32_t StringTools::strtokcmp(const char * string, const char * compare, const char * separator) {
if(!string || !compare)
return -1;
char TokCopy[512];
strncpy(TokCopy, compare, sizeof(TokCopy));
TokCopy[511] = '\0';
char * strTok = strtok(TokCopy, separator);
while (strTok != NULL) {
if (strcasecmp(string, strTok) == 0) {
return 0;
}
strTok = strtok(NULL,separator);
}
return -1;
}
int32_t StringTools::strextcmp(const char * string, const char * extension, char seperator) {
if(!string || !extension)
return -1;
char *ptr = strrchr(string, seperator);
if(!ptr)
return -1;
return strcasecmp(ptr + 1, extension);
}
std::vector<std::string> StringTools::stringSplit(const std::string & inValue, const std::string & splitter) {
std::string value = inValue;
std::vector<std::string> result;
while (true) {
uint32_t index = value.find(splitter);
if (index == std::string::npos) {
result.push_back(value);
break;
}
std::string first = value.substr(0, index);
result.push_back(first);
if (index + splitter.size() == value.length()) {
result.push_back("");
break;
}
if(index + splitter.size() > value.length()) {
break;
}
value = value.substr(index + splitter.size(), value.length());
}
return result;
}

View File

@@ -0,0 +1,80 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef __STRING_TOOLS_H
#define __STRING_TOOLS_H
#include <vector>
#include <string>
#include <wut_types.h>
class StringTools {
public:
static BOOL EndsWith(const std::string& a, const std::string& b);
static const char * byte_to_binary(int32_t x);
static std::string removeCharFromString(std::string& input,char toBeRemoved);
static const char * fmt(const char * format, ...);
static const wchar_t * wfmt(const char * format, ...);
static int32_t strprintf(std::string &str, const char * format, ...);
static std::string strfmt(const char * format, ...);
static BOOL char2wchar_t(const char * src, wchar_t * dest);
static int32_t strtokcmp(const char * string, const char * compare, const char * separator);
static int32_t strextcmp(const char * string, const char * extension, char seperator);
static const char * FullpathToFilename(const char *path) {
if(!path)
return path;
const char * ptr = path;
const char * Filename = ptr;
while(*ptr != '\0') {
if(ptr[0] == '/' && ptr[1] != '\0')
Filename = ptr+1;
++ptr;
}
return Filename;
}
static void RemoveDoubleSlashs(std::string &str) {
uint32_t length = str.size();
//! clear path of double slashes
for(uint32_t i = 1; i < length; ++i) {
if(str[i-1] == '/' && str[i] == '/') {
str.erase(i, 1);
i--;
length--;
}
}
}
static std::vector<std::string> stringSplit(const std::string & value, const std::string & splitter);
};
#endif /* __STRING_TOOLS_H */

View File

@@ -0,0 +1,87 @@
/****************************************************************************
* Copyright (C) 2016-2020 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 <coreinit/dynload.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
#define LIB_AX_OLD 14
#define LIB_PROC_UI 15
#define LIB_NTAG 16
#define LIB_NFP 17
#define LIB_SAVE 18
#define LIB_ACT 19
#define LIB_NIM 20
// functions types
#define STATIC_FUNCTION 0
#define DYNAMIC_FUNCTION 1
//Orignal code by Chadderz.
#define DECL(res, name, ...) \
res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".data"))); \
res my_ ## name(__VA_ARGS__)
#define FUNCTION_PATCHER_METHOD_STORE_SIZE 7
typedef struct {
const uint32_t replaceAddr;
const uint32_t replaceCall;
const uint32_t library;
const char functionName[50];
uint32_t realAddr;
uint32_t restoreInstruction;
uint8_t functionType;
uint8_t alreadyPatched;
} hooks_magic_t;
void PatchInvidualMethodHooks(hooks_magic_t hook_information[],int32_t hook_information_size, volatile uint32_t dynamic_method_calls[]);
void RestoreInvidualInstructions(hooks_magic_t hook_information[],int32_t hook_information_size);
uint32_t GetAddressOfFunction(const char * functionName,uint32_t library);
int32_t isDynamicFunction(uint32_t physicalAddress);
void resetLibs();
//Orignal code by Chadderz.
#define MAKE_MAGIC(x, lib,functionType) { (uint32_t) my_ ## x, (uint32_t) &real_ ## x, lib, # x,0,0,functionType,0}
#define MAKE_MAGIC_NAME(x,y, lib,functionType) { (uint32_t) my_ ## x, (uint32_t) &real_ ## x, lib, # y,0,0,functionType,0}
#ifdef __cplusplus
}
#endif
#endif /* _FS_H */

View File

@@ -0,0 +1,568 @@
/****************************************************************************
* 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 <vector>
#include <algorithm>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <coreinit/memorymap.h>
#include <coreinit/cache.h>
#include <coreinit/dynload.h>
#include "kernel/kernel_utils.h"
#include "function_patcher.h"
#include "logger.h"
#define LIB_CODE_RW_BASE_OFFSET 0xC1000000
#define CODE_RW_BASE_OFFSET 0x00000000
#define DEBUG_LOG_DYN 0
OSDynLoad_Module acp_handle_internal = 0;
OSDynLoad_Module aoc_handle_internal = 0;
OSDynLoad_Module sound_handle_internal = 0;
OSDynLoad_Module sound_handle_internal_old = 0;
OSDynLoad_Module libcurl_handle_internal = 0;
OSDynLoad_Module gx2_handle_internal = 0;
OSDynLoad_Module nfp_handle_internal = 0;
OSDynLoad_Module nn_act_handle_internal = 0;
OSDynLoad_Module nn_nim_handle_internal = 0;
OSDynLoad_Module nn_save_handle_internal = 0;
OSDynLoad_Module ntag_handle_internal = 0;
OSDynLoad_Module coreinit_handle_internal = 0;
OSDynLoad_Module padscore_handle_internal = 0;
OSDynLoad_Module proc_ui_handle_internal = 0;
OSDynLoad_Module nsysnet_handle_internal = 0;
OSDynLoad_Module sysapp_handle_internal = 0;
OSDynLoad_Module syshid_handle_internal = 0;
OSDynLoad_Module vpad_handle_internal = 0;
OSDynLoad_Module vpadbase_handle_internal = 0;
/*
* 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 PatchInvidualMethodHooks(hooks_magic_t method_hooks[],int32_t hook_information_size, volatile uint32_t dynamic_method_calls[]) {
resetLibs();
DEBUG_FUNCTION_LINE("Patching %d given functions",hook_information_size);
/* Patch branches to it. */
volatile uint32_t *space = &dynamic_method_calls[0];
int32_t method_hooks_count = hook_information_size;
uint32_t skip_instr = 1;
uint32_t my_instr_len = 6;
uint32_t instr_len = my_instr_len + skip_instr;
uint32_t flush_len = 4*instr_len;
for(int32_t i = 0; i < method_hooks_count; i++) {
log_printf("Patching %s ...",method_hooks[i].functionName);
if(method_hooks[i].functionType == STATIC_FUNCTION && method_hooks[i].alreadyPatched == 1) {
if(isDynamicFunction((uint32_t)OSEffectiveToPhysical(method_hooks[i].realAddr))) {
log_printf("The function %s is a dynamic function. Please fix that <3", method_hooks[i].functionName);
method_hooks[i].functionType = DYNAMIC_FUNCTION;
} else {
log_printf("Skipping %s, its already patched", method_hooks[i].functionName);
space += instr_len;
continue;
}
}
uint32_t physical = 0;
uint32_t repl_addr = (uint32_t)method_hooks[i].replaceAddr;
uint32_t call_addr = (uint32_t)method_hooks[i].replaceCall;
uint32_t real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library);
if(!real_addr) {
log_printf("");
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s", method_hooks[i].functionName);
space += instr_len;
continue;
}
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("%s is located at %08X!", method_hooks[i].functionName,real_addr);
}
physical = (uint32_t)OSEffectiveToPhysical(real_addr);
if(!physical) {
log_printf("Error. Something is wrong with the physical address");
space += instr_len;
continue;
}
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("%s physical is located at %08X!", method_hooks[i].functionName,physical);
}
*(volatile uint32_t *)(call_addr) = (uint32_t)(space) - CODE_RW_BASE_OFFSET;
uint32_t targetAddr = (uint32_t)space;
if(targetAddr < 0x00800000 || targetAddr >= 0x01000000) {
targetAddr = (uint32_t) OSEffectiveToPhysical(targetAddr);
} else {
targetAddr = targetAddr + 0x30800000 - 0x00800000;
}
KernelCopyData(targetAddr, physical, 4);
ICInvalidateRange((void*)(space), 4);
DCFlushRange((void*)(space), 4);
space++;
//Only works if skip_instr == 1
if(skip_instr == 1) {
// fill the restore instruction section
method_hooks[i].realAddr = real_addr;
method_hooks[i].restoreInstruction = *(space-1);
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("method_hooks[i].realAddr = %08X!", method_hooks[i].realAddr);
}
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("method_hooks[i].restoreInstruction = %08X!",method_hooks[i].restoreInstruction) ;
}
} else {
log_printf("Error. Can't save %s for restoring!", method_hooks[i].functionName);
}
//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 | (((real_addr + (skip_instr * 4)) >> 16) & 0x0000FFFF); // lis r3, real_addr@h
space++;
*space = 0x60630000 | ((real_addr + (skip_instr * 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 - instr_len), flush_len);
ICInvalidateRange((unsigned char*)(space - instr_len), flush_len);
//setting jump back
uint32_t replace_instr = 0x48000002 | (repl_addr & 0x03fffffc);
DCFlushRange(&replace_instr, 4);
KernelCopyData(physical, (uint32_t)OSEffectiveToPhysical((uint32_t)&replace_instr), 4);
ICInvalidateRange((void*)(real_addr), 4);
method_hooks[i].alreadyPatched = 1;
log_printf("done!\n");
}
DEBUG_FUNCTION_LINE("Done with patching given functions!");
}
/* ****************************************************************** */
/* RESTORE ORIGINAL INSTRUCTIONS */
/* ****************************************************************** */
void RestoreInvidualInstructions(hooks_magic_t method_hooks[],int32_t hook_information_size) {
resetLibs();
DEBUG_FUNCTION_LINE("Restoring given functions!");
int32_t method_hooks_count = hook_information_size;
for(int32_t i = 0; i < method_hooks_count; i++) {
DEBUG_FUNCTION_LINE("Restoring %s... ",method_hooks[i].functionName);
if(method_hooks[i].restoreInstruction == 0 || method_hooks[i].realAddr == 0) {
log_printf("I dont have the information for the restore =( skip");
continue;
}
uint32_t real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library);
if(!real_addr) {
log_printf("OSDynLoad_FindExport failed for %s", method_hooks[i].functionName);
continue;
}
uint32_t physical = (uint32_t)OSEffectiveToPhysical(real_addr);
if(!physical) {
log_printf("Something is wrong with the physical address");
continue;
}
if(isDynamicFunction(physical)) {
log_printf("Its a dynamic function. We don't need to restore it!",method_hooks[i].functionName);
} else {
physical = (uint32_t)OSEffectiveToPhysical(method_hooks[i].realAddr); //When its an static function, we need to use the old location
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("Restoring %08X to %08X",(uint32_t)method_hooks[i].restoreInstruction,physical);
}
uint32_t targetAddr = (uint32_t)&method_hooks[i].restoreInstruction;
if(targetAddr < 0x00800000 || targetAddr >= 0x01000000) {
targetAddr = (uint32_t) OSEffectiveToPhysical(targetAddr);
} else {
targetAddr = targetAddr + 0x30800000 - 0x00800000;
}
KernelCopyData(physical,targetAddr, 4);
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("ICInvalidateRange %08X",(void*)method_hooks[i].realAddr);
}
ICInvalidateRange((void*)method_hooks[i].realAddr, 4);
log_printf("done");
}
method_hooks[i].alreadyPatched = 0; // In case a
}
DEBUG_FUNCTION_LINE("Done with restoring given functions!");
}
int32_t isDynamicFunction(uint32_t physicalAddress) {
if((physicalAddress & 0x80000000) == 0x80000000) {
return 1;
}
return 0;
}
uint32_t GetAddressOfFunction(const char * functionName,uint32_t library) {
uint32_t real_addr = 0;
/*
if(strcmp(functionName, "OSDynLoad_Acquire") == 0) {
memcpy(&real_addr, &OSDynLoad_Acquire, 4);
return real_addr;
} else if(strcmp(functionName, "LiWaitOneChunk") == 0) {
real_addr = (uint32_t)addr_LiWaitOneChunk;
return real_addr;
} else if(strcmp(functionName, "LiBounceOneChunk") == 0) {
//! not required on firmwares above 3.1.0
if(OS_FIRMWARE >= 400)
return 0;
uint32_t addr_LiBounceOneChunk = 0x010003A0;
real_addr = (uint32_t)addr_LiBounceOneChunk;
return real_addr;
}
*/
OSDynLoad_Module rpl_handle = 0;
if(library == LIB_CORE_INIT) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_CORE_INIT", functionName);
}
if(coreinit_handle_internal == 0) {
OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle_internal);
}
if(coreinit_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_CORE_INIT failed to acquire");
return 0;
}
rpl_handle = coreinit_handle_internal;
} else if(library == LIB_NSYSNET) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NSYSNET", functionName);
}
if(nsysnet_handle_internal == 0) {
OSDynLoad_Acquire("nsysnet.rpl", &nsysnet_handle_internal);
}
if(nsysnet_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_NSYSNET failed to acquire");
return 0;
}
rpl_handle = nsysnet_handle_internal;
} else if(library == LIB_GX2) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_GX2", functionName);
}
if(gx2_handle_internal == 0) {
OSDynLoad_Acquire("gx2.rpl", &gx2_handle_internal);
}
if(gx2_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_GX2 failed to acquire");
return 0;
}
rpl_handle = gx2_handle_internal;
} else if(library == LIB_AOC) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AOC", functionName);
}
if(aoc_handle_internal == 0) {
OSDynLoad_Acquire("nn_aoc.rpl", &aoc_handle_internal);
}
if(aoc_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_AOC failed to acquire");
return 0;
}
rpl_handle = aoc_handle_internal;
} else if(library == LIB_AX) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AX", functionName);
}
if(sound_handle_internal == 0) {
OSDynLoad_Acquire("sndcore2.rpl", &sound_handle_internal);
}
if(sound_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_AX failed to acquire");
return 0;
}
rpl_handle = sound_handle_internal;
} else if(library == LIB_AX_OLD) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AX_OLD", functionName);
}
if(sound_handle_internal_old == 0) {
OSDynLoad_Acquire("snd_core.rpl", &sound_handle_internal_old);
}
if(sound_handle_internal_old == 0) {
DEBUG_FUNCTION_LINE("LIB_AX_OLD failed to acquire");
return 0;
}
rpl_handle = sound_handle_internal_old;
} else if(library == LIB_FS) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_FS", functionName);
}
if(coreinit_handle_internal == 0) {
OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle_internal);
}
if(coreinit_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_FS failed to acquire");
return 0;
}
rpl_handle = coreinit_handle_internal;
} else if(library == LIB_OS) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_OS", functionName);
}
if(coreinit_handle_internal == 0) {
OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle_internal);
}
if(coreinit_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_OS failed to acquire");
return 0;
}
rpl_handle = coreinit_handle_internal;
} else if(library == LIB_PADSCORE) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_PADSCORE", functionName);
}
if(padscore_handle_internal == 0) {
OSDynLoad_Acquire("padscore.rpl", &padscore_handle_internal);
}
if(padscore_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_PADSCORE failed to acquire");
return 0;
}
rpl_handle = padscore_handle_internal;
} else if(library == LIB_SOCKET) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SOCKET", functionName);
}
if(nsysnet_handle_internal == 0) {
OSDynLoad_Acquire("nsysnet.rpl", &nsysnet_handle_internal);
}
if(nsysnet_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_SOCKET failed to acquire");
return 0;
}
rpl_handle = nsysnet_handle_internal;
} else if(library == LIB_SYS) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SYS", functionName);
}
if(sysapp_handle_internal == 0) {
OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle_internal);
}
if(sysapp_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_SYS failed to acquire");
return 0;
}
rpl_handle = sysapp_handle_internal;
} else if(library == LIB_VPAD) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_VPAD", functionName);
}
if(vpad_handle_internal == 0) {
OSDynLoad_Acquire("vpad.rpl", &vpad_handle_internal);
}
if(vpad_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_VPAD failed to acquire");
return 0;
}
rpl_handle = vpad_handle_internal;
} else if(library == LIB_NN_ACP) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NN_ACP", functionName);
}
if(acp_handle_internal == 0) {
OSDynLoad_Acquire("nn_acp.rpl", &acp_handle_internal);
}
if(acp_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_NN_ACP failed to acquire");
return 0;
}
rpl_handle = acp_handle_internal;
} else if(library == LIB_SYSHID) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SYSHID", functionName);
}
if(syshid_handle_internal == 0) {
OSDynLoad_Acquire("nsyshid.rpl", &syshid_handle_internal);
}
if(syshid_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_SYSHID failed to acquire");
return 0;
}
rpl_handle = syshid_handle_internal;
} else if(library == LIB_VPADBASE) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_VPADBASE", functionName);
}
if(vpadbase_handle_internal == 0) {
OSDynLoad_Acquire("vpadbase.rpl", &vpadbase_handle_internal);
}
if(vpadbase_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_VPADBASE failed to acquire");
return 0;
}
rpl_handle = vpadbase_handle_internal;
} else if(library == LIB_PROC_UI) {
if(DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_PROC_UI", functionName);
}
if(proc_ui_handle_internal == 0) {
OSDynLoad_Acquire("proc_ui.rpl", &proc_ui_handle_internal);
}
if(proc_ui_handle_internal == 0) {
DEBUG_FUNCTION_LINE("LIB_PROC_UI failed to acquire");
return 0;
}
rpl_handle = proc_ui_handle_internal;
} else if(library == LIB_NTAG) {
if(DEBUG_LOG_DYN) {
log_printf("FindExport of %s! From LIB_NTAG", functionName);
}
if(ntag_handle_internal == 0) {
OSDynLoad_Acquire("ntag.rpl", &ntag_handle_internal);
}
if(ntag_handle_internal == 0) {
log_print("LIB_NTAG failed to acquire");
return 0;
}
rpl_handle = ntag_handle_internal;
} else if(library == LIB_NFP) {
if(DEBUG_LOG_DYN) {
log_printf("FindExport of %s! From LIB_NFP", functionName);
}
if(nfp_handle_internal == 0) {
OSDynLoad_Acquire("nn_nfp.rpl", &nfp_handle_internal);
}
if(nfp_handle_internal == 0) {
log_print("LIB_NFP failed to acquire");
return 0;
}
rpl_handle = nfp_handle_internal;
} else if(library == LIB_SAVE) {
if(DEBUG_LOG_DYN) {
log_printf("FindExport of %s! From LIB_SAVE", functionName);
}
if(nn_save_handle_internal == 0) {
OSDynLoad_Acquire("nn_save.rpl", &nn_save_handle_internal);
}
if(nn_save_handle_internal == 0) {
log_print("LIB_SAVE failed to acquire");
return 0;
}
rpl_handle = nn_save_handle_internal;
} else if(library == LIB_ACT) {
if(DEBUG_LOG_DYN) {
log_printf("FindExport of %s! From LIB_ACT", functionName);
}
if(nn_act_handle_internal == 0) {
OSDynLoad_Acquire("nn_act.rpl", &nn_act_handle_internal);
}
if(nn_act_handle_internal == 0) {
log_print("LIB_ACT failed to acquire");
return 0;
}
rpl_handle = nn_act_handle_internal;
} else if(library == LIB_NIM) {
if(DEBUG_LOG_DYN) {
log_printf("FindExport of %s! From LIB_NIM", functionName);
}
if(nn_nim_handle_internal == 0) {
OSDynLoad_Acquire("nn_nim.rpl", &nn_nim_handle_internal);
}
if(nn_nim_handle_internal == 0) {
log_print("LIB_NIM failed to acquire");
return 0;
}
rpl_handle = nn_nim_handle_internal;
}
if(!rpl_handle) {
DEBUG_FUNCTION_LINE("Failed to find the RPL handle for %s", functionName);
return 0;
}
OSDynLoad_FindExport(rpl_handle, 0, functionName, (void**) &real_addr);
if(!real_addr) {
OSDynLoad_FindExport(rpl_handle, 1, functionName, (void**) &real_addr);
if(!real_addr) {
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s", functionName);
return 0;
}
}
if((library == LIB_NN_ACP) && (uint32_t)(*(volatile uint32_t*)(real_addr) & 0x48000002) == 0x48000000) {
uint32_t address_diff = (uint32_t)(*(volatile uint32_t*)(real_addr) & 0x03FFFFFC);
if((address_diff & 0x03000000) == 0x03000000) {
address_diff |= 0xFC000000;
}
real_addr += (int32_t)address_diff;
if((uint32_t)(*(volatile uint32_t*)(real_addr) & 0x48000002) == 0x48000000) {
return 0;
}
}
return real_addr;
}
void resetLibs() {
acp_handle_internal = 0;
aoc_handle_internal = 0;
sound_handle_internal = 0;
sound_handle_internal_old = 0;
libcurl_handle_internal = 0;
gx2_handle_internal = 0;
nfp_handle_internal = 0;
nn_act_handle_internal = 0;
nn_nim_handle_internal = 0;
nn_save_handle_internal = 0;
ntag_handle_internal = 0;
coreinit_handle_internal = 0;
padscore_handle_internal = 0;
proc_ui_handle_internal = 0;
nsysnet_handle_internal = 0;
sysapp_handle_internal = 0;
syshid_handle_internal = 0;
vpad_handle_internal = 0;
vpadbase_handle_internal = 0;
}

82
source/utils/logger.c Normal file
View File

@@ -0,0 +1,82 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <utils/logger.h>
#include <nsysnet/socket.h>
#include <coreinit/debug.h>
#include <coreinit/systeminfo.h>
#include <coreinit/thread.h>
static int log_socket __attribute__((section(".data")))= -1;
static struct sockaddr_in connect_addr __attribute__((section(".data")));
static volatile int log_lock __attribute__((section(".data"))) = 0;
void log_init_() {
int broadcastEnable = 1;
log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (log_socket < 0)
return;
setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
memset(&connect_addr, 0, sizeof(struct sockaddr_in));
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = 4405;
connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
}
void log_print_(const char *str) {
// socket is always 0 initially as it is in the BSS
if(log_socket < 0) {
return;
}
while(log_lock)
OSSleepTicks(OSMicrosecondsToTicks(1000));
log_lock = 1;
int len = strlen(str);
int ret;
while (len > 0) {
int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet
ret = sendto(log_socket, str, block, 0, (struct sockaddr *)&connect_addr, sizeof(struct sockaddr_in));
if(ret < 0)
break;
len -= ret;
str += ret;
}
log_lock = 0;
}
void OSFatal_printf(const char *format, ...) {
char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
OSFatal(tmp);
}
va_end(va);
}
void log_printf_(const char *format, ...) {
if(log_socket < 0) {
return;
}
char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if((vsprintf(tmp, format, va) >= 0)) {
log_print_(tmp);
}
va_end(va);
}

38
source/utils/logger.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef __LOGGER_H_
#define __LOGGER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
void log_init_();
//void log_deinit_(void);
void log_print_(const char *str);
void log_printf_(const char *format, ...);
void OSFatal_printf(const char *format, ...);
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...)do { \
OSFatal_printf("[%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0)
#define log_init() log_init_()
//#define log_deinit() log_deinit_()
#define log_print(str) log_print_(str)
#define log_printf(FMT, ARGS...) log_printf_(FMT, ## ARGS);
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
log_printf("[%23s]%30s@L%04d: " FMT "\n",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0)
#ifdef __cplusplus
}
#endif
#endif

41
source/utils/utils.c Normal file
View File

@@ -0,0 +1,41 @@
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <malloc.h>
#include "utils/logger.h"
// https://gist.github.com/ccbrown/9722406
void dumpHex(const void* data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
log_printf("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char*)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
log_printf(" ");
if ((i+1) % 16 == 0) {
log_printf("| %s \n", ascii);
if(i + 1 < size) {
DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", data + i + 1,i+1);
}
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
log_printf(" ");
}
for (j = (i+1) % 16; j < 16; ++j) {
log_printf(" ");
}
log_printf("| %s \n", ascii);
}
}
}
}

40
source/utils/utils.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef __UTILS_H_
#define __UTILS_H_
#include <malloc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LIMIT(x, min, max) \
({ \
typeof( x ) _x = x; \
typeof( min ) _min = min; \
typeof( max ) _max = max; \
( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \
})
#define DegToRad(a) ( (a) * 0.01745329252f )
#define RadToDeg(a) ( (a) * 57.29577951f )
#define ALIGN4(x) (((x) + 3) & ~3)
#define ALIGN32(x) (((x) + 31) & ~31)
// those work only in powers of 2
#define ROUNDDOWN(val, align) ((val) & ~(align-1))
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align-1)), align)
#define le16(i) ((((uint16_t) ((i) & 0xFF)) << 8) | ((uint16_t) (((i) & 0xFF00) >> 8)))
#define le32(i) ((((uint32_t)le16((i) & 0xFFFF)) << 16) | ((uint32_t)le16(((i) & 0xFFFF0000) >> 16)))
#define le64(i) ((((uint64_t)le32((i) & 0xFFFFFFFFLL)) << 32) | ((uint64_t)le32(((i) & 0xFFFFFFFF00000000LL) >> 32)))
//Needs to have log_init() called beforehand.
void dumpHex(const void* data, size_t size);
#ifdef __cplusplus
}
#endif
#endif // __UTILS_H_