FunctionPatcherModule/source/function_patcher.cpp

129 lines
5.2 KiB
C++
Raw Normal View History

2022-02-03 20:53:38 +01:00
#include "function_patcher.h"
#include "FunctionAddressProvider.h"
#include "PatchedFunctionData.h"
#include "utils/CThread.h"
2022-05-07 23:20:46 +02:00
#include "utils/logger.h"
2020-06-06 22:15:47 +02:00
#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include <coreinit/memorymap.h>
#include <kernel/kernel.h>
#include <memory>
2020-06-06 22:15:47 +02:00
static void writeDataAndFlushIC(CThread *thread, void *arg) {
auto *data = (PatchedFunctionData *) arg;
2020-06-06 22:15:47 +02:00
uint32_t replace_instruction = data->replaceWithInstruction;
uint32_t physical_address = data->realPhysicalFunctionAddress;
uint32_t effective_address = data->realEffectiveFunctionAddress;
2020-06-06 22:15:47 +02:00
DCFlushRange(&replace_instruction, 4);
DCFlushRange(&physical_address, 4);
2022-02-03 20:53:38 +01:00
auto replace_instruction_physical = (uint32_t) &replace_instruction;
2020-06-06 22:15:47 +02:00
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);
}
bool PatchFunction(std::shared_ptr<PatchedFunctionData> &patchedFunction) {
if (patchedFunction->isPatched) {
return true;
}
// The addresses of a function might change every time with run another application.
if (!patchedFunction->updateFunctionAddresses()) {
return true;
}
if (patchedFunction->functionName) {
DEBUG_FUNCTION_LINE("Patching function %s...", patchedFunction->functionName->c_str());
} else {
DEBUG_FUNCTION_LINE("Patching function @ %08X", patchedFunction->realEffectiveFunctionAddress);
}
2020-06-06 22:15:47 +02:00
volatile uint32_t replacedInstruction;
2020-06-06 22:15:47 +02:00
auto targetAddress = (uint32_t) &replacedInstruction;
if (targetAddress < 0x00800000 || targetAddress >= 0x01000000) {
targetAddress = (uint32_t) OSEffectiveToPhysical(targetAddress);
} else {
targetAddress = targetAddress + 0x30800000 - 0x00800000;
2020-06-06 22:15:47 +02:00
}
if (targetAddress == 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to get physical address");
OSFatal("Failed to get physical address");
return false;
}
2020-06-12 21:10:59 +02:00
// Save the instruction we will replace.
KernelCopyData(targetAddress, patchedFunction->realPhysicalFunctionAddress, 4);
DCFlushRange((void *) &replacedInstruction, 4);
patchedFunction->replacedInstruction = replacedInstruction;
// Generate a jump to the original function so the unpatched function can still be called
patchedFunction->generateJumpToOriginal();
// Generate a code that is run when somebody calls the patched function.
// If the correct process calls this, it'll jump the function replacement, otherwise the original function will be called.
patchedFunction->generateReplacementJump();
2020-06-12 21:10:59 +02:00
// Write this->replaceWithInstruction to the first instruction of the function we want to replace.
CThread::runOnAllCores(writeDataAndFlushIC, patchedFunction.get());
2020-06-12 21:10:59 +02:00
// Set patch status
patchedFunction->isPatched = true;
2020-06-12 21:10:59 +02:00
return true;
2020-06-12 21:10:59 +02:00
}
bool RestoreFunction(std::shared_ptr<PatchedFunctionData> &patchedFunction) {
if (!patchedFunction->isPatched) {
DEBUG_FUNCTION_LINE_VERBOSE("Skip restoring function because it's not patched");
2021-09-24 14:49:20 +02:00
return true;
2020-06-06 22:15:47 +02:00
}
if (patchedFunction->replacedInstruction == 0 || patchedFunction->realEffectiveFunctionAddress == 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to restore function, information is missing.");
return false;
2020-06-06 22:15:47 +02:00
}
auto targetAddrPhys = (uint32_t) patchedFunction->realPhysicalFunctionAddress;
2020-06-06 22:15:47 +02:00
if (patchedFunction->library != LIBRARY_OTHER) {
targetAddrPhys = (uint32_t) OSEffectiveToPhysical(patchedFunction->realEffectiveFunctionAddress);
2020-06-06 22:15:47 +02:00
}
if (patchedFunction->isDynamicFunction() &&
// Other processes than the wii u menu and game one seem to keep their rpl's loaded.
patchedFunction->targetProcess != FP_TARGET_PROCESS_GAME_AND_MENU &&
patchedFunction->targetProcess != FP_TARGET_PROCESS_GAME &&
patchedFunction->targetProcess != FP_TARGET_PROCESS_WII_U_MENU) {
DEBUG_FUNCTION_LINE_VERBOSE("Its a dynamic function. We don't need to restore it!");
} else {
DEBUG_FUNCTION_LINE_VERBOSE("Restoring %08X to %08X [%08X]", (uint32_t) patchedFunction->replacedInstruction, patchedFunction->realEffectiveFunctionAddress, targetAddrPhys);
auto sourceAddr = (uint32_t) &patchedFunction->replacedInstruction;
2020-06-06 22:15:47 +02:00
auto sourceAddrPhys = (uint32_t) OSEffectiveToPhysical(sourceAddr);
2020-06-06 22:15:47 +02:00
// These hardcoded values should be replaced with something more dynamic.
if (sourceAddrPhys == 0 && (sourceAddr >= 0x00800000 && sourceAddr < 0x01000000)) {
sourceAddrPhys = sourceAddr + (0x30800000 - 0x00800000);
}
2020-06-06 22:15:47 +02:00
if (sourceAddrPhys == 0) {
OSFatal("Failed to get physical address");
2020-06-06 22:15:47 +02:00
}
KernelCopyData(targetAddrPhys, sourceAddrPhys, 4);
ICInvalidateRange((void *) patchedFunction->realEffectiveFunctionAddress, 4);
DCFlushRange((void *) patchedFunction->realEffectiveFunctionAddress, 4);
2020-06-06 22:15:47 +02:00
}
patchedFunction->isPatched = false;
return true;
2020-06-06 22:15:47 +02:00
}