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
47impl Clone for Pointer
48{
49    fn clone(&self) -> Pointer
50    {
51        Self::new(self.process_data.clone(), self.is_64_bit, self.base_address, self.offsets.clone())
52    }
53}
54
55impl Default for Pointer
56{
57    fn default() -> Self
58    {
59        Pointer
60        {
61            process_data: Rc::new(RefCell::new(ProcessData::default())),
62            is_64_bit: true,
63            base_address: 0,
64            offsets: Vec::new(),
65            debug: false,
66        }
67    }
68}
69
70impl Pointer
71{
72    pub(crate) fn new(process_data: Rc<RefCell<ProcessData>>, is_64_bit: bool, base_address: usize, offsets: Vec<usize>) -> Self
73    {
74        Pointer
75        {
76            process_data,
77            is_64_bit,
78            base_address,
79            offsets,
80            debug: false,
81        }
82    }
83
84    /// Get the base address of this pointer, without resolving offsets.
85    pub fn get_base_address(&self) -> usize
86    {
87        return self.base_address;
88    }
89
90    fn resolve_offsets(&self, offsets: &Vec<usize>) -> usize
91    {
92        let mut path = String::from(format!(" {:#010x}", self.base_address));
93        let mut ptr = self.base_address;
94
95        for i in 0..offsets.len()
96        {
97            let offset = offsets[i];
98
99            //Create a copy for debug output
100            let debug_copy = ptr;
101
102            //Resolve an offset
103            let address = ptr + offset;
104
105            //Not the last offset = resolve as pointer
106            if i + 1 < offsets.len()
107            {
108                if self.is_64_bit
109                {
110                    let mut buffer = [0; 8];
111                    self.read_memory_abs(address, &mut buffer);
112                    ptr = u64::from_ne_bytes(buffer) as usize;
113                }
114                else
115                {
116                    let mut buffer = [0; 4];
117                    self.read_memory_abs(address, &mut buffer);
118                    ptr = u32::from_ne_bytes(buffer) as usize;
119                }
120
121                path.push_str(format!("\n[{:#010x} + {:#010x}]: {:#010x}", debug_copy, offset, ptr).as_str());
122
123                if ptr == 0
124                {
125                    if self.debug
126                    {
127                        println!("{}", path);
128                    }
129                    return 0;
130                }
131            }
132            else
133            {
134                ptr = address;
135                path.push_str(format!("\n{:#010x} + {:#010x}: {:#010x}", debug_copy, offset, ptr).as_str());
136            }
137        }
138        if self.debug
139        {
140            println!("{}", path);
141        }
142        return ptr;
143    }
144}
145
146impl BaseReadWrite for Pointer
147{
148    fn read_memory_rel(&self, offset: Option<usize>, buffer: &mut [u8]) -> bool
149    {
150        let mut copy = self.offsets.clone();
151        if offset.is_some()
152        {
153            copy.push(offset.unwrap());
154        }
155        let address = self.resolve_offsets(&copy);
156        return self.read_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
157    }
158
159    fn write_memory_rel(&self, offset: Option<usize>, buffer: &[u8]) -> bool
160    {
161        let mut copy = self.offsets.clone();
162        if offset.is_some()
163        {
164            copy.push(offset.unwrap());
165        }
166        let address = self.resolve_offsets(&copy);
167        return self.write_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
168    }
169
170    fn read_memory_abs(&self, address: usize, buffer: &mut [u8]) -> bool
171    {
172        return self.read_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
173    }
174
175    fn write_memory_abs(&self, address: usize, buffer: &[u8]) -> bool
176    {
177        return self.write_with_handle(self.process_data.borrow().handle, self.process_data.borrow().memory_type.clone(), address, buffer);
178    }
179}
180
181impl ReadWrite for Pointer{}