mirror of
https://github.com/wiiu-env/FunctionPatcherModule.git
synced 2024-11-17 07:19:23 +01:00
initial commit
This commit is contained in:
commit
edcf2c69b1
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
*.cbp
|
||||
*.elf
|
||||
*.layout
|
||||
*.rpx
|
||||
build/
|
||||
*.save-failed
|
||||
.idea/
|
||||
cmake-build-debug/
|
||||
CMakeLists.txt
|
||||
*.wms
|
142
Makefile
Normal file
142
Makefile
Normal 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
154
source/CThread.h
Normal 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
125
source/defines.h
Normal 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
336
source/function_patcher.cpp
Normal 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
26
source/function_patcher.h
Normal 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
30
source/logger.h
Normal 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
14
source/main.cpp
Normal 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);
|
Loading…
Reference in New Issue
Block a user