1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(target_os = "windows")]
pub use windows::*;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use linux::*;
use std::io::Error as IoError;
#[derive(Debug)]
pub enum MemoryReadError {
InaccessibleMemoryAddress { address: usize },
LessBytesRead { expected: usize, actual: usize },
IOError { io_error: IoError },
}
impl From<IoError> for MemoryReadError {
fn from(io_error: IoError) -> Self {
MemoryReadError::IOError { io_error }
}
}
macro_rules! define_number_read (
($type: ident, $name: ident, $bytes: expr) => (
fn $name(&self, address: usize) -> Result<$type, MemoryReadError> {
let mut buffer = [0u8; $bytes];
self.read_bytes(address, &mut buffer)?;
Ok($type::from_le_bytes(buffer))
}
);
);
pub trait Process {
fn base_address(&self, module_name: &str) -> Option<usize>;
fn read_bytes(&self, address: usize, buffer: &mut [u8]) -> Result<(), MemoryReadError>;
fn read_string(&self, address: usize) -> Result<String, MemoryReadError> {
let mut buffer = Vec::new();
let mut index = 0;
loop {
let ch = self.read_u8(address + index as usize)?;
if ch == 0 {
break;
}
buffer.insert(index, ch);
index += 1;
}
Ok(String::from_utf8(buffer).unwrap_or(String::from("")))
}
fn read_u8(&self, address: usize) -> Result<u8, MemoryReadError> {
let mut buffer = [0u8; 1];
self.read_bytes(address, &mut buffer)?;
Ok(buffer[0])
}
fn read_bool(&self, address: usize) -> Result<bool, MemoryReadError> {
Ok(self.read_u8(address)? == 1)
}
define_number_read!(u32, read_u32, 4);
define_number_read!(u64, read_u64, 8);
define_number_read!(u128, read_u128, 16);
define_number_read!(i32, read_i32, 4);
define_number_read!(i64, read_i64, 8);
define_number_read!(f32, read_f32, 4);
define_number_read!(f64, read_f64, 8);
}