pub struct VmmScatterMemory<'a> { /* private fields */ }
Expand description

Efficient Memory Reading API.

The Scatter Memory API allows reading several scattered memory regions at the same time in one pass - greatly improving efficiency over multiple normal memory reads.

The Rust Scatter API may be used in two different ways, both are displayed below in the examples section.

§Created By

§Example #1

// Example: vmmprocess.mem_scatter() #1:
// This example will show how it's possible to use VmmScatterMemory to
// more efficiently read memory from the underlying device.
{
    // Example: vmmprocess.mem_scatter():
    // Retrieve a scatter memory read object that may be used to batch
    // several reads/writes into one efficient call to the memory device.
    println!("========================================");
    println!("vmmprocess.mem_scatter() #1:");
    let mem_scatter = vmmprocess.mem_scatter(FLAG_NOCACHE | FLAG_ZEROPAD_ON_FAIL)?;
    println!("mem_scatter = {mem_scatter}");
    // Prepare three memory ranges to read.
    let _r = mem_scatter.prepare(kernel32.va_base + 0x0000, 0x100);
    let _r = mem_scatter.prepare(kernel32.va_base + 0x1000, 0x100);
    let _r = mem_scatter.prepare(kernel32.va_base + 0x2000, 0x100);
    // Perform the actual read (and writes) by calling the execute() function.
    let _r = mem_scatter.execute();
    // Fetch data read. It's possible (but wasteful) to read less data than was prepared.
    if let Ok(data_read) = mem_scatter.read(kernel32.va_base + 0x0000, 0x80) {
        println!("memory range: va={:x} cb={:x} cb_read={:x}", kernel32.va_base + 0x0000, 0x80, data_read.len());
        println!("{:?}", data_read.hex_dump());
        println!("-----------------------");
    }
    if let Ok(data_read) = mem_scatter.read(kernel32.va_base + 0x1000, 0x100) {
        println!("memory range: va={:x} cb={:x} cb_read={:x}", kernel32.va_base + 0x1000, 0x100, data_read.len());
        println!("{:?}", data_read.hex_dump());
        println!("-----------------------");
    }
    // It's possible to do a re-read of the ranges by calling execute again!
    let _r = mem_scatter.execute();
    if let Ok(data_read) = mem_scatter.read(kernel32.va_base + 0x0000, 0x80) {
        println!("memory range: va={:x} cb={:x} cb_read={:x}", kernel32.va_base + 0x0000, 0x80, data_read.len());
        println!("{:?}", data_read.hex_dump());
        println!("-----------------------");
    }
    // It's also possible to clear the VmmScatterMemory to start anew.
    // Clearing is slightly more efficient than creating a new object.
    // let _r = mem_scatter.clear();
 
    // NB! the VmmScatterMemory struct will be automatically free'd
    //     on the native backend when it goes out of scope.
}

§Example #2

// Example: vmmprocess.mem_scatter() #2:
// This example demo how it's possible to use the prepare_ex function
// which will populate the prepared data regions automatically when the
// VmmScatterMemory is dropped.
// It's not recommended to mix the #1 and #2 syntaxes.
{
    // memory ranges to read are tuples:
    // .0 = the virtual address to read.
    // .1 = vector of u8 which memory should be read into.
    // .2 = u32 receiving the bytes successfully read data.
    let mut memory_range_1 = (kernel32.va_base + 0x0000, vec![0u8; 0x100], 0u32);
    let mut memory_range_2 = (kernel32.va_base + 0x1000, vec![0u8; 0x100], 0u32);
    let mut memory_range_3 = (kernel32.va_base + 0x2000, vec![0u8; 0x100], 0u32);
    // Feed the ranges into a mutable VmmScatterMemory inside a
    // separate scope. The actual memory read will take place when
    // the VmmScatterMemory goes out of scope and are dropped.
    println!("========================================");
    println!("vmmprocess.mem_scatter() #2:");
    if let Ok(mut mem_scatter) = vmmprocess.mem_scatter(FLAG_NOCACHE | FLAG_ZEROPAD_ON_FAIL) {
        let _r = mem_scatter.prepare_ex(&mut memory_range_1);
        let _r = mem_scatter.prepare_ex(&mut memory_range_2);
        let _r = mem_scatter.prepare_ex(&mut memory_range_3);
    }
    // Results should now be available in the memory ranges if the read
    // was successful. Note that there is no guarantee that memory is
    // read - make sure to check the .2 item - number of bytes read.
    for memory_range in [memory_range_1, memory_range_2, memory_range_3] {
        println!("memory range: va={:x} cb={:x} cb_read={:x}", memory_range.0, memory_range.1.len(), memory_range.2);
        println!("{:?}", memory_range.1.hex_dump());
        println!("-----------------------");
    }
}

