remote_mem/
lib.rs

1use robs::{scanner, signature::Signature};
2use thiserror::Error;
3
4#[cfg(target_family = "windows")]
5pub mod windows;
6
7pub struct RemoteMemory {
8    #[cfg(target_family = "windows")]
9    windows_remote_memory: windows::windows_remote_memory::WindowsRemoteMemory,
10}
11
12#[derive(Debug, Error)]
13pub enum RemoteMemoryError {
14    #[cfg(target_family = "windows")]
15    #[error("{0}")]
16    WindowsError(windows::windows_remote_memory::WindowsError),
17    #[error("'{0}' OS is not supported")]
18    OsNotSupported(String),
19}
20
21#[cfg(target_family = "windows")]
22impl From<windows::windows_remote_memory::WindowsError> for RemoteMemoryError {
23    fn from(e: windows::windows_remote_memory::WindowsError) -> Self {
24        RemoteMemoryError::WindowsError(e)
25    }
26}
27
28#[cfg(target_family = "windows")]
29impl RemoteMemory {
30    pub fn new(process_id: u32) -> Result<RemoteMemory, RemoteMemoryError> {
31        Ok(RemoteMemory {
32            windows_remote_memory: windows::windows_remote_memory::WindowsRemoteMemory::new(
33                process_id,
34            )?,
35        })
36    }
37
38    pub fn new_by_name(process_name: &str) -> Result<RemoteMemory, RemoteMemoryError> {
39        Ok(RemoteMemory {
40            windows_remote_memory:
41                windows::windows_remote_memory::WindowsRemoteMemory::new_by_name(process_name)?,
42        })
43    }
44
45    pub fn read_bytes(&self, address: usize, buffer: &mut [u8]) -> Result<(), RemoteMemoryError> {
46        Ok(self.windows_remote_memory.read_bytes(address, buffer)?)
47    }
48
49    pub fn write_ptr(
50        &self,
51        address: usize,
52        ptr: usize,
53        num_bytes_to_write: usize,
54    ) -> Result<(), RemoteMemoryError> {
55        Ok(self
56            .windows_remote_memory
57            .write_ptr(address, ptr, num_bytes_to_write)?)
58    }
59
60    pub fn get_base_address(&self) -> usize {
61        self.windows_remote_memory.base_module.mod_base_addr as usize
62    }
63
64    pub fn get_base_size(&self) -> usize {
65        self.windows_remote_memory.base_module.mod_base_size as usize
66    }
67}
68
69impl RemoteMemory {
70    pub fn read<T: Sized + Copy>(&self, address: usize) -> Result<T, RemoteMemoryError> {
71        let size = std::mem::size_of::<T>();
72        let mut buffer: Vec<u8> = vec![0; size];
73        self.read_bytes(address, &mut buffer)?;
74        Ok(unsafe { (buffer.as_ptr() as *const T).read_unaligned() })
75    }
76
77    pub fn write_bytes(&self, address: usize, buffer: &[u8]) -> Result<(), RemoteMemoryError> {
78        self.write_ptr(address, buffer.as_ptr() as usize, buffer.len())
79    }
80
81    pub fn write<T: Sized + Copy>(
82        &self,
83        address: usize,
84        value: T,
85    ) -> Result<(), RemoteMemoryError> {
86        let size = std::mem::size_of::<T>();
87        self.write_ptr(address, std::ptr::addr_of!(value) as usize, size)
88    }
89
90    pub fn find_signature(&self, signature: &Signature) -> Option<usize> {
91        let base_address = self.get_base_address();
92        let base_size = self.get_base_size();
93        let mut buffer = vec![0; base_size];
94        self.read_bytes(base_address, &mut buffer).ok()?;
95        scanner::find_signature(&buffer, signature)
96    }
97}
98
99#[cfg(test)]
100mod test {
101    #[test]
102    fn test_read_bytes() {
103        let buffer = vec![0xFF, 0x00, 0x12, 0xCD];
104        let buffer_ptr = buffer.as_ptr() as usize;
105        let process_id = std::process::id();
106        let remote_memory = super::RemoteMemory::new(process_id);
107        assert!(remote_memory.is_ok());
108        let remote_memory = remote_memory.unwrap();
109        let mut read_buffer = vec![0; 4];
110        assert!(remote_memory
111            .read_bytes(buffer_ptr, &mut read_buffer)
112            .is_ok());
113        assert_eq!(buffer, read_buffer);
114    }
115
116    #[test]
117    fn test_read_u32() {
118        let value = 12345;
119        let value_ptr = std::ptr::addr_of!(value) as usize;
120        let process_id = std::process::id();
121        let remote_memory = super::RemoteMemory::new(process_id);
122        assert!(remote_memory.is_ok());
123        let remote_memory = remote_memory.unwrap();
124        let read_value = remote_memory.read::<u32>(value_ptr);
125        assert!(read_value.is_ok());
126        let read_value = read_value.unwrap();
127        assert_eq!(read_value, value);
128    }
129
130    #[test]
131    fn test_write_bytes() {
132        let data = vec![0xFF, 0x00, 0x12, 0xCD];
133        let buffer = vec![0; 4];
134        let buffer_ptr = buffer.as_ptr() as usize;
135        let process_id = std::process::id();
136        let remote_memory = super::RemoteMemory::new(process_id);
137        assert!(remote_memory.is_ok());
138        let remote_memory = remote_memory.unwrap();
139        assert_ne!(data, buffer);
140        assert!(remote_memory.write_bytes(buffer_ptr, &data).is_ok());
141        assert_eq!(data, buffer);
142    }
143
144    #[test]
145    fn test_write_u32() {
146        let data: usize = 12345;
147        let buffer: usize = 0;
148        let buffer_ptr = std::ptr::addr_of!(buffer) as usize;
149        let process_id = std::process::id();
150        let remote_memory = super::RemoteMemory::new(process_id);
151        assert!(remote_memory.is_ok());
152        let remote_memory = remote_memory.unwrap();
153        assert_ne!(data, buffer);
154        assert!(remote_memory.write::<usize>(buffer_ptr, data).is_ok());
155        assert_eq!(data, buffer);
156    }
157}