-
Notifications
You must be signed in to change notification settings - Fork 4
SaltySD Code Edits
There are 3 steps to replacing a function:
- Research the function
- Reimplement the function
- Use
SaltySD_function_replace_sym
So first of all you want to locate a function you want to reimplement. In order to do this, you'll need to use a software reverse engineering framework to inspect the game's NSO file. For this I'd recommend GHIDRA with the switch GHIDRA loader.
Editor's note: this replacement won't convince "the game" that we're always in training mode. It only convinces the smash ball, as you can see this function is used by the smash ball to determine its behavior. However, the idea remains the same, and so this should always be considered when replacing a function. - jugeeya
For my example, I'm going to convince the game we're always in training mode. I've found a function called app::smashball::is_training_mode(void) in GHIDRA, here's a small excerpt from the disassembly and decompilation of them offered by GHIDRA:
**************************************************************
* app::smashball::is_training_mode() *
**************************************************************
undefined is_training_mode(void)
undefined w0:1 <RETURN> XREF[1]: 710107aa50(W)
ulonglong x0:8 isTraining XREF[1]: 710107aa50(W)
undefined8 Stack[-0x10]:8 local_10 XREF[2]: 710107a9f0(W),
710107aa64(*)
_ZN3app9smashball16is_training_modeEv XREF[1]: Entry Point(*)
app::smashball::is_training_mode
710107a9f0 fd 7b bf a9 stp x29,x30,[sp, #local_10]!
710107a9f4 fd 03 00 91 mov x29,sp
710107a9f8 48 b4 02 90 adrp x8,0x7106702000
710107a9fc 08 41 1f 91 add x8,x8,#0x7d0
// WARNING: Unknown calling convention yet parameter storage is locked
// app::smashball::is_training_mode()
ulonglong is_training_mode(void)
{
int iVar1;
ulonglong isTraining;
if (((DAT_71067027d0 & 1) == 0) && (iVar1 = FUN_7102ff51d0(&DAT_71067027d0), iVar1 != 0)) {
FUN_7102cf2500();
FUN_71000001c0(&LAB_7102cf22a0,&DAT_71066b56f0,&PTR_ConstantUnitZ_710426e000);
FUN_7102ff51e0(&DAT_71067027d0);
}
isTraining = 1;
if (modeByte_71066b5720 != 0xc) {
isTraining = (ulonglong)(modeByte_71066b5720 == 0x20);
}
return isTraining;
}
Important takeaways from this:
- is_training_mode takes no arguments (void) and returns a ulonglong (aka a 64 bit unsigned integer).
- is_training_mode has a "mangled" name of _ZN3app9smashball16is_training_modeEv
Now, when we reimplement this we need to make sure we match the arguments taken and the return value given, otherwise things will likely break. So our reimplementation should look something like this:
(in our main.c)
uint64_t is_training_mode() {
return 1;
}
In this case, the ulonglong represents a bool, so we return 1 to indicate it is true. Now to tell the framework to replace the game's training mode function with your own just add the following line to main.c
's main() function:
SaltySD_function_replace_sym("_ZN3app9smashball16is_training_modeEv", &is_training_mode);
The first argument is our mangled name, the second is a pointer to the function we want to replace it with.