dobby_api/
lib.rs

1#![deny(clippy::all, clippy::pedantic)]
2#![warn(clippy::nursery)]
3#[allow(non_camel_case_types)]
4// The type alias generated by bindgen does not conform to the rust specification
5pub mod bind;
6mod error;
7
8use std::{
9    ffi::{c_void, CStr, CString},
10    ptr,
11};
12
13pub use error::Error;
14
15/// Memory address
16pub type Address = *mut c_void;
17
18/// Patch the code at target address with supplied bytes
19///
20/// # Errors
21///
22/// Memory Errors
23///
24/// # Safety
25///
26/// Patch may cause the program to crash, so it is unsafe
27#[allow(clippy::missing_panics_doc)]
28#[allow(clippy::as_ptr_cast_mut)]
29pub unsafe fn patch_code(addr: Address, code: &[u8]) -> Result<(), Error> {
30    let ret = match bind::DobbyCodePatch(
31        addr,
32        code.as_ptr().cast_mut(),
33        u32::try_from(code.len()).unwrap(),
34    ) {
35        0 => return Ok(()),
36        1 => Error::MemoryOperationError,
37        2 => Error::NotSupportAllocateExecutableMemory,
38        3 => Error::MemoryOperationErrorNotEnough,
39        4 => Error::MemoryOperationErrorNone,
40        _ => unreachable!(),
41    };
42
43    Err(ret)
44}
45
46/// Replace a function call
47///
48/// # Errors
49///
50/// Failed to apply hook
51///
52/// # Safety
53///
54/// Hook can cause all kinds of undefined behavior, so it's unsafe
55pub unsafe fn hook(
56    target_func_addr: Address,
57    replace_func_addr: Address,
58    ori_func_save: Option<&mut Address>,
59) -> Result<(), Error> {
60    let result = ori_func_save.map_or_else(
61        || bind::DobbyHook(target_func_addr, replace_func_addr, ptr::null_mut()),
62        |save_ptr| bind::DobbyHook(target_func_addr, replace_func_addr, save_ptr),
63    );
64
65    if result == -1 {
66        return Err(Error::FailedToHook);
67    }
68
69    Ok(())
70}
71
72/// Undo the Hook at the specified address
73///
74/// # Errors
75///
76/// Failed to undo hook
77///
78/// # Safety
79///
80/// Hook can cause all kinds of undefined behavior, so it's unsafe
81pub unsafe fn undo_hook(undo_addr: Address) -> Result<(), Error> {
82    if bind::DobbyDestroy(undo_addr) == -1 {
83        Err(Error::FailedToUndoHook)
84    } else {
85        Ok(())
86    }
87}
88
89/// Search for the address of a function by the specified symbol
90///
91/// library: lib name(Or None)
92///
93/// symbol: symbol name(sugg. Try readelf -s /path/to/elf)
94///
95/// It's safe to resolve a address by smybol, though hook is unsafe
96///
97/// # Errors
98///
99/// Func not found
100#[allow(clippy::missing_panics_doc)]
101pub fn resolve_func_addr<S: AsRef<str>>(library: Option<S>, symbol: S) -> Result<Address, Error> {
102    let symbol = symbol.as_ref();
103
104    let addr = unsafe {
105        let symbol = CString::new(symbol).unwrap();
106
107        library.map_or_else(
108            || bind::DobbySymbolResolver(ptr::null(), symbol.as_ptr()),
109            |library| {
110                let library = CString::new(library.as_ref()).unwrap();
111                bind::DobbySymbolResolver(library.as_ptr(), symbol.as_ptr())
112            },
113        )
114    };
115
116    if addr.is_null() {
117        Err(Error::FuncNotFound)
118    } else {
119        Ok(addr)
120    }
121}
122
123/// Get the version of the Dobby lib, not the version of this crate
124#[allow(clippy::missing_panics_doc)]
125#[must_use]
126pub fn get_version() -> &'static str {
127    unsafe { CStr::from_ptr(bind::DobbyGetVersion()).to_str().unwrap() }
128}