1use memprocfs::{Vmm, VmmProcess, VmmScatterMemory};
2
3pub mod error;
4mod embedded;
5
6pub use error::DmaError;
7
8pub struct Dma<'a> {
9 vmm: Vmm<'a>,
10}
11
12impl<'a> Dma<'a> {
13 pub fn new(device: &str) -> Result<Self, DmaError> {
14 let vmm_dll_path = embedded::get_vmm_dll_path()?;
15 let args = vec!["-device", device, "-waitinitialize"];
16
17 let vmm = Vmm::new(vmm_dll_path, &args)
18 .map_err(|e| DmaError::InitFailed(e.to_string()))?;
19
20 Ok(Dma { vmm })
21 }
22
23 pub fn list_processes(&self) -> Result<Vec<ProcessInfo>, DmaError> {
24 let process_list = self.vmm.process_list()
25 .map_err(|e| DmaError::ProcessError(e.to_string()))?;
26
27 let mut processes = Vec::new();
28 for proc in &*process_list {
29 if let Ok(info) = proc.info() {
30 let path = proc.get_path_kernel().unwrap_or_default();
31 processes.push(ProcessInfo {
32 pid: proc.pid,
33 name: info.name,
34 ppid: info.ppid,
35 path,
36 });
37 }
38 }
39
40 Ok(processes)
41 }
42
43 pub fn attach(&'a self, name: &str) -> Result<Process<'a>, DmaError> {
44 let vmm_process = self.vmm.process_from_name(name)
45 .map_err(|e| DmaError::ProcessError(format!("Process '{}' not found: {}", name, e)))?;
46
47 Ok(Process::new(vmm_process))
48 }
49
50 pub fn attach_pid(&'a self, pid: u32) -> Result<Process<'a>, DmaError> {
51 let vmm_process = self.vmm.process_from_pid(pid)
52 .map_err(|e| DmaError::ProcessError(format!("PID {} not found: {}", pid, e)))?;
53
54 Ok(Process::new(vmm_process))
55 }
56
57 pub fn get_process_info(&self, name: &str) -> Result<ProcessInfo, DmaError> {
58 let proc = self.vmm.process_from_name(name)
59 .map_err(|e| DmaError::ProcessError(format!("Process '{}' not found: {}", name, e)))?;
60
61 let info = proc.info()
62 .map_err(|e| DmaError::ProcessError(e.to_string()))?;
63
64 let path = proc.get_path_kernel().unwrap_or_default();
65
66 Ok(ProcessInfo {
67 pid: proc.pid,
68 name: info.name,
69 ppid: info.ppid,
70 path,
71 })
72 }
73
74 pub fn vmm(&self) -> &Vmm<'a> {
75 &self.vmm
76 }
77}
78
79pub struct Process<'a> {
80 inner: VmmProcess<'a>,
81}
82
83impl<'a> Process<'a> {
84 fn new(inner: VmmProcess<'a>) -> Self {
85 Self { inner }
86 }
87
88 pub fn pid(&self) -> u32 {
89 self.inner.pid
90 }
91
92 pub fn info(&self) -> Result<ProcessInfo, DmaError> {
93 let info = self.inner.info()
94 .map_err(|e| DmaError::ProcessError(e.to_string()))?;
95
96 let path = self.inner.get_path_kernel().unwrap_or_default();
97
98 Ok(ProcessInfo {
99 pid: self.inner.pid,
100 name: info.name,
101 ppid: info.ppid,
102 path,
103 })
104 }
105
106 pub fn read<T: Copy>(&self, address: u64) -> Result<T, DmaError> {
107 self.inner.mem_read_as(address, 0)
108 .map_err(|e| DmaError::MemoryError(format!("Read failed at 0x{:X}: {}", address, e)))
109 }
110
111 pub fn read_bytes(&self, address: u64, size: usize) -> Result<Vec<u8>, DmaError> {
112 self.inner.mem_read(address, size)
113 .map_err(|e| DmaError::MemoryError(format!("Read {} bytes failed at 0x{:X}: {}", size, address, e)))
114 }
115
116 pub fn write<T: Copy>(&self, address: u64, value: &T) -> Result<(), DmaError> {
117 self.inner.mem_write_as(address, value)
118 .map_err(|e| DmaError::MemoryError(format!("Write failed at 0x{:X}: {}", address, e)))
119 }
120
121 pub fn write_bytes(&self, address: u64, data: &[u8]) -> Result<(), DmaError> {
122 self.inner.mem_write(address, data)
123 .map_err(|e| DmaError::MemoryError(format!("Write {} bytes failed at 0x{:X}: {}", data.len(), address, e)))
124 }
125
126 pub fn scatter(&'a self) -> Result<ScatterHandle<'a>, DmaError> {
127 let scatter = self.inner.mem_scatter(0)
128 .map_err(|e| DmaError::MemoryError(format!("Failed to create scatter handle: {}", e)))?;
129
130 Ok(ScatterHandle { scatter })
131 }
132
133 pub fn module_base(&self, module_name: &str) -> Result<u64, DmaError> {
134 self.inner.get_module_base(module_name)
135 .map_err(|e| DmaError::ModuleError(format!("Module '{}' not found: {}", module_name, e)))
136 }
137
138 pub fn proc_address(&self, module_name: &str, function_name: &str) -> Result<u64, DmaError> {
139 self.inner.get_proc_address(module_name, function_name)
140 .map_err(|e| DmaError::ModuleError(format!("Function '{}' in '{}' not found: {}", function_name, module_name, e)))
141 }
142
143 pub fn list_modules(&self) -> Result<Vec<Module>, DmaError> {
144 let module_map = self.inner.map_module(false, false)
145 .map_err(|e| DmaError::ModuleError(format!("Failed to enumerate modules: {}", e)))?;
146
147 let modules = module_map.iter()
148 .map(|m| Module {
149 name: m.name.clone(),
150 base: m.va_base,
151 size: m.image_size as usize,
152 entry: m.va_entry,
153 path: m.full_name.clone(),
154 })
155 .collect();
156
157 Ok(modules)
158 }
159
160 pub fn read_string(&self, address: u64, max_length: usize) -> Result<String, DmaError> {
161 let bytes = self.read_bytes(address, max_length)?;
162
163 let null_pos = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
164 let string_bytes = &bytes[..null_pos];
165
166 String::from_utf8(string_bytes.to_vec())
167 .map_err(|e| DmaError::MemoryError(format!("Invalid UTF-8 string at 0x{:X}: {}", address, e)))
168 }
169
170 pub fn inner(&self) -> &VmmProcess<'a> {
171 &self.inner
172 }
173}
174
175pub struct ScatterHandle<'a> {
176 scatter: VmmScatterMemory<'a>,
177}
178
179impl<'a> ScatterHandle<'a> {
180 pub fn prepare_read(&mut self, address: u64, size: usize) {
181 let _ = self.scatter.prepare(address, size);
182 }
183
184 pub fn prepare_read_ex(&mut self, data: &'a mut (u64, Vec<u8>, u32)) {
185 let _ = self.scatter.prepare_ex(data);
186 }
187
188 pub fn execute(&mut self) -> Result<(), DmaError> {
189 self.scatter.execute()
190 .map_err(|e| DmaError::MemoryError(format!("Scatter execute failed: {}", e)))
191 }
192
193 pub fn read(&mut self, address: u64, size: usize) -> Result<Vec<u8>, DmaError> {
194 self.scatter.read(address, size)
195 .map_err(|e| DmaError::MemoryError(format!("Scatter read failed at 0x{:X}: {}", address, e)))
196 }
197
198 pub fn read_as<T: Copy>(&mut self, address: u64) -> Result<T, DmaError> {
199 self.scatter.read_as(address)
200 .map_err(|e| DmaError::MemoryError(format!("Scatter read_as failed at 0x{:X}: {}", address, e)))
201 }
202
203 pub fn clear(&mut self) {
204 let _ = self.scatter.clear();
205 }
206}
207
208#[derive(Debug, Clone)]
209pub struct ProcessInfo {
210 pub pid: u32,
211 pub name: String,
212 pub ppid: u32,
213 pub path: String,
214}
215
216#[derive(Debug, Clone)]
217pub struct Module {
218 pub name: String,
219 pub base: u64,
220 pub size: usize,
221 pub entry: u64,
222 pub path: String,
223}