android_game_hook/
android_game_hook.rs

1use substrate::utils::{get_absolute_address, is_library_loaded, string_to_offset};
2use substrate::MSHookFunction;
3use std::ffi::c_void;
4use std::thread;
5use std::time::Duration;
6
7static mut OLD_UPDATE: *mut c_void = std::ptr::null_mut();
8static mut OLD_FIXED_UPDATE: *mut c_void = std::ptr::null_mut();
9
10#[repr(C)]
11struct UnityObject {
12    vtable: *mut c_void,
13    data: *mut c_void,
14}
15
16unsafe extern "C" fn hooked_update(instance: *mut UnityObject) {
17    println!("[Hook] Update() called - instance: {:p}", instance);
18
19    if !OLD_UPDATE.is_null() {
20        let original: extern "C" fn(*mut UnityObject) = std::mem::transmute(OLD_UPDATE);
21        original(instance);
22    }
23}
24
25unsafe extern "C" fn hooked_fixed_update(instance: *mut UnityObject) {
26    println!("[Hook] FixedUpdate() called - instance: {:p}", instance);
27
28    if !OLD_FIXED_UPDATE.is_null() {
29        let original: extern "C" fn(*mut UnityObject) = std::mem::transmute(OLD_FIXED_UPDATE);
30        original(instance);
31    }
32}
33
34fn wait_for_library(lib_name: &str, timeout_secs: u64) -> bool {
35    let start = std::time::Instant::now();
36    while start.elapsed().as_secs() < timeout_secs {
37        if is_library_loaded(lib_name) {
38            return true;
39        }
40        thread::sleep(Duration::from_millis(100));
41    }
42    false
43}
44
45fn main() {
46    println!("=== Android Game Hook Example (IL2CPP/Unity) ===\n");
47
48    let library = "libil2cpp.so";
49
50    let update_offset_str = "0x123456";
51    let fixed_update_offset_str = "0x789ABC";
52
53    println!("Waiting for {} to load...", library);
54
55    if wait_for_library(library, 30) {
56        println!("✓ {} loaded!", library);
57
58        unsafe {
59            match string_to_offset(update_offset_str) {
60                Ok(update_offset) => {
61                    println!("\nHooking Update() at offset: 0x{:X}", update_offset);
62
63                    match get_absolute_address(library, update_offset) {
64                        Ok(addr) => {
65                            println!("Absolute address: 0x{:x}", addr);
66
67                            MSHookFunction(
68                                addr as *mut c_void,
69                                hooked_update as *mut c_void,
70                                &mut OLD_UPDATE
71                            );
72
73                            if !OLD_UPDATE.is_null() {
74                                println!("✓ Update() hooked successfully!");
75                            }
76                        }
77                        Err(e) => eprintln!("✗ Failed to get address: {}", e),
78                    }
79                }
80                Err(e) => eprintln!("✗ Invalid offset: {}", e),
81            }
82
83            match string_to_offset(fixed_update_offset_str) {
84                Ok(fixed_offset) => {
85                    println!("\nHooking FixedUpdate() at offset: 0x{:X}", fixed_offset);
86
87                    match get_absolute_address(library, fixed_offset) {
88                        Ok(addr) => {
89                            println!("Absolute address: 0x{:x}", addr);
90
91                            MSHookFunction(
92                                addr as *mut c_void,
93                                hooked_fixed_update as *mut c_void,
94                                &mut OLD_FIXED_UPDATE
95                            );
96
97                            if !OLD_FIXED_UPDATE.is_null() {
98                                println!("✓ FixedUpdate() hooked successfully!");
99                            }
100                        }
101                        Err(e) => eprintln!("✗ Failed to get address: {}", e),
102                    }
103                }
104                Err(e) => eprintln!("✗ Invalid offset: {}", e),
105            }
106
107            println!("\n=== Hooks Installed ===");
108            println!("The game functions will now call your hooks.");
109            println!("\nNote: Replace the offset values with real ones from your game!");
110        }
111    } else {
112        eprintln!("✗ Timeout waiting for {} to load", library);
113        eprintln!("\nTo use this example:");
114        eprintln!("1. Find function offsets using IDA Pro, Ghidra, or similar");
115        eprintln!("2. Replace the offset strings with actual values");
116        eprintln!("3. Run as part of an injected library in the game process");
117    }
118}