2022-02-03 20:53:38 +01:00
# include "function_patcher.h"
2022-05-08 18:51:05 +02:00
# include "FunctionAddressProvider.h"
# include "PatchedFunctionData.h"
# include "utils/CThread.h"
2022-05-07 23:20:46 +02:00
# include "utils/logger.h"
2023-01-02 14:47:19 +01:00
# include "utils/utils.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>
2022-05-08 18:51:05 +02:00
# include <memory>
2020-06-06 22:15:47 +02:00
2022-05-08 18:51:05 +02:00
static void writeDataAndFlushIC ( CThread * thread , void * arg ) {
auto * data = ( PatchedFunctionData * ) arg ;
2020-06-06 22:15:47 +02:00
2022-05-08 18:51:05 +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 ) ;
}
2022-05-08 18:51:05 +02:00
bool PatchFunction ( std : : shared_ptr < PatchedFunctionData > & patchedFunction ) {
2023-01-01 15:37:27 +01:00
if ( patchedFunction - > isPatched ) {
2022-05-08 18:51:05 +02:00
return true ;
2020-12-28 14:45:28 +01:00
}
2020-06-13 13:14:00 +02:00
2023-01-07 23:32:04 +01:00
if ( ! patchedFunction - > shouldBePatched ( ) ) {
return false ;
}
2023-01-01 15:37:27 +01:00
// The addresses of a function might change every time with run another application.
if ( ! patchedFunction - > updateFunctionAddresses ( ) ) {
2023-01-06 14:25:38 +01:00
return false ;
2022-05-08 18:51:05 +02:00
}
2020-06-13 13:59:01 +02:00
2022-05-08 18:51:05 +02:00
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
2023-01-04 22:52:29 +01:00
if ( ! ReadFromPhysicalAddress ( patchedFunction - > realPhysicalFunctionAddress , & patchedFunction - > replacedInstruction ) ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to read instruction. " ) ;
2023-01-06 14:15:59 +01:00
OSFatal ( " FunctionPatcherModule: Failed to read instruction. " ) ;
2022-05-08 18:51:05 +02:00
return false ;
}
2020-06-12 21:10:59 +02:00
2022-05-08 18:51:05 +02:00
// Generate a jump to the original function so the unpatched function can still be called
patchedFunction - > generateJumpToOriginal ( ) ;
2020-08-09 18:02:07 +02:00
2022-05-08 18:51:05 +02:00
// 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
2022-05-08 18:51:05 +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
2022-05-08 18:51:05 +02:00
// Set patch status
patchedFunction - > isPatched = true ;
2020-06-12 21:10:59 +02:00
2022-05-08 18:51:05 +02:00
return true ;
2020-06-12 21:10:59 +02:00
}
2022-05-08 18:51:05 +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
}
2022-05-08 18:51:05 +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
}
2022-05-08 18:51:05 +02:00
auto targetAddrPhys = ( uint32_t ) patchedFunction - > realPhysicalFunctionAddress ;
2020-06-06 22:15:47 +02:00
2022-05-08 18:51:05 +02:00
if ( patchedFunction - > library ! = LIBRARY_OTHER ) {
targetAddrPhys = ( uint32_t ) OSEffectiveToPhysical ( patchedFunction - > realEffectiveFunctionAddress ) ;
2020-06-06 22:15:47 +02:00
}
2023-01-02 14:47:19 +01:00
// Check if patched instruction is still loaded.
uint32_t currentInstruction ;
if ( ! ReadFromPhysicalAddress ( patchedFunction - > realPhysicalFunctionAddress , & currentInstruction ) ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to read instruction. " ) ;
return false ;
}
if ( currentInstruction ! = patchedFunction - > replaceWithInstruction ) {
DEBUG_FUNCTION_LINE_WARN ( " Instruction is different than expected. Skip restoring. Expected: %08X Real: %08X " , currentInstruction , patchedFunction - > replaceWithInstruction ) ;
return false ;
}
2020-06-06 22:15:47 +02:00
2023-01-02 14:47:19 +01:00
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
2023-01-02 14:47:19 +01:00
auto sourceAddrPhys = ( uint32_t ) OSEffectiveToPhysical ( sourceAddr ) ;
2020-06-06 22:15:47 +02:00
2023-01-02 14:47:19 +01:00
// These hardcoded values should be replaced with something more dynamic.
if ( sourceAddrPhys = = 0 & & ( sourceAddr > = 0x00800000 & & sourceAddr < 0x01000000 ) ) {
sourceAddrPhys = sourceAddr + ( 0x30800000 - 0x00800000 ) ;
}
2022-05-08 18:51:05 +02:00
2023-01-02 14:47:19 +01:00
if ( sourceAddrPhys = = 0 ) {
2023-01-06 14:15:59 +01:00
OSFatal ( " FunctionPatcherModule: Failed to get physical address " ) ;
2020-06-06 22:15:47 +02:00
}
2023-01-02 14:47:19 +01:00
KernelCopyData ( targetAddrPhys , sourceAddrPhys , 4 ) ;
ICInvalidateRange ( ( void * ) patchedFunction - > realEffectiveFunctionAddress , 4 ) ;
DCFlushRange ( ( void * ) patchedFunction - > realEffectiveFunctionAddress , 4 ) ;
2022-05-08 18:51:05 +02:00
patchedFunction - > isPatched = false ;
return true ;
2020-06-06 22:15:47 +02:00
}