rosu_mem/
process.rs

1use std::path::PathBuf;
2
3use super::{error::ProcessError, signature::Signature};
4use paste::paste;
5
6#[cfg(target_os = "windows")]
7use windows::Win32::Foundation::HANDLE;
8
9#[derive(Debug)]
10pub struct MemoryRegion {
11    pub from: usize,
12    pub size: usize,
13}
14
15macro_rules! prim_read_impl {
16    ($t: ident) => {
17        paste! {
18            fn [<read_ $t>](
19                &self,
20                addr: i32
21            ) -> Result<$t, ProcessError> {
22                let mut bytes = [0u8; std::mem::size_of::<$t>()];
23                self.read(addr, std::mem::size_of::<$t>(), &mut bytes)?;
24
25                Ok($t::from_le_bytes(bytes))
26            }
27        }
28    };
29}
30
31macro_rules! prim_read_array_impl {
32    ($t: ident) => {
33        paste! {
34            fn [<read_ $t _array>](
35                &self,
36                addr: i32,
37                buff: &mut Vec<$t>
38            ) -> Result<(), ProcessError> {
39                let items_ptr = self.read_i32(addr + 4)?;
40                let size = self.read_i32(addr + 12)? as usize;
41
42                buff.resize(size, 0 as $t);
43
44                let byte_buff = unsafe { std::slice::from_raw_parts_mut(
45                    buff.as_mut_ptr() as *mut u8,
46                    buff.len() * std::mem::size_of::<$t>()
47                ) };
48
49
50                self.read(
51                    items_ptr + 8,
52                    size * std::mem::size_of::<$t>(),
53                    byte_buff
54                )?;
55
56                Ok(())
57            }
58        }
59    };
60}
61
62pub struct Process {
63    #[cfg(target_os = "linux")]
64    pub pid: i32,
65
66    #[cfg(target_os = "windows")]
67    pub pid: u32,
68
69    #[cfg(target_os = "windows")]
70    pub handle: HANDLE,
71
72    pub maps: Vec<MemoryRegion>,
73
74    pub executable_dir: Option<PathBuf>,
75}
76
77pub trait ProcessTraits
78where
79    Self: Sized,
80{
81    /// Initialize a `Process` struct
82    ///
83    /// * `proc_name` - Name of the process or key words
84    /// * `exclude` - Key words to avoid when searching for process name
85    ///
86    /// Notes
87    /// For more details of searching the process name see [`find_process`]
88    /// method
89    fn initialize(
90        proc_name: &str,
91        exclude: &[&str],
92    ) -> Result<Self, ProcessError>;
93
94    /// Attemp to find a process
95    ///
96    /// * `proc_name` - Name of the process or key words
97    /// * `exclude` - Key words to avoid when searching for process name
98    ///
99    /// # Notes
100    /// It's going try to search process name by using `contains` function
101    /// with `proc_name` argument on process name. Same applies to `exclude`
102    fn find_process(
103        proc_name: &str,
104        exclude: &[&str],
105    ) -> Result<Self, ProcessError>;
106
107    fn read_regions(self) -> Result<Self, ProcessError>;
108
109    fn read_signature(&self, sign: &Signature) -> Result<i32, ProcessError>;
110
111    fn read(
112        &self,
113        addr: i32,
114        len: usize,
115        buff: &mut [u8],
116    ) -> Result<(), ProcessError>;
117
118    fn read_uleb128(&self, mut addr: i32) -> Result<u64, ProcessError> {
119        let mut value: u64 = 0;
120        let mut bytes_read = 0;
121
122        loop {
123            let byte = self.read_u8(addr)?;
124            addr += 1;
125
126            let byte_value = (byte & 0b0111_1111) as u64;
127            value |= byte_value << (7 * bytes_read);
128
129            bytes_read += 1;
130
131            if (byte & !0b0111_1111) == 0 {
132                break;
133            }
134        }
135
136        Ok(value)
137    }
138
139    fn read_string(&self, addr: i32) -> Result<String, ProcessError> {
140        let mut addr = self.read_i32(addr)?;
141        // C# string structure: 4B obj header, 4B str len, str itself
142        let len = self.read_u32(addr + 0x4)? as usize;
143        addr += 0x8;
144
145        let mut buff = vec![0u16; len];
146
147        let byte_buff = unsafe {
148            std::slice::from_raw_parts_mut(
149                buff.as_mut_ptr() as *mut u8,
150                buff.len() * 2,
151            )
152        };
153
154        self.read(addr, byte_buff.len(), byte_buff)?;
155
156        Ok(String::from_utf16_lossy(&buff))
157    }
158
159    prim_read_impl!(i8);
160    prim_read_impl!(i16);
161    prim_read_impl!(i32);
162    prim_read_impl!(i64);
163    prim_read_impl!(i128);
164
165    prim_read_impl!(u8);
166    prim_read_impl!(u16);
167    prim_read_impl!(u32);
168    prim_read_impl!(u64);
169    prim_read_impl!(u128);
170
171    prim_read_impl!(f32);
172    prim_read_impl!(f64);
173
174    prim_read_array_impl!(i8);
175    prim_read_array_impl!(i16);
176    prim_read_array_impl!(i32);
177    prim_read_array_impl!(i64);
178    prim_read_array_impl!(i128);
179
180    prim_read_array_impl!(u8);
181    prim_read_array_impl!(u16);
182    prim_read_array_impl!(u32);
183    prim_read_array_impl!(u64);
184    prim_read_array_impl!(u128);
185
186    prim_read_array_impl!(f32);
187    prim_read_array_impl!(f64);
188}