initial commit

This commit is contained in:
Maschell 2020-06-06 22:15:47 +02:00
commit edcf2c69b1
8 changed files with 837 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
*.cbp
*.elf
*.layout
*.rpx
build/
*.save-failed
.idea/
cmake-build-debug/
CMakeLists.txt
*.wms

142
Makefile Normal file
View File

@ -0,0 +1,142 @@
#-------------------------------------------------------------------------------
.SUFFIXES:
#-------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/wums/share/wums_rules
WUMS_ROOT := $(DEVKITPRO)/wums
WUT_ROOT := $(DEVKITPRO)/wut
#-------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#-------------------------------------------------------------------------------
TARGET := FunctionPatcherModule
BUILD := build
SOURCES := source
DATA := data
INCLUDES := source
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O0 -ffunction-sections\
$(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
CXXFLAGS := $(CFLAGS) -std=c++17
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(WUMSSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := -lwums -lwut -lkernel
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
# containing include and lib
#-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT)
#-------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#-------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#-------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#-------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#-------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#-------------------------------------------------------------------------------
export LD := $(CC)
#-------------------------------------------------------------------------------
else
#-------------------------------------------------------------------------------
export LD := $(CXX)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#-------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#-------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
#-------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#-------------------------------------------------------------------------------
# main targets
#-------------------------------------------------------------------------------
all : $(OUTPUT).wms
$(OUTPUT).wms : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#-------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#-------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#-------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
-include $(DEPENDS)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------

154
source/CThread.h Normal file
View File

@ -0,0 +1,154 @@
/****************************************************************************
* Copyright (C) 2015 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/>.
****************************************************************************/
#pragma once
#include <malloc.h>
#include <unistd.h>
#include <cstdint>
#include <coreinit/thread.h>
class CThread {
public:
typedef void (*Callback)(CThread *thread, void *arg);
//! constructor
CThread(int32_t iAttr, int32_t iPriority = 16, int32_t iStackSize = 0x8000, CThread::Callback callback = NULL, void *callbackArg = NULL)
: pThread(NULL), pThreadStack(NULL), pCallback(callback), pCallbackArg(callbackArg) {
//! save attribute assignment
iAttributes = iAttr;
//! allocate the thread
pThread = (OSThread *) memalign(0x10, sizeof(OSThread));
//! allocate the stack
pThreadStack = (uint8_t *) memalign(0x20, iStackSize);
//! create the thread
if (pThread && pThreadStack) {
OSCreateThread(pThread, (int (*)(int, const char **)) &CThread::threadCallback, 1, (char *) this, (void *) (pThreadStack + iStackSize), iStackSize, iPriority, iAttributes);
}
}
//! destructor
virtual ~CThread() {
shutdownThread();
}
static CThread *create(CThread::Callback callback, void *callbackArg, int32_t iAttr = eAttributeNone, int32_t iPriority = 16, int32_t iStackSize = 0x8000) {
return (new CThread(iAttr, iPriority, iStackSize, callback, callbackArg));
}
static void runOnAllCores(CThread::Callback callback, void *callbackArg, int32_t iAttr = 0, int32_t iPriority = 16, int32_t iStackSize = 0x8000) {
int32_t aff[] = {CThread::eAttributeAffCore2, CThread::eAttributeAffCore1, CThread::eAttributeAffCore0};
for (uint32_t i = 0; i < (sizeof(aff) / sizeof(aff[0])); i++) {
CThread *thread = CThread::create(callback, callbackArg, iAttr | aff[i], iPriority, iStackSize);
thread->resumeThread();
delete thread;
}
}
//! Get thread ID
virtual void *getThread() const {
return pThread;
}
//! Thread entry function
virtual void executeThread(void) {
if (pCallback)
pCallback(this, pCallbackArg);
}
//! Suspend thread
virtual void suspendThread(void) {
if (isThreadSuspended()) return;
if (pThread) OSSuspendThread(pThread);
}
//! Resume thread
virtual void resumeThread(void) {
if (!isThreadSuspended()) return;
if (pThread) OSResumeThread(pThread);
}
//! Set thread priority
virtual void setThreadPriority(int32_t prio) {
if (pThread) OSSetThreadPriority(pThread, prio);
}
//! Check if thread is suspended
virtual bool isThreadSuspended(void) const {
if (pThread) return OSIsThreadSuspended(pThread);
return false;
}
//! Check if thread is terminated
virtual bool isThreadTerminated(void) const {
if (pThread) return OSIsThreadTerminated(pThread);
return false;
}
//! Check if thread is running
virtual bool isThreadRunning(void) const {
return !isThreadSuspended() && !isThreadRunning();
}
//! Gets the thread affinity.
virtual uint16_t getThreadAffinity(void) const {
if (pThread) return OSGetThreadAffinity(pThread);
return 0;
}
//! Shutdown thread
virtual void shutdownThread(void) {
//! wait for thread to finish
if (pThread && !(iAttributes & eAttributeDetach)) {
while (isThreadSuspended()) {
resumeThread();
}
OSJoinThread(pThread, NULL);
}
//! free the thread stack buffer
if (pThreadStack) {
free(pThreadStack);
}
if (pThread) {
free(pThread);
}
pThread = NULL;
pThreadStack = NULL;
}
//! Thread attributes
enum eCThreadAttributes {
eAttributeNone = 0x07,
eAttributeAffCore0 = 0x01,
eAttributeAffCore1 = 0x02,
eAttributeAffCore2 = 0x04,
eAttributeDetach = 0x08,
eAttributePinnedAff = 0x10
};
private:
static int32_t threadCallback(int32_t argc, void *arg) {
//! After call to start() continue with the internal function
((CThread *) arg)->executeThread();
return 0;
}
int32_t iAttributes;
OSThread *pThread;
uint8_t *pThreadStack;
Callback pCallback;
void *pCallbackArg;
};

125
source/defines.h Normal file
View File

@ -0,0 +1,125 @@
#pragma once
typedef enum function_replacement_library_type_t {
LIBRARY_AVM,
LIBRARY_CAMERA,
LIBRARY_COREINIT,
LIBRARY_DC,
LIBRARY_DMAE,
LIBRARY_DRMAPP,
LIBRARY_ERREULA,
LIBRARY_GX2,
LIBRARY_H264,
LIBRARY_LZMA920,
LIBRARY_MIC,
LIBRARY_NFC,
LIBRARY_NIO_PROF,
LIBRARY_NLIBCURL,
LIBRARY_NLIBNSS,
LIBRARY_NLIBNSS2,
LIBRARY_NN_AC,
LIBRARY_NN_ACP,
LIBRARY_NN_ACT,
LIBRARY_NN_AOC,
LIBRARY_NN_BOSS,
LIBRARY_NN_CCR,
LIBRARY_NN_CMPT,
LIBRARY_NN_DLP,
LIBRARY_NN_EC,
LIBRARY_NN_FP,
LIBRARY_NN_HAI,
LIBRARY_NN_HPAD,
LIBRARY_NN_IDBE,
LIBRARY_NN_NDM,
LIBRARY_NN_NETS2,
LIBRARY_NN_NFP,
LIBRARY_NN_NIM,
LIBRARY_NN_OLV,
LIBRARY_NN_PDM,
LIBRARY_NN_SAVE,
LIBRARY_NN_SL,
LIBRARY_NN_SPM,
LIBRARY_NN_TEMP,
LIBRARY_NN_UDS,
LIBRARY_NN_VCTL,
LIBRARY_NSYSCCR,
LIBRARY_NSYSHID,
LIBRARY_NSYSKBD,
LIBRARY_NSYSNET,
LIBRARY_NSYSUHS,
LIBRARY_NSYSUVD,
LIBRARY_NTAG,
LIBRARY_PADSCORE,
LIBRARY_PROC_UI,
LIBRARY_SND_CORE,
LIBRARY_SND_USER,
LIBRARY_SNDCORE2,
LIBRARY_SNDUSER2,
LIBRARY_SWKBD,
LIBRARY_SYSAPP,
LIBRARY_TCL,
LIBRARY_TVE,
LIBRARY_UAC,
LIBRARY_UAC_RPL,
LIBRARY_USB_MIC,
LIBRARY_UVC,
LIBRARY_UVD,
LIBRARY_VPAD,
LIBRARY_VPADBASE,
LIBRARY_ZLIB125,
LIBRARY_OTHER,
} function_replacement_library_type_t;
#define MAXIMUM_FUNCTION_NAME_LENGTH 100
#define FUNCTION_PATCHER_METHOD_STORE_SIZE 20
#define STATIC_FUNCTION 0
#define DYNAMIC_FUNCTION 1
typedef struct function_replacement_data_t {
uint32_t physicalAddr; /* [needs to be filled] */
uint32_t virtualAddr; /* [needs to be filled] */
uint32_t replaceAddr; /* [needs to be filled] Address of our replacement function */
uint32_t replaceCall; /* [needs to be filled] Address to access the real_function */
function_replacement_library_type_t library; /* [needs to be filled] rpl where the function we want to replace is. */
char function_name[MAXIMUM_FUNCTION_NAME_LENGTH]; /* [needs to be filled] name of the function we want to replace */
uint32_t realAddr; /* [will be filled] Address of the real function we want to replace. */
volatile uint32_t replace_data [FUNCTION_PATCHER_METHOD_STORE_SIZE]; /* [will be filled] Space for us to store some jump instructions */
uint32_t restoreInstruction; /* [will be filled] Copy of the instruction we replaced to jump to our code. */
uint8_t functionType; /* [will be filled] */
uint8_t alreadyPatched; /* [will be filled] */
} function_replacement_data_t;
#define REPLACE_FUNCTION(x, lib, function_name) \
{ \
0, \
0, \
(uint32_t) my_ ## x, \
(uint32_t) &real_ ## x \
lib, \
# function_name, \
0, \
{}, \
0, \
functionType, \
0 \
}
#define REPLACE_FUNCTION_VIA_ADDRESS(x, physicalAddress, effectiveAddress) \
{ \
physicalAddress, \
effectiveAddress, \
(uint32_t) my_ ## x, \
(uint32_t) &real_ ## x \
LIBRARY_OTHER, \
# x, \
0, \
{}, \
0, \
functionType, \
0 \
}
#define DECL_FUNCTION(res, name, ...) \
res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".data"))); \
res my_ ## name(__VA_ARGS__)

