mnemosyne 0.3.1

a process hooking library
Documentation
use crate::module;

pub struct Detour {
    hook_pointer: u64,
    original_pointer: u64,
    original_bytes: [u8; 12],
    is_hooked: bool,
}

impl Detour {
    pub fn new(original: u64, hook: u64) -> Option<Self> {
        let mut detour = Self {
            hook_pointer: hook,
            original_pointer: original,
            original_bytes: [0; 12],
            is_hooked: false,
        };

        if !detour.save() || !detour.hook() {
            return None;
        }

        Some(detour)
    }

    fn hook(&mut self) -> bool {
        let mut jump = [
            0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0,
        ];

        let hook_address = self.hook_pointer;
        jump[2..10].copy_from_slice(&hook_address.to_le_bytes());

        match module::write(self.original_pointer, &jump) {
            Ok(_) => {
                self.is_hooked = true;
                true
            }

            Err(_) => false,
        }
    }

    pub fn unhook(&mut self) -> bool {
        if self.is_hooked {
            self.is_hooked = false;
            return self.restore();
        }

        true
    }

    fn save(&mut self) -> bool {
        let result = module::read::<[u8; 12]>(self.original_pointer);
        if result.is_none() {
            return false;
        }

        self.original_bytes = result.unwrap();
        true
    }

    fn restore(&self) -> bool {
        module::write(self.original_pointer, &self.original_bytes).is_ok()
    }

    pub fn call_original<R, Args>(&mut self, args: Args) -> Result<R, &str> {
        if !self.unhook() {
            return Err("failed to unhook detour");
        }

        let result = unsafe {
            std::mem::transmute::<_, extern "C" fn(Args) -> R>(self.original_pointer)(args)
        };

        if !self.hook() {
            return Err("failed to re-hook detour");
        }

        Ok(result)
    }
}

impl Default for Detour {
    fn default() -> Self {
        unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() }
    }
}

impl Drop for Detour {
    fn drop(&mut self) {
        if self.hook_pointer == 0 {
            return;
        }

        self.unhook();
    }
}