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>
impl<'a> VmmScatterMemory<'a>
Sourcepub fn prepare_ex(
&mut self,
data_to_read: &'a mut (u64, Vec<u8>, u32),
) -> ResultEx<()>
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 onmem_scatter.execute()
call. Should be zero at call tomem_scatter.prepare_ex()
.
Sourcepub fn prepare_ex_as<T>(
&mut self,
data_to_read: &'a mut (u64, T, u32),
) -> ResultEx<()>
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 onmem_scatter.execute()
call. Should be zero at call tomem_scatter.prepare_ex()
.
Source§impl VmmScatterMemory<'_>
impl VmmScatterMemory<'_>
Sourcepub fn prepare(&self, va: u64, size: usize) -> ResultEx<()>
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.
Sourcepub fn prepare_as<T>(&self, va: u64) -> ResultEx<()>
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.
Sourcepub fn prepare_write(&self, va: u64, data: &[u8]) -> ResultEx<()>
pub fn prepare_write(&self, va: u64, data: &[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.
Sourcepub fn prepare_write_as<T>(&self, va: u64, data: &T) -> ResultEx<()>
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.
Sourcepub fn execute(&self) -> ResultEx<()>
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()
.
Sourcepub fn read(&self, va: u64, size: usize) -> ResultEx<Vec<u8>>
pub fn read(&self, va: u64, size: usize) -> ResultEx<Vec<u8>>
Read memory prepared after the execute()
call.
Sourcepub fn read_as<T>(&self, va: u64) -> ResultEx<T>
pub fn read_as<T>(&self, va: u64) -> ResultEx<T>
Read memory prepared after the execute()
call.