verity_memory/ops/
read.rs1use std::panic::{catch_unwind, AssertUnwindSafe};
2
3use winapi::{shared::minwindef::LPVOID, um::{memoryapi::VirtualProtect, winnt::PAGE_EXECUTE_READWRITE}};
4
5use crate::{errors::ReadMemoryError, utils};
6
7pub unsafe fn read_memory<T: Copy>(address: *const T) -> Result<T, ReadMemoryError> {
40 if address.is_null() {
41 return Err(ReadMemoryError::NullPointer);
42 }
43
44 if !utils::check_alignment(address) {
45 return Err(ReadMemoryError::InvalidAlignment);
46 }
47
48 let mut old_protect = 0;
49 let size = std::mem::size_of::<T>();
50
51 let res = VirtualProtect(
52 address as LPVOID,
53 size,
54 PAGE_EXECUTE_READWRITE,
55 &mut old_protect,
56 );
57
58 if res == 0 {
59 return Err(ReadMemoryError::FailedToChangeProtection);
60 }
61
62 let result = catch_unwind(AssertUnwindSafe(|| *address))
63 .map_err(|_| ReadMemoryError::InvalidAccess);
64
65 let res_restore = VirtualProtect(address as LPVOID, size, old_protect, &mut old_protect);
66 if res_restore == 0 {
67 return Err(ReadMemoryError::FailedToRestoreProtection);
68 }
69
70 result
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_read_memory_valid() {
79 let valid_data = 42;
80 let ptr: *const i32 = &valid_data;
81
82 let result = unsafe { read_memory(ptr) };
83 assert_eq!(result, Ok(42));
84 }
85
86 #[test]
87 fn test_read_memory_null_pointer() {
88 let null_ptr: *const i32 = std::ptr::null();
89
90 let result = unsafe { read_memory(null_ptr) };
91 assert_eq!(result, Err(ReadMemoryError::NullPointer));
92 }
93
94 #[test]
95 fn test_read_memory_invalid_alignment() {
96 let invalid_data = 42i32;
97 let ptr: *const i32 = &invalid_data;
98
99 let unaligned_ptr = (ptr as usize + 1) as *const i32;
100
101 let result = unsafe { read_memory(unaligned_ptr) };
102 assert_eq!(result, Err(ReadMemoryError::InvalidAlignment));
103 }
104}