proc_mem_rs/process/
module.rs

1use regex::bytes::Regex;
2
3use crate::ProcMemError;
4
5/// contains info needed to find the byte pattern in memory
6pub struct Signature {
7    pub name: String,
8    pub pattern: String,
9    /// signature offsets for dereferencing
10    pub offsets: Vec<isize>,
11    /// added to the result
12    pub extra: isize,
13    /// get the address relative to the module
14    pub relative: bool,
15    /// read u32 at found address and add it to the result
16    pub rip_relative: bool,
17    /// added to the rip result
18    pub rip_offset: isize,
19}
20
21/// contains info about the module and its content in bytes
22#[derive(Debug)]
23pub struct Module {
24    module_name: String,
25    module_path: String,
26    process_id: u32,
27    process_iswow64: bool,
28    module_baseaddr: usize,
29    module_basesize: usize,
30    module_data: Vec<u8>
31}
32
33impl Module {
34    pub fn new(mname: String, mpath: String, pid: u32, mbaseaddr: usize, mbasesize: usize, proc: &crate::Process) -> Self {
35        Module { 
36            module_name: mname,
37            module_path: mpath, 
38            process_id: pid,
39            process_iswow64: proc.iswow64(), 
40            module_baseaddr: mbaseaddr, 
41            module_basesize: mbasesize,
42            module_data: proc.read_module(mbaseaddr, mbasesize).unwrap_or_default(),
43        }
44    }
45
46    pub fn name(&self) -> &str {&self.module_name}
47    pub fn path(&self) -> &str {&self.module_path}
48    pub fn pid(&self) -> &u32 {&self.process_id}
49    pub fn base_address(&self) -> usize {self.module_baseaddr}
50    pub fn base_size(&self) -> &usize {&self.module_basesize}
51    pub fn data(&self) -> &Vec<u8>{&self.module_data}
52
53    pub fn get_raw<T: Copy>(&self, mut o: usize, is_relative: bool) -> Option<T> {
54        if !is_relative {
55            o -= self.module_baseaddr;
56        }
57        if o + std::mem::size_of::<T>() >= self.module_data.len() {
58            return None;
59        }
60        let ptr = self.module_data.get(o)?;
61        let raw: T = unsafe { std::mem::transmute_copy(ptr) };
62        Some(raw)
63    }
64
65
66    /// This functions finds an address in memory based on the provided [`Signature`]
67    /// ```rust
68    /// use proc_mem_rs::{Process, Module, Signature, ProcMemError};
69    /// let some_game: Result<Process,ProcMemError> = Process::with_name("some_game.exe");
70    /// let module: Result<Module,ProcMemError> = some_game.module("module.dll");
71    /// let lp_signature = Signature {
72    ///     name: "LocalPlayer",
73    ///     pattern: "8D 34 85 ? ? ? ? 89 15 ? ? ? ? 8B 41 08 8B 48 04 83 F9 FF",
74    ///     offsets: vec![3],
75    ///     extra: 4,
76    ///     relative: true,
77    ///     rip_relative: false,
78    ///     rip_offset: 0,
79    /// };
80    /// let lp_address: Result<usize,ProcMemError> = module.find_signature(&lp_signature);
81    /// ``` 
82    pub fn find_signature(&self, sig: &Signature) -> Result<usize, ProcMemError> {
83        let mut addr = Self::find_pattern(&self.module_data,&sig.pattern).ok_or(ProcMemError::SignatureNotFound)?;
84        
85        for (_i,o) in sig.offsets.iter().enumerate() {
86            let pos = (addr as isize).wrapping_add(*o) as usize;
87            let data = self.module_data.get(pos).ok_or_else(|| {
88                ProcMemError::AddressOutOfBounds
89            })?;
90            let tmp = if self.process_iswow64 {
91                let raw: u32 = unsafe {(data as *const u8).cast::<u32>().read_unaligned()};
92                raw as usize
93            } else {
94                let raw: u64 = unsafe {(data as *const u8).cast::<u64>().read_unaligned()};
95                raw as usize
96            };
97
98            addr = tmp.wrapping_sub(self.module_baseaddr);
99        }
100
101        if sig.rip_relative {
102            addr = (addr as isize).wrapping_add(sig.rip_offset) as usize;
103    
104            let rip: u32 = self
105                .get_raw(addr, true)
106                .ok_or(ProcMemError::RIPRelativeFailed)?;
107
108            addr = addr.wrapping_add(rip as usize + ::std::mem::size_of::<u32>());
109        }
110    
111        addr = (addr as isize).wrapping_add(sig.extra) as usize;
112        if !sig.relative {
113            addr = addr.wrapping_add(self.module_baseaddr);
114        }
115
116        Ok(addr)
117    }
118
119
120    fn generate_regex(raw: &str) -> Option<Regex> {
121        let mut res = raw
122            .to_string()
123            .split_whitespace()
124            .map(|x| match &x {
125                &"?" => ".".to_string(),
126                x => format!("\\x{}", x),
127            })
128            .collect::<Vec<_>>()
129            .join("");
130        res.insert_str(0, "(?s-u)");
131        Regex::new(&res).ok()
132    }
133    
134    fn find_pattern(data: &[u8], pattern: &str) -> Option<usize> {
135        Self::generate_regex(pattern)
136            .and_then(|r| r.find(data))
137            .and_then(|m| Some(m.start()))
138    }
139}