dma_rs/
lib.rs

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}