mem_rs/
pointer.rs

1// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs).
2// Copyright (c) 2022 Frank van der Stam.
3// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, version 3.
8//
9// This program is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17use std::cell::RefCell;
18use std::rc::Rc;
19use crate::memory::{BaseReadWrite, ReadWrite};
20use crate::process_data::ProcessData;
21
22
23/// Represents a pointer path that is dynamically resolved each read/write operation.
24/// This ensures that the pointer is always valid. Race conditions can occur and the pointer could encounter
25/// a null pointer along the path. Should always be constructed via the Process struct.
26///
27/// # Example
28///
29/// ```
30/// use mem_rs::prelude::*;
31///
32/// let mut process = Process::new("name_of_process.exe");
33/// process.refresh()?;
34/// let pointer = process.create_pointer(0x1234, vec![0]);
35/// let data = pointer.read_u8_rel(Some(0x1234));
36/// ```
37pub struct Pointer
38{
39    process_data: Rc<RefCell<ProcessData>>,
40    pub is_64_bit: bool,
41    pub base_address: usize,
42    pub offsets: Vec<usize>,
43    /// Set this to true to print each memory address while resolving the pointer path.
44    pub debug: bool,
45}
46
47unsafe impl Sync for Pointer {}
48unsafe impl Send for Pointer {}
49
50impl Clone for Pointer
51{
52    fn clone(&self) -> Pointer
53    {
54        Self::new(self.process_data.clone(), self.is_64_bit, self.base_address, self.offsets.clone())
55    }
56}
57
58impl Default for Pointer
59{
60    fn default() -> Self
61    {
62        Pointer
63        {
64            process_data: Rc::new(RefCell::new(ProcessData::default())),
65            is_64_bit: true,
66            base_address: 0,
67            offsets: Vec::new(),
68            debug: false,
69        }
70    }
71}
72
73impl Pointer
74{
75    pub(crate) fn new(process_data: Rc<RefCell<ProcessData>>, is_64_bit: bool, base_address: usize, offsets: Vec<usize>) -> Self
76    {
77        Pointer
78        {
79            process_data,
80            is_64_bit,
81            base_address,
82            offsets,
83            debug: false,
84        }
85    }
86
87    /// Get the base address of this pointer, without resolving offsets.
88    pub fn get_base_address(&self) -> usize
89    {
90        return self.base_address;
91    }
92
93    fn resolve_offsets(&self, offsets: &Vec<usize>) -> usize
94    {
95        let mut path = String::from(format!(" {:#010x}", self.base_address));
96        let mut ptr = self.base_address;
97
98        for i in 0..offsets.len()
99        {
100            let offset = offsets[i];
101
102            //Create a copy for debug output
103            let debug_copy = ptr;
104
105            //Resolve an offset
106            let address = ptr + offset;
107
108            //Not the last offset = resolve as pointer
109            if i + 1 < offsets.len()
110            {
111                if self.is_64_bit
112                {
113                    let mut buffer = [0; 8];
114                    self.read_memory_abs(address, &mut buffer);
115                    ptr = u64::from_ne_bytes(buffer) as usize;
116                }
117                else
118                {
119                    let mut buffer = [0; 4];
120                    self.read_memory_abs(address, &mut buffer);
121                    ptr = u32::from_ne_bytes(buffer) as usize;
122                }
123
124                path.push_str(format!("\n[{:#010x} + {:#010x}]: {:#010x}", debug_copy, offset, ptr).as_str());
125
126                if ptr == 0
127                {
128                    if self.debug
129                    {
130                        println!("{}", path);
131                    }
132                    return 0;
133                }
134            }
135            else
136            {
137                ptr = address;
138                path.push_str(format!("\n{:#010x} + {:#010x}: {:#010x}", debug_copy, offset, ptr).as_str());
139            }
140        }
141        if self.debug
142        {
143            println!("{}", path);
144        }
145        return ptr;
146    }
147}
148
149impl BaseReadWrite for Pointer
150{
151    fn read_memory_rel(&self, offset: Option<usize>, buffer: &mut [u8]) -> bool
152    {
153        let mut copy = self.offsets.clone();
154        if offset.is_some()
155        {
156            copy.push(offset.unwrap());
157        }
158        let address = self.resolve_offsets(&copy);
159        return self.read_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
160    }
161
162    fn write_memory_rel(&self, offset: Option<usize>, buffer: &[u8]) -> bool
163    {
164        let mut copy = self.offsets.clone();
165        if offset.is_some()
166        {
167            copy.push(offset.unwrap());
168        }
169        let address = self.resolve_offsets(&copy);
170        return self.write_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
171    }
172
173    fn read_memory_abs(&self, address: usize, buffer: &mut [u8]) -> bool
174    {
175        return self.read_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
176    }
177
178    fn write_memory_abs(&self, address: usize, buffer: &[u8]) -> bool
179    {
180        return self.write_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
181    }
182}
183
184impl ReadWrite for Pointer{}