More Examples
Now that you've made a basic plugin using hooks, here are some concise examples of things you can do with the plugin macros.
Function Hooks
Hooking By Signature
#[hook_signature]
extern "C" fn my_hook(arg1: u32, arg2: f32) -> bool {
// Create the hook at the pointer identified using this signature.
register!("DE AD BE EF ?? ?? ?? ??");
// Call our own hook function again.
my_hook::func(1, 3.5);
// call the original Exanima function, and return the result.
my_hook(arg1, 2.0)
}
Hooking By Signature With Offset
// When the register!() macro finds a pointer, it will add 0x20 (32) bytes to it.
// This also supports negative offsets, e.g. -0x20
#[hook_signature(offset = 0x20)]
extern "C" fn my_hook(arg1: u32, arg2: f32) -> bool {
// Create the hook at the pointer identified using this signature.
register!("DE AD BE EF ?? ?? ?? ??");
// Call our own hook function again.
my_hook::func(1, 3.5);
// call the original Exanima function, and return the result.
my_hook(arg1, 2.0)
}
Hooking By Pointer
#[hook_pointer]
extern "C" fn my_hook(arg1: u32, arg2: f32) -> bool {
// Create the hook at the pointer returned from this macro
register!(
let pointer = "DE AD BE EF ?? ?? ?? ??";
// Find our pointer using whatever method we want, and return it.
emf_rs::Memory::sig_scan(pointer)
);
// Call our own hook function again.
my_hook::func(1, 3.5);
// call the original Exanima function, and return the result.
my_hook(arg1, 2.0)
}
Memory Patching
Patching By Signature
#[patch_signature]
// The `address` argument is the pointer found by the register!() macro.
// It cannot be used inside the register!() macro as it doesn't exist yet at that point.
fn my_patch(address: *mut u8) -> Vec<u8> {
// Apply the patch at the pointer identified using this signature.
register!("DE AD BE EF ?? ?? ?? ??");
// Return these bytes to be used for the patch.
vec![0x1, 0x2, 0x3, 0x90, 0x90, 0x90]
}
Patching By Signature With Offset
// When the register!() macro finds a pointer, it will add 0x20 (32) bytes to it.
// This also supports negative offsets, e.g. -0x20
#[patch_signature(offset = 123)]
// The `address` argument is the pointer found by the register!() macro.
// It cannot be used inside the register!() macro as it doesn't exist yet at that point.
fn my_patch(address: *mut u8) -> Vec<u8> {
// Apply the patch at the pointer identified using this signature, with the offset applied.
register!("DE AD BE EF ?? ?? ?? ??");
// Return these bytes to be used for the patch.
vec![0x1, 0x2, 0x3, 0x90, 0x90, 0x90]
}
Patching By Pointer
#[patch_pointer]
// The `address` argument is the pointer found by the register!() macro.
// It cannot be used inside the register!() macro as it doesn't exist yet at that point.
fn my_patch(address: *mut u8) -> Vec<u8> {
// Apply the patch at the pointer identified using this signature, with the offset applied.
register!(
let signature = "DE AD BE EF ?? ?? ?? ??");
emf_rs::Memory::sig_scan(signature)
);
// Return these bytes to be used for the patch.
vec![0x1, 0x2, 0x3, 0x90, 0x90, 0x90]
}
More things you can do with register!()
Register can be a one-liner
// Patch based on signature
#[patch_signature]
fn my_patch(address: *mut u8) -> Vec<u8> {
// Use the signature
register!("DE AD BE EF ?? ?? ?? ??");
...
}
Register can be as many lines, and as complex as you want
#[patch_pointer]
fn my_patch(address: *mut u8) -> Vec<u8> {
// register!() macro behaves like it's own code block.
register!(
// You can run pretty much anything in here. But try to keep it minimal.
// Plugin initialisation pauses the game until it's complete, so these should be short and sweet.
// You'd never really want to place a random loop like this in here,
// it's just used to show you can treat this like any code block.
for i in 0..16 {
println!("Looped {} times!", i);
}
let signature = "DE AD BE EF ?? ?? ?? ??";
let pointer = emf_rs::Memory::sig_scan(signature);
// Increment the pointer by 0x20 (32) bytes. Negative number also work
let pointer = pointer.byte_offset(0x20);
return pointer;
)
}
You can hardcode pointer for testing
Only do this for testing. Never release a plugin with hard-coded pointers.
// Patch based on hard-coded pointer
#[patch_pointer]
fn my_patch(address: *mut u8) -> Vec<u8> {
// It's only acceptable to hard-code pointers during debugging, testing, and development.
// Never release a plugin with hard-coded pointers!!
register!(0x1234567);
...
}