android_mem_kit/
il2cpp.rs1use std::ffi::{CString, c_void};
2use std::sync::OnceLock;
3
4unsafe extern "C" {
5 fn bridge_xdl_open(filename: *const i8) -> *mut c_void;
6 fn bridge_xdl_sym(handle: *mut c_void, symbol: *const i8) -> *mut c_void;
7}
8
9struct Il2CppHandle(*mut c_void);
11unsafe impl Send for Il2CppHandle {}
12unsafe impl Sync for Il2CppHandle {}
13
14static IL2CPP_HANDLE: OnceLock<Il2CppHandle> = OnceLock::new();
15
16fn get_handle() -> Option<*mut c_void> {
17 let handle_wrapper = IL2CPP_HANDLE.get_or_init(|| {
19 unsafe {
20 let name = CString::new("libil2cpp.so").unwrap();
21 let handle = bridge_xdl_open(name.as_ptr() as *const i8);
22
23 if handle.is_null() {
25 Il2CppHandle(std::ptr::null_mut())
26 } else {
27 Il2CppHandle(handle)
28 }
29 }
30 });
31
32 let ptr = handle_wrapper.0;
34 if ptr.is_null() {
35 None
36 } else {
37 Some(ptr)
38 }
39}
40
41pub fn resolve_export(symbol_name: &str) -> Option<usize> {
42 let handle = get_handle()?; let c_sym = CString::new(symbol_name).ok()?;
45 unsafe {
46 let addr = bridge_xdl_sym(handle, c_sym.as_ptr() as *const i8);
47 if addr.is_null() {
48 None
49 } else {
50 Some(addr as usize)
51 }
52 }
53}
54
55#[macro_export]
56macro_rules! il2cpp_call {
57 ($func_name:expr, $ret:ty, $($arg:expr),*) => {
58 {
59 static CACHED_ADDR: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
60 let mut addr = CACHED_ADDR.load(std::sync::atomic::Ordering::Relaxed);
61
62 if addr == 0 {
63 if let Some(a) = $crate::il2cpp::resolve_export($func_name) {
64 addr = a;
65 CACHED_ADDR.store(addr, std::sync::atomic::Ordering::Relaxed);
66 }
67 }
68
69 if addr != 0 {
70 let func: extern "C" fn($($arg),*) -> $ret = std::mem::transmute(addr);
71 Some(func($($arg),*))
72 } else {
73 None
74 }
75 }
76 };
77}