wraith/manipulation/manual_map/
mod.rs1mod allocator;
29mod entry;
30mod mapper;
31mod parser;
32mod relocator;
33mod resolver;
34mod tls;
35
36pub use allocator::MappedMemory;
37pub use entry::reason;
38pub use parser::ParsedPe;
39
40use crate::error::{Result, WraithError};
41use core::marker::PhantomData;
42
43pub mod state {
45 pub struct Parsed;
47 pub struct Allocated;
49 pub struct SectionsMapped;
51 pub struct Relocated;
53 pub struct ImportsResolved;
55 pub struct TlsProcessed;
57 pub struct Ready;
59}
60
61pub struct ManualMapper<S> {
66 pe: ParsedPe,
67 memory: Option<MappedMemory>,
68 _state: PhantomData<S>,
69}
70
71impl ManualMapper<state::Parsed> {
72 pub fn parse(data: &[u8]) -> Result<Self> {
74 let pe = ParsedPe::parse(data)?;
75 Ok(Self {
76 pe,
77 memory: None,
78 _state: PhantomData,
79 })
80 }
81
82 pub fn from_file(path: &str) -> Result<Self> {
84 let data = std::fs::read(path).map_err(|e| WraithError::InvalidPeFormat {
85 reason: format!("failed to read file: {e}"),
86 })?;
87 Self::parse(&data)
88 }
89
90 pub fn pe(&self) -> &ParsedPe {
92 &self.pe
93 }
94
95 pub fn allocate(self) -> Result<ManualMapper<state::Allocated>> {
99 let size = self.pe.size_of_image();
100 let preferred_base = self.pe.preferred_base();
101
102 let memory = allocator::allocate_image(size, preferred_base)?;
103
104 Ok(ManualMapper {
105 pe: self.pe,
106 memory: Some(memory),
107 _state: PhantomData,
108 })
109 }
110
111 pub fn allocate_at(self, base: usize) -> Result<ManualMapper<state::Allocated>> {
115 let size = self.pe.size_of_image();
116 let memory = allocator::allocate_at(base, size)?;
117
118 Ok(ManualMapper {
119 pe: self.pe,
120 memory: Some(memory),
121 _state: PhantomData,
122 })
123 }
124
125 pub fn allocate_anywhere(self) -> Result<ManualMapper<state::Allocated>> {
127 let size = self.pe.size_of_image();
128 let memory = allocator::allocate_anywhere(size)?;
129
130 Ok(ManualMapper {
131 pe: self.pe,
132 memory: Some(memory),
133 _state: PhantomData,
134 })
135 }
136}
137
138impl ManualMapper<state::Allocated> {
139 pub fn base(&self) -> usize {
141 self.memory.as_ref().unwrap().base()
142 }
143
144 pub fn pe(&self) -> &ParsedPe {
146 &self.pe
147 }
148
149 pub fn map_sections(mut self) -> Result<ManualMapper<state::SectionsMapped>> {
151 let memory = self.memory.as_mut().unwrap();
152 mapper::map_sections(&self.pe, memory)?;
153
154 Ok(ManualMapper {
155 pe: self.pe,
156 memory: self.memory,
157 _state: PhantomData,
158 })
159 }
160}
161
162impl ManualMapper<state::SectionsMapped> {
163 pub fn base(&self) -> usize {
165 self.memory.as_ref().unwrap().base()
166 }
167
168 pub fn pe(&self) -> &ParsedPe {
170 &self.pe
171 }
172
173 pub fn relocate(mut self) -> Result<ManualMapper<state::Relocated>> {
175 let memory = self.memory.as_mut().unwrap();
176 let delta = memory.base() as i64 - self.pe.preferred_base() as i64;
177
178 if delta != 0 {
179 relocator::apply_relocations(&self.pe, memory, delta)?;
180 }
181
182 Ok(ManualMapper {
183 pe: self.pe,
184 memory: self.memory,
185 _state: PhantomData,
186 })
187 }
188
189 pub fn skip_relocations(self) -> ManualMapper<state::Relocated> {
191 ManualMapper {
192 pe: self.pe,
193 memory: self.memory,
194 _state: PhantomData,
195 }
196 }
197}
198
199impl ManualMapper<state::Relocated> {
200 pub fn base(&self) -> usize {
202 self.memory.as_ref().unwrap().base()
203 }
204
205 pub fn pe(&self) -> &ParsedPe {
207 &self.pe
208 }
209
210 pub fn resolve_imports(mut self) -> Result<ManualMapper<state::ImportsResolved>> {
212 let memory = self.memory.as_mut().unwrap();
213 resolver::resolve_imports(&self.pe, memory)?;
214
215 Ok(ManualMapper {
216 pe: self.pe,
217 memory: self.memory,
218 _state: PhantomData,
219 })
220 }
221
222 pub fn resolve_imports_with<F>(
224 mut self,
225 resolver_fn: F,
226 ) -> Result<ManualMapper<state::ImportsResolved>>
227 where
228 F: Fn(&str, &str) -> Option<usize>,
229 {
230 let memory = self.memory.as_mut().unwrap();
231 resolver::resolve_imports_custom(&self.pe, memory, resolver_fn)?;
232
233 Ok(ManualMapper {
234 pe: self.pe,
235 memory: self.memory,
236 _state: PhantomData,
237 })
238 }
239
240 pub fn skip_imports(self) -> ManualMapper<state::ImportsResolved> {
242 ManualMapper {
243 pe: self.pe,
244 memory: self.memory,
245 _state: PhantomData,
246 }
247 }
248}
249
250impl ManualMapper<state::ImportsResolved> {
251 pub fn base(&self) -> usize {
253 self.memory.as_ref().unwrap().base()
254 }
255
256 pub fn pe(&self) -> &ParsedPe {
258 &self.pe
259 }
260
261 pub fn process_tls(mut self) -> Result<ManualMapper<state::TlsProcessed>> {
263 let memory = self.memory.as_mut().unwrap();
264 tls::process_tls(&self.pe, memory)?;
265
266 Ok(ManualMapper {
267 pe: self.pe,
268 memory: self.memory,
269 _state: PhantomData,
270 })
271 }
272
273 pub fn skip_tls(self) -> ManualMapper<state::TlsProcessed> {
275 ManualMapper {
276 pe: self.pe,
277 memory: self.memory,
278 _state: PhantomData,
279 }
280 }
281}
282
283impl ManualMapper<state::TlsProcessed> {
284 pub fn base(&self) -> usize {
286 self.memory.as_ref().unwrap().base()
287 }
288
289 pub fn pe(&self) -> &ParsedPe {
291 &self.pe
292 }
293
294 pub fn finalize(mut self) -> Result<ManualMapper<state::Ready>> {
296 let memory = self.memory.as_mut().unwrap();
297 mapper::set_section_protections(&self.pe, memory)?;
298
299 Ok(ManualMapper {
300 pe: self.pe,
301 memory: self.memory,
302 _state: PhantomData,
303 })
304 }
305
306 pub fn finalize_without_protections(self) -> ManualMapper<state::Ready> {
308 ManualMapper {
309 pe: self.pe,
310 memory: self.memory,
311 _state: PhantomData,
312 }
313 }
314}
315
316impl ManualMapper<state::Ready> {
317 pub fn call_entry_point(&self) -> Result<bool> {
319 let memory = self.memory.as_ref().unwrap();
320 entry::call_dll_attach(&self.pe, memory)
321 }
322
323 pub fn call_entry_point_with_reason(&self, call_reason: u32) -> Result<bool> {
325 let memory = self.memory.as_ref().unwrap();
326 entry::call_entry_point(&self.pe, memory, call_reason)
327 }
328
329 pub fn get_export(&self, name: &str) -> Result<usize> {
331 let memory = self.memory.as_ref().unwrap();
332 resolver::get_mapped_export(&self.pe, memory, name)
333 }
334
335 pub fn get_export_by_ordinal(&self, ordinal: u16) -> Result<usize> {
337 let memory = self.memory.as_ref().unwrap();
338 resolver::get_mapped_export_by_ordinal(&self.pe, memory, ordinal)
339 }
340
341 pub fn base(&self) -> usize {
343 self.memory.as_ref().unwrap().base()
344 }
345
346 pub fn size(&self) -> usize {
348 self.memory.as_ref().unwrap().size()
349 }
350
351 pub fn pe(&self) -> &ParsedPe {
353 &self.pe
354 }
355
356 pub fn into_memory(mut self) -> MappedMemory {
358 self.memory.take().unwrap()
359 }
360
361 pub fn ptr_at(&self, offset: usize) -> *mut u8 {
363 self.memory.as_ref().unwrap().ptr_at(offset)
364 }
365
366 pub fn unmap(mut self) -> Result<()> {
368 if let Some(memory) = self.memory.take() {
369 let _ = entry::call_dll_detach(&self.pe, &memory);
371 memory.free()?;
372 }
373 Ok(())
374 }
375}
376
377pub fn map_pe(data: &[u8]) -> Result<ManualMapper<state::Ready>> {
379 ManualMapper::parse(data)?
380 .allocate()?
381 .map_sections()?
382 .relocate()?
383 .resolve_imports()?
384 .process_tls()?
385 .finalize()
386}
387
388pub fn map_file(path: &str) -> Result<ManualMapper<state::Ready>> {
390 ManualMapper::from_file(path)?
391 .allocate()?
392 .map_sections()?
393 .relocate()?
394 .resolve_imports()?
395 .process_tls()?
396 .finalize()
397}
398
399pub fn map_and_call(data: &[u8]) -> Result<ManualMapper<state::Ready>> {
401 let mapper = map_pe(data)?;
402 mapper.call_entry_point()?;
403 Ok(mapper)
404}
405
406pub fn map_file_and_call(path: &str) -> Result<ManualMapper<state::Ready>> {
408 let mapper = map_file(path)?;
409 mapper.call_entry_point()?;
410 Ok(mapper)
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416
417 #[test]
418 fn test_parse_and_allocate() {
419 let exe_path = std::env::current_exe().unwrap();
420 let data = std::fs::read(&exe_path).unwrap();
421
422 let mapper = ManualMapper::parse(&data).unwrap();
423 assert!(mapper.pe().size_of_image() > 0);
424
425 let mapper = mapper.allocate().unwrap();
426 assert!(mapper.base() != 0);
427 }
428
429 #[test]
430 fn test_map_sections() {
431 let exe_path = std::env::current_exe().unwrap();
432 let data = std::fs::read(&exe_path).unwrap();
433
434 let mapper = ManualMapper::parse(&data)
435 .unwrap()
436 .allocate()
437 .unwrap()
438 .map_sections()
439 .unwrap();
440
441 assert!(mapper.base() != 0);
443 }
444
445 }