Implementations§

source§

impl<'a> VmmScatterMemory<'a>

source

pub fn prepare_ex( &mut self, data_to_read: &'a mut (u64, Vec<u8>, u32) ) -> ResultEx<()>

Prepare a memory range for reading according to method #2.

Once the mem_scatter.execute() call has been made the memory read should (if successful) be found in the prepared tuple.

See the VmmScatterMemory struct for an example.

§Arguments
  • data_to_read - Tuple with data to prepare as below:
    • data_to_read.0 - Address to start read from.
    • data_to_read.1 - Byte Vec with space to fill with read data on success.
    • data_to_read.2 - Bytes actually read on mem_scatter.execute() call. Should be zero at call to mem_scatter.prepare_ex().
source

pub fn prepare_ex_as<T>( &mut self, data_to_read: &'a mut (u64, T, u32) ) -> ResultEx<()>

Prepare a memory range for reading according to method #2.

Once the mem_scatter.execute() call has been made the memory read should (if successful) be found in the prepared tuple.

See the VmmScatterMemory struct for an example.

§Arguments
  • data_to_read - Tuple with data to prepare as below:
    • data_to_read.0 - Address to start read from.
    • data_to_read.1 - Generic Type/Struct to fill with read data on success.
    • data_to_read.2 - Bytes actually read on mem_scatter.execute() call. Should be zero at call to mem_scatter.prepare_ex().
source§

impl VmmScatterMemory<'_>

source

pub fn prepare(&self, va: u64, size: usize) -> ResultEx<()>

Prepare a memory range for reading according to method #1.

Once the mem_scatter.execute() call has been made it’s possible to read the memory by calling mem_scatter.read().

See the VmmScatterMemory struct for an example.

§Arguments
  • va - Address to prepare to read from.
  • size - Number of bytes to read.
source

pub fn prepare_as<T>(&self, va: u64) -> ResultEx<()>

Prepare a memory range for reading according to method #1.

Once the mem_scatter.execute() call has been made it’s possible to read the memory by calling mem_scatter.read().

See the VmmScatterMemory struct for an example.

§Arguments
  • va - Address to prepare to read from.
source

pub fn prepare_write(&self, va: u64, data: &Vec<u8>) -> ResultEx<()>

Prepare a memory range for writing.

Writing takes place on the call to mem_scatter.execute().

§Arguments
  • va - Address to prepare to write to.
  • data - Data to write.
source

pub fn prepare_write_as<T>(&self, va: u64, data: &T) -> ResultEx<()>

Prepare a memory range for writing.

Writing takes place on the call to mem_scatter.execute().

§Arguments
  • va - Address to prepare to write to.
  • data - Data to write. In case of a struct repr(C) is recommended.
source

pub fn execute(&self) -> ResultEx<()>

Execute the scatter call to the underlying memory device.

This function takes care of all reading and writing. After this function is called it’s possible to read memory, or if approach #2 is used the memory should already be read into buffers prepared with the call to mem_scatter.prepare_ex().

source

pub fn read(&self, va: u64, size: usize) -> ResultEx<Vec<u8>>

Read memory prepared after the execute() call.

source

pub fn read_as<T>(&self, va: u64) -> ResultEx<T>

Read memory prepared after the execute() call.

source

pub fn clear(&self) -> ResultEx<()>

Clear the scatter memory for additional read/writes.

Trait Implementations§

source§

impl<'a> Debug for VmmScatterMemory<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for VmmScatterMemory<'_>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Drop for VmmScatterMemory<'_>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for VmmScatterMemory<'a>

§

impl<'a> RefUnwindSafe for VmmScatterMemory<'a>

§

impl<'a> Send for VmmScatterMemory<'a>

§

impl<'a> Sync for VmmScatterMemory<'a>

§

impl<'a> Unpin for VmmScatterMemory<'a>

§

impl<'a> UnwindSafe for VmmScatterMemory<'a>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToString for T
where T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.