wraith/util/
memory.rs

1//! Memory read/write utilities
2
3use crate::error::{Result, WraithError};
4
5/// read memory at address into value
6///
7/// # Safety
8/// address must be valid and readable
9pub unsafe fn read_memory<T: Copy>(address: usize) -> Result<T> {
10    if address == 0 {
11        return Err(WraithError::NullPointer {
12            context: "read_memory",
13        });
14    }
15
16    // SAFETY: caller ensures address validity
17    Ok(unsafe { (address as *const T).read_unaligned() })
18}
19
20/// write value to memory at address
21///
22/// # Safety
23/// address must be valid and writable
24pub unsafe fn write_memory<T: Copy>(address: usize, value: &T) -> Result<()> {
25    if address == 0 {
26        return Err(WraithError::NullPointer {
27            context: "write_memory",
28        });
29    }
30
31    // SAFETY: caller ensures address validity
32    unsafe {
33        (address as *mut T).write_unaligned(*value);
34    }
35    Ok(())
36}
37
38/// change memory protection
39pub fn protect_memory(address: usize, size: usize, protection: u32) -> Result<u32> {
40    let mut old_protect: u32 = 0;
41
42    let result = unsafe {
43        VirtualProtect(
44            address as *mut _,
45            size,
46            protection,
47            &mut old_protect,
48        )
49    };
50
51    if result == 0 {
52        Err(WraithError::ProtectionChangeFailed {
53            address: u64::try_from(address).unwrap_or(u64::MAX),
54            size,
55        })
56    } else {
57        Ok(old_protect)
58    }
59}
60
61/// RAII guard for memory protection changes
62pub struct ProtectionGuard {
63    address: usize,
64    size: usize,
65    old_protection: u32,
66}
67
68impl ProtectionGuard {
69    /// change protection, returning guard that restores on drop
70    pub fn new(address: usize, size: usize, new_protection: u32) -> Result<Self> {
71        let old_protection = protect_memory(address, size, new_protection)?;
72        Ok(Self {
73            address,
74            size,
75            old_protection,
76        })
77    }
78}
79
80impl Drop for ProtectionGuard {
81    fn drop(&mut self) {
82        let _ = protect_memory(self.address, self.size, self.old_protection);
83    }
84}
85
86#[link(name = "kernel32")]
87extern "system" {
88    fn VirtualProtect(
89        lpAddress: *mut core::ffi::c_void,
90        dwSize: usize,
91        flNewProtect: u32,
92        lpflOldProtect: *mut u32,
93    ) -> i32;
94}