libmem 5.1.4

Advanced Game Hacking Library (Windows/Linux/FreeBSD)
use crate::{Address, Process};
use libmem_sys::{lm_address_t, lm_process_t, LM_TRUE};
use std::mem::{transmute_copy, MaybeUninit};

#[derive(Debug)]
pub struct Trampoline {
    pub address: Address,
    pub size: usize,
}

impl Trampoline {
    pub unsafe fn callable<T>(&self) -> T {
        transmute_copy(&self.address)
    }
}

#[derive(Debug)]
pub struct RemoteTrampoline {
    pub address: Address,
    pub size: usize,
}

pub unsafe fn hook_code(from: Address, to: Address) -> Option<Trampoline> {
    let mut tramp_addr: MaybeUninit<lm_address_t> = MaybeUninit::uninit();
    let size = libmem_sys::LM_HookCode(from, to, tramp_addr.as_mut_ptr());

    (size > 0).then_some(Trampoline {
        address: tramp_addr.assume_init(),
        size,
    })
}

pub fn hook_code_ex(process: &Process, from: Address, to: Address) -> Option<RemoteTrampoline> {
    let raw_process: lm_process_t = process.to_owned().into();
    let mut tramp_addr: MaybeUninit<lm_address_t> = MaybeUninit::uninit();
    let size = unsafe {
        libmem_sys::LM_HookCodeEx(
            &raw_process as *const lm_process_t,
            from,
            to,
            tramp_addr.as_mut_ptr(),
        )
    };

    (size > 0).then_some(RemoteTrampoline {
        address: unsafe { tramp_addr.assume_init() },
        size,
    })
}

pub unsafe fn unhook_code(from: Address, trampoline: Trampoline) -> Option<()> {
    (libmem_sys::LM_UnhookCode(from, trampoline.address, trampoline.size) == LM_TRUE).then_some(())
}

pub fn unhook_code_ex(
    process: &Process,
    from: Address,
    trampoline: RemoteTrampoline,
) -> Option<()> {
    let raw_process: lm_process_t = process.to_owned().into();

    (unsafe {
        libmem_sys::LM_UnhookCodeEx(
            &raw_process as *const lm_process_t,
            from,
            trampoline.address,
            trampoline.size,
        )
    } == LM_TRUE)
        .then_some(())
}