-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathmemory.rs
135 lines (116 loc) · 4.05 KB
/
memory.rs
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use core::ffi::c_void;
use windows_sys::{Win32::Foundation, Win32::System::Diagnostics::Debug::*};
pub trait MemorySource {
// Read up to "len" bytes, and return Option<u8> to represent what bytes are available in the range
fn read_memory(&self, address: u64, len: usize) -> Result<Vec<Option<u8>>, &'static str>;
// Read up to "len" bytes, and stop at the first failure
fn read_raw_memory(&self, address: u64, len: usize) -> Vec<u8>;
}
pub fn read_memory_array<T: Sized + Default>(
source: &dyn MemorySource,
address: u64,
max_count: usize,
) -> Result<Vec<T>, &'static str> {
let element_size = ::core::mem::size_of::<T>();
let max_bytes = max_count * element_size;
let raw_bytes = source.read_raw_memory(address, max_bytes);
let mut data: Vec<T> = Vec::new();
let mut offset: usize = 0;
while offset + element_size <= raw_bytes.len() {
let mut item: T = T::default();
let dst: *mut u8 = unsafe { std::mem::transmute(&mut item) };
let src = &raw_bytes[offset] as *const u8;
unsafe { std::ptr::copy_nonoverlapping(src, dst, element_size) };
data.push(item);
offset += element_size;
}
Ok(data)
}
pub fn read_memory_data<T: Sized + Default + Copy>(
source: &dyn MemorySource,
address: u64,
) -> Result<T, &'static str> {
let data = read_memory_array::<T>(source, address, 1)?;
Ok(data[0])
}
pub fn read_memory_string(
source: &dyn MemorySource,
address: u64,
max_count: usize,
is_wide: bool,
) -> Result<String, &'static str> {
let result: String = if is_wide {
let mut words = read_memory_array::<u16>(source, address, max_count)?;
let null_pos = words.iter().position(|&v| v == 0);
if let Some(null_pos) = null_pos {
words.truncate(null_pos);
}
String::from_utf16_lossy(&words)
} else {
let mut bytes = read_memory_array::<u8>(source, address, max_count)?;
let null_pos = bytes.iter().position(|&v| v == 0);
if let Some(null_pos) = null_pos {
bytes.truncate(null_pos);
}
String::from_utf8(bytes).unwrap()
};
Ok(result)
}
struct LiveMemorySource {
hprocess: Foundation::HANDLE,
}
pub fn make_live_memory_source(hprocess: Foundation::HANDLE) -> Box<dyn MemorySource> {
Box::new(LiveMemorySource { hprocess })
}
impl MemorySource for LiveMemorySource {
fn read_memory(&self, address: u64, len: usize) -> Result<Vec<Option<u8>>, &'static str> {
let mut buffer: Vec<u8> = vec![0; len];
let mut data: Vec<Option<u8>> = vec![None; len];
let mut offset: usize = 0;
while offset < len {
let mut bytes_read: usize = 0;
let len_left = len - offset;
let cur_address = address + (offset as u64);
let result = unsafe {
ReadProcessMemory(
self.hprocess,
cur_address as *const c_void,
buffer.as_mut_ptr() as *mut c_void,
len_left,
&mut bytes_read as *mut usize,
)
};
if result == 0 {
return Err("ReadProcessMemory failed");
};
for index in 0..bytes_read {
let data_index = offset + index;
data[data_index] = Some(buffer[index]);
}
if bytes_read > 0 {
offset += bytes_read;
} else {
offset += 1;
}
}
Ok(data)
}
fn read_raw_memory(&self, address: u64, len: usize) -> Vec<u8> {
let mut buffer: Vec<u8> = vec![0; len];
let mut bytes_read: usize = 0;
let result = unsafe {
ReadProcessMemory(
self.hprocess,
address as *const c_void,
buffer.as_mut_ptr() as *mut c_void,
len,
&mut bytes_read as *mut usize,
)
};
if result == 0 {
bytes_read = 0;
}
buffer.truncate(bytes_read);
buffer
}
}