remote-mem 0.1.1

Remote memory access library
Documentation
use robs::{scanner, signature::Signature};
use thiserror::Error;

#[cfg(target_family = "windows")]
pub mod windows;

pub struct RemoteMemory {
    #[cfg(target_family = "windows")]
    windows_remote_memory: windows::windows_remote_memory::WindowsRemoteMemory,
}

#[derive(Debug, Error)]
pub enum RemoteMemoryError {
    #[cfg(target_family = "windows")]
    #[error("{0}")]
    WindowsError(windows::windows_remote_memory::WindowsError),
    #[error("'{0}' OS is not supported")]
    OsNotSupported(String),
}

#[cfg(target_family = "windows")]
impl From<windows::windows_remote_memory::WindowsError> for RemoteMemoryError {
    fn from(e: windows::windows_remote_memory::WindowsError) -> Self {
        RemoteMemoryError::WindowsError(e)
    }
}

#[cfg(target_family = "windows")]
impl RemoteMemory {
    pub fn new(process_id: u32) -> Result<RemoteMemory, RemoteMemoryError> {
        Ok(RemoteMemory {
            windows_remote_memory: windows::windows_remote_memory::WindowsRemoteMemory::new(
                process_id,
            )?,
        })
    }

    pub fn new_by_name(process_name: &str) -> Result<RemoteMemory, RemoteMemoryError> {
        Ok(RemoteMemory {
            windows_remote_memory:
                windows::windows_remote_memory::WindowsRemoteMemory::new_by_name(process_name)?,
        })
    }

    pub fn read_bytes(&self, address: usize, buffer: &mut [u8]) -> Result<(), RemoteMemoryError> {
        Ok(self.windows_remote_memory.read_bytes(address, buffer)?)
    }

    pub fn write_ptr(
        &self,
        address: usize,
        ptr: usize,
        num_bytes_to_write: usize,
    ) -> Result<(), RemoteMemoryError> {
        Ok(self
            .windows_remote_memory
            .write_ptr(address, ptr, num_bytes_to_write)?)
    }

    pub fn get_base_address(&self) -> usize {
        self.windows_remote_memory.base_module.mod_base_addr as usize
    }

    pub fn get_base_size(&self) -> usize {
        self.windows_remote_memory.base_module.mod_base_size as usize
    }
}

impl RemoteMemory {
    pub fn read<T: Sized + Copy>(&self, address: usize) -> Result<T, RemoteMemoryError> {
        let size = std::mem::size_of::<T>();
        let mut buffer: Vec<u8> = vec![0; size];
        self.read_bytes(address, &mut buffer)?;
        Ok(unsafe { (buffer.as_ptr() as *const T).read_unaligned() })
    }

    pub fn write_bytes(&self, address: usize, buffer: &[u8]) -> Result<(), RemoteMemoryError> {
        self.write_ptr(address, buffer.as_ptr() as usize, buffer.len())
    }

    pub fn write<T: Sized + Copy>(
        &self,
        address: usize,
        value: T,
    ) -> Result<(), RemoteMemoryError> {
        let size = std::mem::size_of::<T>();
        self.write_ptr(address, std::ptr::addr_of!(value) as usize, size)
    }

    pub fn find_signature(&self, signature: &Signature) -> Option<usize> {
        let base_address = self.get_base_address();
        let base_size = self.get_base_size();
        let mut buffer = vec![0; base_size];
        self.read_bytes(base_address, &mut buffer).ok()?;
        scanner::find_signature(&buffer, signature)
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_read_bytes() {
        let buffer = vec![0xFF, 0x00, 0x12, 0xCD];
        let buffer_ptr = buffer.as_ptr() as usize;
        let process_id = std::process::id();
        let remote_memory = super::RemoteMemory::new(process_id);
        assert!(remote_memory.is_ok());
        let remote_memory = remote_memory.unwrap();
        let mut read_buffer = vec![0; 4];
        assert!(remote_memory
            .read_bytes(buffer_ptr, &mut read_buffer)
            .is_ok());
        assert_eq!(buffer, read_buffer);
    }

    #[test]
    fn test_read_u32() {
        let value = 12345;
        let value_ptr = std::ptr::addr_of!(value) as usize;
        let process_id = std::process::id();
        let remote_memory = super::RemoteMemory::new(process_id);
        assert!(remote_memory.is_ok());
        let remote_memory = remote_memory.unwrap();
        let read_value = remote_memory.read::<u32>(value_ptr);
        assert!(read_value.is_ok());
        let read_value = read_value.unwrap();
        assert_eq!(read_value, value);
    }

    #[test]
    fn test_write_bytes() {
        let data = vec![0xFF, 0x00, 0x12, 0xCD];
        let buffer = vec![0; 4];
        let buffer_ptr = buffer.as_ptr() as usize;
        let process_id = std::process::id();
        let remote_memory = super::RemoteMemory::new(process_id);
        assert!(remote_memory.is_ok());
        let remote_memory = remote_memory.unwrap();
        assert_ne!(data, buffer);
        assert!(remote_memory.write_bytes(buffer_ptr, &data).is_ok());
        assert_eq!(data, buffer);
    }

    #[test]
    fn test_write_u32() {
        let data: usize = 12345;
        let buffer: usize = 0;
        let buffer_ptr = std::ptr::addr_of!(buffer) as usize;
        let process_id = std::process::id();
        let remote_memory = super::RemoteMemory::new(process_id);
        assert!(remote_memory.is_ok());
        let remote_memory = remote_memory.unwrap();
        assert_ne!(data, buffer);
        assert!(remote_memory.write::<usize>(buffer_ptr, data).is_ok());
        assert_eq!(data, buffer);
    }
}