Skip to main content

libinject/
drcore.rs

1use navigator::cli::LibinjectArgs;
2
3use crate::ffi::{self, _module_handle_t, app_pc, generic_func_t, module_data_t};
4use crate::utils::{Boolean, ReadError, Utf8NameError, WriteError};
5use std::ffi::{CStr, CString};
6use std::os::raw::c_void;
7
8const MAX_LOG_LEN: usize = 2500;
9
10impl Boolean for ffi::bool_ {
11    fn as_bool(self: Self) -> bool {
12        self != 0
13    }
14}
15
16/// Log to the dynamorio stderr (via dr_fprintf). Adding a newline at the end of `s`
17/// and chunking the string if it exceeds a maximum length.
18pub fn log(s: &str) {
19    if s.len() <= MAX_LOG_LEN {
20        return log_helper(s, true);
21    }
22    log_helper(&s[..MAX_LOG_LEN], false);
23    log(&s[MAX_LOG_LEN..]);
24}
25
26fn log_helper(s: &str, newline: bool) {
27    let mut to_log = s.to_owned();
28    if newline {
29        to_log.push_str("\n");
30    }
31    unsafe {
32        let stderr = ffi::dr_get_stderr_file();
33        ffi::dr_fprintf(stderr, CString::new(to_log).unwrap().as_ptr());
34    }
35}
36
37/// Safely read `size` bytes from the address in `ptr`.
38pub fn safe_read(ptr: *mut c_void, size: usize) -> Result<Vec<u8>, ReadError> {
39    let mut buf = vec![0u8; size];
40    let mut bytes_read: usize = 0;
41    unsafe {
42        let success =
43            ffi::dr_safe_read(ptr, size, buf.as_mut_ptr() as *mut c_void, &mut bytes_read)
44                .as_bool();
45        if success {
46            Ok(buf)
47        } else {
48            Err(ReadError {
49                n_bytes_tried: size,
50                n_bytes_read: bytes_read,
51                buf,
52            })
53        }
54    }
55}
56
57/// Safely read `size` bytes from the address in `ptr`.
58pub fn safe_write(target_ptr: *mut c_void, mut to_write: Vec<u8>) -> Result<(), WriteError> {
59    let mut bytes_written: usize = 0;
60    unsafe {
61        let success = ffi::dr_safe_write(
62            target_ptr,
63            to_write.len(),
64            to_write.as_mut_ptr() as *mut c_void,
65            &mut bytes_written,
66        )
67        .as_bool();
68        if success {
69            Ok(())
70        } else {
71            Err(WriteError {
72                n_bytes_tried: to_write.len(),
73                data_tried: to_write,
74                n_bytes_written: bytes_written,
75            })
76        }
77    }
78}
79
80/// Get name of the module, assuming valid utf8.
81pub fn utf8_name_of_module(m: module_data_t) -> Result<String, Utf8NameError> {
82    unsafe {
83        let mod_name_ptr = ffi::dr_module_preferred_name(&m);
84        if mod_name_ptr.is_null() {
85            return Err(Utf8NameError::NullPtr);
86        } else {
87            let cstr_mod_name = CStr::from_ptr(mod_name_ptr);
88            match cstr_mod_name.to_str() {
89                Ok(v) => Ok(v.to_string()),
90                Err(_) => Err(Utf8NameError::Malformed(
91                    cstr_mod_name.to_string_lossy().to_string(),
92                )),
93            }
94        }
95    }
96}
97
98pub unsafe fn get_proc_address(base_addr: app_pc, name: &str) -> generic_func_t {
99    unsafe {
100        ffi::dr_get_proc_address(
101            base_addr as *mut _module_handle_t,
102            CString::new(name).unwrap().as_ptr(),
103        )
104    }
105}
106
107pub unsafe fn app_pc_is_in_target_module(app_pc: *const u8, cli_args: LibinjectArgs) -> bool {
108    unsafe {
109        let module_ptr = ffi::dr_lookup_module(app_pc as *mut u8);
110        if module_ptr.is_null() {
111            return false;
112        }
113
114        let mod_name = match utf8_name_of_module(*module_ptr) {
115            Ok(name) => name,
116            Err(utf8_name_error) => {
117                log(&format!(
118                    "failed to read the module name: {:?}",
119                    utf8_name_error
120                ));
121                return false;
122            }
123        };
124
125        mod_name.to_lowercase() == cli_args.target_module.to_lowercase()
126    }
127}