memlib 0.1.3

An abstraction layer for interacting with memory
Documentation
use std::cell::RefCell;
use memlib::{MemoryRead, MemoryReadExt, MemoryWrite, MemoryWriteExt};

/// An example memory source we will use to implement memlib traits onto.
/// This can be replaced with an actual process in implementation.
/// This needs to contain a RefCell to implement MemoryWrite because the trait only takes &self
pub struct MemorySource(RefCell<Vec<u8>>);

impl MemorySource {
    pub fn new() -> Self {
        Self(RefCell::new(vec![0xAB; 0x1000]))
    }
}

impl memlib::MemoryRead for MemorySource {
    fn try_read_bytes_into(&self, address: u64, buffer: &mut [u8]) -> Option<()> {
        let buf = self.0.borrow();
        // Check if the read is out of bounds
        if address as usize + buffer.len() > buf.len() {
            return None;
        }

        // Copy the bytes from the source into the buffer
        buffer.copy_from_slice(&buf[address as usize..address as usize + buffer.len()]);

        Some(())
    }
}

impl memlib::MemoryWrite for MemorySource {
    fn try_write_bytes(&self, address: u64, buffer: &[u8]) -> Option<()> {
        let buf = self.0.borrow_mut();
        // Check if the write is out of bounds
        if address as usize + buffer.len() > self.0.len() {
            return None;
        }

        // Copy the bytes from the buffer into the source
        self.0.borrow_mut()[address as usize..address as usize + buffer.len()].copy_from_slice(buffer);

        Some(())
    }
}


fn main() {
    // Create the memory source
    let memory_source = MemorySource::new();

    // Read 4 bytes at offset 0x10
    let mut buffer = [0u8; 4];
    memory_source.try_read_bytes_into(0x10, &mut buffer).unwrap();
    assert_eq!(buffer, [0xAB, 0xAB, 0xAB, 0xAB]);

    // We can also do this with the helper functions inside MemoryRead and MemoryReadExt
    use memlib::MemoryReadExt;
    let val = memory_source.read::<u32>(0x10);
    assert_eq!(val, 0xABABABAB);

    // Now let's write some bytes
    let buffer = [0xCD; 4];
    memory_source.try_write_bytes(0x10, &buffer).unwrap();

    // We can also write with the helper functions
    memory_source.write(0x10, &0xCDCDCDCD);

    let val = memory_source.read::<u32>(0x10);
    assert_eq!(val, 0xCDCDCDCD);
}

pub struct TestBuffer(*mut [u8]);

impl TestBuffer {
    pub fn new() -> Self {
        Self(Box::into_raw(Box::new([0u8; 0x1000])))
    }

    pub fn read_offset(&self, offset: u64) -> u8 {
        unsafe {
            if offset as usize >= (*self.0).len() {
                panic!("Out of bounds");
            }
            (*self.0).as_ptr().offset(offset as isize).read_volatile()
        }
    }

    pub fn write_offset(&self, offset: u64, value: u8) {
        unsafe {
            if offset as usize >= (*self.0).len() {
                panic!("Out of bounds");
            }
            (*self.0).as_ptr().offset(offset as isize).write_volatile(value)
        }
    }
}