Scroll/libserver/src/ffi_util.rs
2025-04-01 02:42:53 +03:00

57 lines
1.6 KiB
Rust

use std::sync::LazyLock;
pub static LIBG_BASE: LazyLock<usize> =
LazyLock::new(|| get_module_base("libg.so").expect("failed to get libg.so base address"));
#[repr(transparent)]
pub struct Nullable<T>(*const T);
impl<T> Nullable<T> {
pub fn get(&self) -> Option<&T> {
(!self.0.is_null()).then(|| unsafe { &*self.0 })
}
pub fn get_mut(&mut self) -> Option<&mut T> {
(!self.0.is_null()).then(|| unsafe { &mut *self.0.cast_mut() })
}
pub fn set(&mut self, value: *const T) {
self.0 = value;
}
}
macro_rules! import {
($name:ident($($arg_name:ident: $arg_type:ty),*) -> $ret_type:ty = $rva:expr) => {
pub fn $name($($arg_name: $arg_type,)*) -> $ret_type {
unsafe {
type FuncType = unsafe extern "cdecl" fn($($arg_type,)*) -> $ret_type;
::std::mem::transmute::<usize, FuncType>(*crate::ffi_util::LIBG_BASE + $rva)($($arg_name,)*)
}
}
};
}
pub(crate) use import;
pub fn get_module_base(shared_object_name: &str) -> Option<usize> {
use std::{
fs::File,
io::{self, BufRead},
};
let file = File::open("/proc/self/maps").expect("failed to open /proc/self/maps");
let reader = io::BufReader::new(file);
for line in reader.lines() {
let line = line.ok()?;
if line.contains(shared_object_name) {
let address_str = line.split_whitespace().next().unwrap_or("");
let address =
usize::from_str_radix(&address_str.split('-').next().unwrap_or(""), 16).ok()?;
return Some(address);
}
}
None
}