336
source/function_patcher.cpp Normal file
View File

@ -0,0 +1,336 @@
#include <coreinit/dynload.h>
#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include <coreinit/memorymap.h>
#include <kernel/kernel.h>
#include "defines.h"
#include "function_patcher.h"
#include "logger.h"
#include "CThread.h"
#define DEBUG_LOG_DYN 1
void writeDataAndFlushIC(CThread *thread, void *arg) {
uint32_t *data = (uint32_t *) arg;
uint16_t core = OSGetThreadAffinity(OSGetCurrentThread());
DCFlushRange(data, sizeof(uint32_t) * 3);
uint32_t replace_instruction = data[0];
uint32_t physical_address = data[1];
uint32_t effective_address = data[2];
DCFlushRange(&replace_instruction, 4);
DCFlushRange(&physical_address, 4);
DEBUG_FUNCTION_LINE("Write instruction %08X to %08X [%08X] on core %d", replace_instruction, effective_address, physical_address, core / 2);
uint32_t replace_instruction_physical = (uint32_t) &replace_instruction;
if (replace_instruction_physical < 0x00800000 || replace_instruction_physical >= 0x01000000) {
replace_instruction_physical = OSEffectiveToPhysical(replace_instruction_physical);
} else {
replace_instruction_physical = replace_instruction_physical + 0x30800000 - 0x00800000;
}
KernelCopyData(physical_address, replace_instruction_physical, 4);
ICInvalidateRange((void *) (effective_address), 4);
}
void FunctionPatcherPatchFunction(function_replacement_data_t *replacements, uint32_t size) {
uint32_t skip_instr = 1;
uint32_t my_instr_len = 4;
uint32_t instr_len = my_instr_len + skip_instr + 15;
uint32_t flush_len = 4 * instr_len;
for (uint32_t i = 0; i < size; i++) {
function_replacement_data_t *function_data = &replacements[i];
/* Patch branches to it. */
volatile uint32_t *space = function_data->replace_data;
DEBUG_FUNCTION_LINE_WRITE("Patching %s ...", function_data->function_name);
if (function_data->library == LIBRARY_OTHER) {
WHBLogWritef("Oh, using straight PA/VA");
if (function_data->alreadyPatched == 1) {
DEBUG_FUNCTION_LINE("Skipping %s, its already patched", function_data->function_name);
continue;
}
} else {
if (function_data->functionType == STATIC_FUNCTION && function_data->alreadyPatched == 1) {
if (isDynamicFunction((uint32_t) OSEffectiveToPhysical(function_data->realAddr))) {
DEBUG_FUNCTION_LINE("INFO: The function %s is a dynamic function.", function_data->function_name);
function_data->functionType = DYNAMIC_FUNCTION;
} else {
WHBLogWritef("Skipping %s, its already patched", function_data->function_name);
continue;
}
}
}
uint32_t physical = function_data->physicalAddr;
uint32_t repl_addr = (uint32_t) function_data->replaceAddr;
uint32_t call_addr = (uint32_t) function_data->replaceCall;
uint32_t real_addr = function_data->virtualAddr;
if (function_data->library != LIBRARY_OTHER) {
real_addr = getAddressOfFunction(function_data->function_name, function_data->library);
}
if (!real_addr) {
WHBLogWritef("");
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s", function_data->function_name);
continue;
}
if (DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("%s is located at %08X!", function_data->function_name, real_addr);
}
if (function_data->library != LIBRARY_OTHER) {
physical = (uint32_t) OSEffectiveToPhysical(real_addr);
}
if (!physical) {
WHBLogWritef("Error. Something is wrong with the physical address");
continue;
}
if (DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("%s physical is located at %08X!", function_data->function_name, physical);
}
*(volatile uint32_t *) (call_addr) = (uint32_t) (space);
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
function_data->realAddr = real_addr;
function_data->restoreInstruction = space[-1];
if (DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("function_data->realAddr = %08X!", function_data->realAddr);
}
if (DEBUG_LOG_DYN) {
DEBUG_FUNCTION_LINE("function_data->restoreInstruction = %08X!", function_data->restoreInstruction);
}
} else {
WHBLogWritef("Error. Can't save %s for restoring!", function_data->function_name);
}
/*
00808cfc 3d601234 lis r11 ,0x1234
00808d00 616b5678 ori r11 ,r11 ,0x5678
00808d04 7d6903a6 mtspr CTR ,r11
00808d08 4e800420 bctr
*/
*space = 0x3d600000 | (((real_addr + (skip_instr * 4)) >> 16) & 0x0000FFFF);
space++; // lis r11 ,0x1234
*space = 0x616b0000 | ((real_addr + (skip_instr * 4)) & 0x0000ffff);
space++; // ori r11 ,r11 ,0x5678
*space = 0x7d6903a6;
space++; // mtspr CTR ,r11
*space = 0x4e800420;
space++;
uint32_t repl_addr_test = (uint32_t) space;
/*
// Only use patched function if OSGetUPID is 2 (wii u menu) or 15 (game)
*space = 0x3d600000 | (((uint32_t*) OSGetUPID)[0] & 0x0000FFFF); space++; // lis r11 ,0x0
*space = 0x816b0000 | (((uint32_t*) OSGetUPID)[1] & 0x0000FFFF); space++; // lwz r11 ,0x0(r11)
*space = 0x2c0b0000 | 0x00000002; space++; // cmpwi r11 ,0x2
*space = 0x41820000 | 0x00000020; space++; // beq myfunc
*space = 0x2c0b0000 | 0x0000000F; space++; // cmpwi r11 ,0xF
*space = 0x41820000 | 0x00000018; space++; // beq myfunc
*space = 0x3d600000 | (((real_addr + (skip_instr * 4)) >> 16) & 0x0000FFFF); space++; // lis r11 ,0x1234
*space = 0x616b0000 | ((real_addr + (skip_instr * 4)) & 0x0000ffff); space++; // ori r11 ,r11 ,0x5678
*space = 0x7d6903a6; space++; // mtspr CTR ,r11
*space = function_data->restoreInstruction; space++; //
*space = 0x4e800420; space++; // bctr*/
// myfunc:
*space = 0x3d600000 | (((repl_addr) >> 16) & 0x0000FFFF);
space++; // lis r11 ,0x1234
*space = 0x616b0000 | ((repl_addr) & 0x0000ffff);
space++; // ori r11 ,r11 ,0x5678
*space = 0x7d6903a6;
space++; // mtspr CTR ,r11
*space = 0x4e800420;
space++; // bctr
DCFlushRange((void *) (((uint32_t) space) - flush_len), flush_len);
ICInvalidateRange((void *) (((uint32_t) space) - flush_len), flush_len);
if ((repl_addr_test & 0x03fffffc) != repl_addr_test) {
OSFatal("Jump is impossible");
}
//setting jump back
uint32_t replace_instr = 0x48000002 | (repl_addr_test & 0x03fffffc);
uint32_t data[] = {
replace_instr,
physical,
real_addr
};
CThread::runOnAllCores(writeDataAndFlushIC, data);
function_data->alreadyPatched = 1;
DEBUG_FUNCTION_LINE("done with patching %s!", function_data->function_name);
}
DEBUG_FUNCTION_LINE("Done with patching given functions!");
}
bool isDynamicFunction(uint32_t physicalAddress) {
if ((physicalAddress & 0x80000000) == 0x80000000) {
return 1;
}
return 0;
}
rpl_handling rpl_handles[] __attribute__((section(".data"))) = {
{LIBRARY_AVM, "avm.rpl", 0},
{LIBRARY_CAMERA, "camera.rpl", 0},
{LIBRARY_COREINIT, "coreinit.rpl", 0},
{LIBRARY_DC, "dc.rpl", 0},
{LIBRARY_DMAE, "dmae.rpl", 0},
{LIBRARY_DRMAPP, "drmapp.rpl", 0},
{LIBRARY_ERREULA, "erreula.rpl", 0},
{LIBRARY_GX2, "gx2.rpl", 0},
{LIBRARY_H264, "h264.rpl", 0},
{LIBRARY_LZMA920, "lzma920.rpl", 0},
{LIBRARY_MIC, "mic.rpl", 0},
{LIBRARY_NFC, "nfc.rpl", 0},
{LIBRARY_NIO_PROF, "nio_prof.rpl", 0},
{LIBRARY_NLIBCURL, "nlibcurl.rpl", 0},
{LIBRARY_NLIBNSS, "nlibnss.rpl", 0},
{LIBRARY_NLIBNSS2, "nlibnss2.rpl", 0},
{LIBRARY_NN_AC, "nn_ac.rpl", 0},
{LIBRARY_NN_ACP, "nn_acp.rpl", 0},
{LIBRARY_NN_ACT, "nn_act.rpl", 0},
{LIBRARY_NN_AOC, "nn_aoc.rpl", 0},
{LIBRARY_NN_BOSS, "nn_boss.rpl", 0},
{LIBRARY_NN_CCR, "nn_ccr.rpl", 0},
{LIBRARY_NN_CMPT, "nn_cmpt.rpl", 0},
{LIBRARY_NN_DLP, "nn_dlp.rpl", 0},
{LIBRARY_NN_EC, "nn_ec.rpl", 0},
{LIBRARY_NN_FP, "nn_fp.rpl", 0},
{LIBRARY_NN_HAI, "nn_hai.rpl", 0},
{LIBRARY_NN_HPAD, "nn_hpad.rpl", 0},
{LIBRARY_NN_IDBE, "nn_idbe.rpl", 0},
{LIBRARY_NN_NDM, "nn_ndm.rpl", 0},
{LIBRARY_NN_NETS2, "nn_nets2.rpl", 0},
{LIBRARY_NN_NFP, "nn_nfp.rpl", 0},
{LIBRARY_NN_NIM, "nn_nim.rpl", 0},
{LIBRARY_NN_OLV, "nn_olv.rpl", 0},
{LIBRARY_NN_PDM, "nn_pdm.rpl", 0},
{LIBRARY_NN_SAVE, "nn_save.rpl", 0},
{LIBRARY_NN_SL, "nn_sl.rpl", 0},
{LIBRARY_NN_SPM, "nn_spm.rpl", 0},
{LIBRARY_NN_TEMP, "nn_temp.rpl", 0},
{LIBRARY_NN_UDS, "nn_uds.rpl", 0},
{LIBRARY_NN_VCTL, "nn_vctl.rpl", 0},
{LIBRARY_NSYSCCR, "nsysccr.rpl", 0},
{LIBRARY_NSYSHID, "nsyshid.rpl", 0},
{LIBRARY_NSYSKBD, "nsyskbd.rpl", 0},
{LIBRARY_NSYSNET, "nsysnet.rpl", 0},
{LIBRARY_NSYSUHS, "nsysuhs.rpl", 0},
{LIBRARY_NSYSUVD, "nsysuvd.rpl", 0},
{LIBRARY_NTAG, "ntag.rpl", 0},
{LIBRARY_PADSCORE, "padscore.rpl", 0},
{LIBRARY_PROC_UI, "proc_ui.rpl", 0},
{LIBRARY_SNDCORE2, "sndcore2.rpl", 0},
{LIBRARY_SNDUSER2, "snduser2.rpl", 0},
{LIBRARY_SND_CORE, "snd_core.rpl", 0},
{LIBRARY_SND_USER, "snd_user.rpl", 0},
{LIBRARY_SWKBD, "swkbd.rpl", 0},
{LIBRARY_SYSAPP, "sysapp.rpl", 0},
{LIBRARY_TCL, "tcl.rpl", 0},
{LIBRARY_TVE, "tve.rpl", 0},
{LIBRARY_UAC, "uac.rpl", 0},
{LIBRARY_UAC_RPL, "uac_rpl.rpl", 0},
{LIBRARY_USB_MIC, "usb_mic.rpl", 0},
{LIBRARY_UVC, "uvc.rpl", 0},
{LIBRARY_UVD, "uvd.rpl", 0},
{LIBRARY_VPAD, "vpad.rpl", 0},
{LIBRARY_VPADBASE, "vpadbase.rpl", 0},
{LIBRARY_ZLIB125, "zlib125.rpl", 0}
};
uint32_t getAddressOfFunction(char *functionName, function_replacement_library_type_t library) {
uint32_t real_addr = 0;
OSDynLoad_Module rpl_handle = 0;
int32_t rpl_handles_size = sizeof rpl_handles / sizeof rpl_handles[0];
for (int32_t i = 0; i < rpl_handles_size; i++) {
if (rpl_handles[i].library == library) {
if (rpl_handles[i].handle == 0) {
DEBUG_FUNCTION_LINE("Lets acquire handle for rpl: %s", rpl_handles[i].rplname);
OSDynLoad_Acquire((char *) rpl_handles[i].rplname, &rpl_handles[i].handle);
}
if (rpl_handles[i].handle == 0) {
WHBLogWritef("%s failed to acquire", rpl_handles[i].rplname);
return 0;
}
rpl_handle = rpl_handles[i].handle;
break;
}
}
if (!rpl_handle) {
DEBUG_FUNCTION_LINE("Failed to find the RPL handle for %s", functionName);
return 0;
}
OSDynLoad_FindExport(rpl_handle, 0, functionName, reinterpret_cast<void **>(&real_addr));
if (!real_addr) {
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s", functionName);
return 0;
}
if ((library == LIBRARY_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 FunctionPatcherResetLibHandles() {
int32_t rpl_handles_size = sizeof rpl_handles / sizeof rpl_handles[0];
for (int32_t i = 0; i < rpl_handles_size; i++) {
if (rpl_handles[i].handle != 0) {
DEBUG_FUNCTION_LINE("Resetting handle for rpl: %s", rpl_handles[i].rplname);
}
rpl_handles[i].handle = 0;
// Release handle?
}
}

26
source/function_patcher.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "defines.h"
#include <coreinit/dynload.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rpl_handling {
function_replacement_library_type_t library;
const char rplname[15];
OSDynLoad_Module handle;
} rpl_handling;
void FunctionPatcherPatchFunction(function_replacement_data_t *replacements, uint32_t size);
void FunctionPatcherResetLibHandles();
uint32_t getAddressOfFunction(char * functionName, function_replacement_library_type_t type);
bool isDynamicFunction(uint32_t physicalAddress);
#ifdef __cplusplus
}
#endif

30
source/logger.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __LOGGER_H_
#define __LOGGER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <whb/log.h>
#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 DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0);
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \
WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0);
#ifdef __cplusplus
}
#endif
#endif

14
source/main.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <wums.h>
#include <whb/log_udp.h>
#include "function_patcher.h"
WUMS_MODULE_EXPORT_NAME("homebrew_functionpatcher");
WUMS_INITIALIZE(){
WHBLogUdpInit();
}
WUMS_APPLICATION_STARTS() {
FunctionPatcherResetLibHandles();
}
WUMS_EXPORT_FUNCTION(FunctionPatcherPatchFunction);