pub trait MemoryView: Send {
Show 37 methods
// Required methods
fn read_raw_iter(
&mut self,
data: ReadRawMemOps<'_, '_, '_, '_>,
) -> Result<()>;
fn write_raw_iter(
&mut self,
data: WriteRawMemOps<'_, '_, '_, '_>,
) -> Result<()>;
fn metadata(&self) -> MemoryViewMetadata;
// Provided methods
fn read_iter<'a, 'b>(
&mut self,
inp: impl Iterator<Item = ReadData<'a>>,
out: Option<&mut ReadCallback<'b, 'a>>,
out_fail: Option<&mut ReadCallback<'b, 'a>>,
) -> Result<()> { ... }
fn read_raw_list(&mut self, data: &mut [ReadData<'_>]) -> PartialResult<()> { ... }
fn read_raw_into(
&mut self,
addr: Address,
out: &mut [u8],
) -> PartialResult<()> { ... }
fn read_raw(&mut self, addr: Address, len: usize) -> PartialResult<Vec<u8>> { ... }
fn read_into<T: Pod + ?Sized>(
&mut self,
addr: Address,
out: &mut T,
) -> PartialResult<()>
where Self: Sized { ... }
fn read<T: Pod + Sized>(&mut self, addr: Address) -> PartialResult<T>
where Self: Sized { ... }
fn read_addr32(&mut self, addr: Address) -> PartialResult<Address>
where Self: Sized { ... }
fn read_addr64(&mut self, addr: Address) -> PartialResult<Address>
where Self: Sized { ... }
fn read_addr_arch(
&mut self,
arch: ArchitectureObj,
addr: Address,
) -> PartialResult<Address>
where Self: Sized { ... }
fn read_ptr_into<U: PrimitiveAddress, T: Pod + ?Sized>(
&mut self,
ptr: Pointer<U, T>,
out: &mut T,
) -> PartialResult<()>
where Self: Sized { ... }
fn read_ptr<U: PrimitiveAddress, T: Pod + Sized>(
&mut self,
ptr: Pointer<U, T>,
) -> PartialResult<T>
where Self: Sized { ... }
fn write_iter<'a, 'b>(
&mut self,
inp: impl Iterator<Item = WriteData<'a>>,
out: Option<&mut WriteCallback<'b, 'a>>,
out_fail: Option<&mut WriteCallback<'b, 'a>>,
) -> Result<()> { ... }
fn write_raw_list(&mut self, data: &[WriteData<'_>]) -> PartialResult<()> { ... }
fn write_raw(&mut self, addr: Address, data: &[u8]) -> PartialResult<()> { ... }
fn write<T: Pod + ?Sized>(
&mut self,
addr: Address,
data: &T,
) -> PartialResult<()>
where Self: Sized { ... }
fn write_ptr<U: PrimitiveAddress, T: Pod + ?Sized>(
&mut self,
ptr: Pointer<U, T>,
data: &T,
) -> PartialResult<()>
where Self: Sized { ... }
fn read_char_array(
&mut self,
addr: Address,
len: usize,
) -> PartialResult<String> { ... }
fn read_char_string_n(
&mut self,
addr: Address,
n: usize,
) -> PartialResult<String> { ... }
fn read_char_string(&mut self, addr: Address) -> PartialResult<String> { ... }
fn read_utf8(
&mut self,
addr: Address,
max_length: usize,
) -> PartialResult<String> { ... }
fn read_utf8_lossy(
&mut self,
addr: Address,
max_length: usize,
) -> PartialResult<String> { ... }
fn cursor(&mut self) -> MemoryCursor<Fwd<&mut Self>> ⓘ
where Self: Sized { ... }
fn into_cursor(self) -> MemoryCursor<Self> ⓘ
where Self: Sized { ... }
fn cursor_at(&mut self, address: Address) -> MemoryCursor<Fwd<&mut Self>> ⓘ
where Self: Sized { ... }
fn into_cursor_at(self, address: Address) -> MemoryCursor<Self> ⓘ
where Self: Sized { ... }
fn batcher(&mut self) -> MemoryViewBatcher<'_, Self>
where Self: Sized { ... }
fn into_overlay_arch(self, arch: ArchitectureObj) -> ArchOverlayView<Self>
where Self: Sized { ... }
fn overlay_arch(
&mut self,
arch: ArchitectureObj,
) -> ArchOverlayView<Fwd<&mut Self>>
where Self: Sized { ... }
fn into_overlay_arch_parts(
self,
arch_bits: u8,
little_endian: bool,
) -> ArchOverlayView<Self>
where Self: Sized { ... }
fn overlay_arch_parts(
&mut self,
arch_bits: u8,
little_endian: bool,
) -> ArchOverlayView<Fwd<&mut Self>>
where Self: Sized { ... }
fn into_remap_view(
self,
mem_map: MemoryMap<(Address, umem)>,
) -> RemapView<Self>
where Self: Sized { ... }
fn remap_view(
&mut self,
mem_map: MemoryMap<(Address, umem)>,
) -> RemapView<Fwd<&mut Self>>
where Self: Sized { ... }
fn into_phys_mem(self) -> PhysicalMemoryOnView<Self>
where Self: Sized { ... }
fn phys_mem(&mut self) -> PhysicalMemoryOnView<Fwd<&mut Self>>
where Self: Sized { ... }
}Expand description
The MemoryView trait implements generic access to memory, no matter if it is a process
virtual memory, or machine’s physical memory.
The CPU accesses virtual memory by setting the CR3 register to the appropiate Directory Table Base (DTB) for that process. The ntoskrnl.exe Kernel Process has it’s own DTB. Using the DTB it is possible to resolve the physical memory location of a virtual address page. After the address has been resolved the physical memory page can then be read or written to.
There are 3 methods which are required to be implemented by the provider of this trait.
§Examples
Reading from a MemoryView:
use memflow::types::Address;
use memflow::mem::MemoryView;
fn read(mem: &mut impl MemoryView, read_addr: Address) {
let mut addr = 0u64;
mem.read_into(read_addr, &mut addr).unwrap();
println!("addr: {:x}", addr);
}Required Methods§
Sourcefn read_raw_iter(&mut self, data: ReadRawMemOps<'_, '_, '_, '_>) -> Result<()>
fn read_raw_iter(&mut self, data: ReadRawMemOps<'_, '_, '_, '_>) -> Result<()>
Raw read operation.
This is the most flexible type of read. One of the read helpers are usually preferred, such
as read or read_iter, but you may wish to
use this function to customize metadata behavior.
§Examples
Custom metadata tagging:
use memflow::types::Address;
use memflow::mem::{MemoryView, mem_data::{MemOps, ReadData}};
use memflow::types::umem;
use memflow::cglue::{CTup2, CTup3};
fn read(mut mem: impl MemoryView, read_addrs: &[Address]) {
let mut bufs = vec![0u8; 16 * read_addrs.len()];
let data = read_addrs
.iter()
.zip(bufs.chunks_mut(16))
.enumerate()
.map(|(i, (&a, chunk))| CTup3(
a,
// Sum `i` with the chunk's address so that we can reverse the process
Address::from((i as umem).wrapping_add(chunk.as_ptr() as usize as umem)),
chunk.into()
));
let mut succeeded = vec![0; read_addrs.len()];
let callback = &mut |CTup2(mdata, d): ReadData| {
// `d = orig_chunk + offset`
// `mdata = i + d = i + orig_chunk + offset`
// We can remove (orig_chunk + offset) by subtracting d from mdata:
// Make sure to use wrapping math!
let idx = mdata.wrapping_sub(Address::from(d.as_ptr() as usize)).to_umem();
succeeded[idx as usize] += 1;
true
};
let mut failed = vec![0; read_addrs.len()];
let callback_fail = &mut |CTup2(mdata, d): ReadData| {
// Same as success callback
let idx = mdata.wrapping_sub(Address::from(d.as_ptr() as usize)).to_umem();
failed[idx as usize] += 1;
true
};
MemOps::with_raw(
data,
Some(&mut callback.into()),
Some(&mut callback_fail.into()),
|data| mem.read_raw_iter(data),
).unwrap();
}fn write_raw_iter(&mut self, data: WriteRawMemOps<'_, '_, '_, '_>) -> Result<()>
fn metadata(&self) -> MemoryViewMetadata
Provided Methods§
Sourcefn read_iter<'a, 'b>(
&mut self,
inp: impl Iterator<Item = ReadData<'a>>,
out: Option<&mut ReadCallback<'b, 'a>>,
out_fail: Option<&mut ReadCallback<'b, 'a>>,
) -> Result<()>
fn read_iter<'a, 'b>( &mut self, inp: impl Iterator<Item = ReadData<'a>>, out: Option<&mut ReadCallback<'b, 'a>>, out_fail: Option<&mut ReadCallback<'b, 'a>>, ) -> Result<()>
Read arbitrary amount of data.
§Arguments
inp- input iterator of (address, buffer) pairs.out- optional callback for any successful reads - along the wayinppairs may be split and only parts of the reads may succeed. This callback will return any successful chunks that have their buffers filled in.out_fail- optional callback for any unsuccessful reads - this is the opposite ofout, meaning any unsuccessful chunks with buffers in an unspecified state.
§Examples
use memflow::types::Address;
use memflow::mem::MemoryView;
use memflow::cglue::CTup2;
fn read(mut mem: impl MemoryView, read_addrs: &[Address]) {
let mut bufs = vec![0u8; 8 * read_addrs.len()];
let data = read_addrs
.iter()
.zip(bufs.chunks_mut(8))
.map(|(&a, chunk)| CTup2(a, chunk.into()));
mem.read_iter(data, None, None).unwrap();
println!("{:?}", bufs);
}fn read_raw_list(&mut self, data: &mut [ReadData<'_>]) -> PartialResult<()>
fn read_raw_into(&mut self, addr: Address, out: &mut [u8]) -> PartialResult<()>
Sourcefn read_raw(&mut self, addr: Address, len: usize) -> PartialResult<Vec<u8>>
fn read_raw(&mut self, addr: Address, len: usize) -> PartialResult<Vec<u8>>
Reads raw bytes from the specified address into a byte vector.
Any data that cannot be read will be defaulted to zero bytes (0x00).
The returned vector is always exactly len bytes long, with unreadable
portions guaranteed to be zero-initialized.
§Arguments
addr- The memory address to read fromlen- The number of bytes to read
§Returns
A PartialResult<Vec<u8>> containing the byte vector, where unread
portions are guaranteed to be zero.
fn read_into<T: Pod + ?Sized>(
&mut self,
addr: Address,
out: &mut T,
) -> PartialResult<()>where
Self: Sized,
Sourcefn read<T: Pod + Sized>(&mut self, addr: Address) -> PartialResult<T>where
Self: Sized,
fn read<T: Pod + Sized>(&mut self, addr: Address) -> PartialResult<T>where
Self: Sized,
Reads a value of type T from the specified address.
Any data that cannot be read will be defaulted to zero bytes (0x00). This ensures that partially readable memory regions return valid data with unreadable portions zero-initialized.
Uses stack allocation for types <= 1KB, heap allocation for larger types.
§Safety
This function is safe for Pod types as any bit pattern is valid.
§Returns
A PartialResult<T> containing the read value, where unread portions
are guaranteed to be zero.
fn read_addr32(&mut self, addr: Address) -> PartialResult<Address>where
Self: Sized,
fn read_addr64(&mut self, addr: Address) -> PartialResult<Address>where
Self: Sized,
fn read_addr_arch(
&mut self,
arch: ArchitectureObj,
addr: Address,
) -> PartialResult<Address>where
Self: Sized,
fn read_ptr_into<U: PrimitiveAddress, T: Pod + ?Sized>(
&mut self,
ptr: Pointer<U, T>,
out: &mut T,
) -> PartialResult<()>where
Self: Sized,
fn read_ptr<U: PrimitiveAddress, T: Pod + Sized>(
&mut self,
ptr: Pointer<U, T>,
) -> PartialResult<T>where
Self: Sized,
Sourcefn write_iter<'a, 'b>(
&mut self,
inp: impl Iterator<Item = WriteData<'a>>,
out: Option<&mut WriteCallback<'b, 'a>>,
out_fail: Option<&mut WriteCallback<'b, 'a>>,
) -> Result<()>
fn write_iter<'a, 'b>( &mut self, inp: impl Iterator<Item = WriteData<'a>>, out: Option<&mut WriteCallback<'b, 'a>>, out_fail: Option<&mut WriteCallback<'b, 'a>>, ) -> Result<()>
Write arbitrary amount of data.
§Arguments
inp- input iterator of (address, buffer) pairs.out- optional callback for any successful writes - along the wayinppairs may be split and only parts of the writes may succeed. This callback will return any successful chunks that have their buffers filled in.out_fail- optional callback for any unsuccessful writes - this is the opposite ofout, meaning any unsuccessful chunks with buffers in an unspecified state.
§Examples
use memflow::types::Address;
use memflow::mem::MemoryView;
use memflow::cglue::CTup2;
use dataview::PodMethods;
fn write(mut mem: impl MemoryView, writes: &[(Address, usize)]) {
let data = writes
.iter()
.map(|(a, chunk)| CTup2(*a, chunk.as_bytes().into()));
mem.write_iter(data, None, None).unwrap();
}fn write_raw_list(&mut self, data: &[WriteData<'_>]) -> PartialResult<()>
fn write_raw(&mut self, addr: Address, data: &[u8]) -> PartialResult<()>
fn write<T: Pod + ?Sized>(
&mut self,
addr: Address,
data: &T,
) -> PartialResult<()>where
Self: Sized,
fn write_ptr<U: PrimitiveAddress, T: Pod + ?Sized>(
&mut self,
ptr: Pointer<U, T>,
data: &T,
) -> PartialResult<()>where
Self: Sized,
Sourcefn read_char_array(
&mut self,
addr: Address,
len: usize,
) -> PartialResult<String>
👎Deprecated: please use read_utf8 or read_utf8_lossy instead
fn read_char_array( &mut self, addr: Address, len: usize, ) -> PartialResult<String>
Reads a fixed length string from the target.
§Remarks:
The string does not have to be null-terminated.
If a null terminator is found the string is truncated to the terminator.
If no null terminator is found the resulting string is exactly len characters long.
Sourcefn read_char_string_n(
&mut self,
addr: Address,
n: usize,
) -> PartialResult<String>
👎Deprecated: please use read_utf8 or read_utf8_lossy instead
fn read_char_string_n( &mut self, addr: Address, n: usize, ) -> PartialResult<String>
Reads a variable length string with a length of up to specified amount from the target.
§Arguments
addr- target address to read fromn- maximum number of bytes to read
§Remarks:
The string must be null-terminated. If no null terminator is found the this function will return an error.
For reading fixed-size char arrays the read_char_array should be used.
Sourcefn read_char_string(&mut self, addr: Address) -> PartialResult<String>
👎Deprecated: please use read_utf8 or read_utf8_lossy instead
fn read_char_string(&mut self, addr: Address) -> PartialResult<String>
Reads a variable length string with up to 4kb length from the target.
§Arguments
addr- target address to read from
Sourcefn read_utf8(
&mut self,
addr: Address,
max_length: usize,
) -> PartialResult<String>
fn read_utf8( &mut self, addr: Address, max_length: usize, ) -> PartialResult<String>
Reads a string at the given position with a length of up to max_length characters.
Not all byte slices are valid Strings, however: String
requires that it is valid UTF-8. from_utf8() checks to ensure that
the bytes are valid UTF-8, and then does the conversion.
§Remarks
If this string contains a ‘\0’ terminator the returned string is clamped to the position of the terminator.
If the string contains no terminator the a string up to max_length characters is returned.
§Examples
Reading from a MemoryView:
use memflow::types::Address;
use memflow::mem::MemoryView;
fn read(mem: &mut impl MemoryView, read_addr: Address) {
let str = mem.read_utf8(read_addr, 32).unwrap();
println!("str: {}", str);
}Sourcefn read_utf8_lossy(
&mut self,
addr: Address,
max_length: usize,
) -> PartialResult<String>
fn read_utf8_lossy( &mut self, addr: Address, max_length: usize, ) -> PartialResult<String>
Reads a string at the given position with a length of up to max_length characters.
Not all byte slices are valid strings, however: strings
are required to be valid UTF-8. During this conversion,
from_utf8_lossy() will replace any invalid UTF-8 sequences with
U+FFFD REPLACEMENT CHARACTER, which looks like this: �
If our byte slice is invalid UTF-8, then we need to insert the replacement characters,
which will change the size of the string, and hence, require a String. But if
it’s already valid UTF-8, we don’t need a new allocation. This return
type allows us to handle both cases.
§Remarks
If this string contains a ‘\0’ terminator the returned string is clamped to the position of the terminator.
If the string contains no terminator the a string up to max_length characters is returned.
§Examples
Reading from a MemoryView:
use memflow::types::Address;
use memflow::mem::MemoryView;
fn read(mem: &mut impl MemoryView, read_addr: Address) {
let str = mem.read_utf8_lossy(read_addr, 32).unwrap();
println!("str: {}", str);
}Sourcefn cursor(&mut self) -> MemoryCursor<Fwd<&mut Self>> ⓘwhere
Self: Sized,
fn cursor(&mut self) -> MemoryCursor<Fwd<&mut Self>> ⓘwhere
Self: Sized,
Returns a cursor over this memory view. See MemoryCursor for more details.
Sourcefn into_cursor(self) -> MemoryCursor<Self> ⓘwhere
Self: Sized,
fn into_cursor(self) -> MemoryCursor<Self> ⓘwhere
Self: Sized,
Converts this memory view into a cursor. See MemoryCursor for more details.
Sourcefn cursor_at(&mut self, address: Address) -> MemoryCursor<Fwd<&mut Self>> ⓘwhere
Self: Sized,
fn cursor_at(&mut self, address: Address) -> MemoryCursor<Fwd<&mut Self>> ⓘwhere
Self: Sized,
Returns a cursor over this memory view at the specified address. See MemoryCursor for more details.
Sourcefn into_cursor_at(self, address: Address) -> MemoryCursor<Self> ⓘwhere
Self: Sized,
fn into_cursor_at(self, address: Address) -> MemoryCursor<Self> ⓘwhere
Self: Sized,
Converts this memory view into a cursor at the specified address. See MemoryCursor for more details.
fn batcher(&mut self) -> MemoryViewBatcher<'_, Self>where
Self: Sized,
fn into_overlay_arch(self, arch: ArchitectureObj) -> ArchOverlayView<Self>where
Self: Sized,
fn overlay_arch(
&mut self,
arch: ArchitectureObj,
) -> ArchOverlayView<Fwd<&mut Self>>where
Self: Sized,
fn into_overlay_arch_parts(
self,
arch_bits: u8,
little_endian: bool,
) -> ArchOverlayView<Self>where
Self: Sized,
fn overlay_arch_parts(
&mut self,
arch_bits: u8,
little_endian: bool,
) -> ArchOverlayView<Fwd<&mut Self>>where
Self: Sized,
fn into_remap_view(self, mem_map: MemoryMap<(Address, umem)>) -> RemapView<Self>where
Self: Sized,
fn remap_view(
&mut self,
mem_map: MemoryMap<(Address, umem)>,
) -> RemapView<Fwd<&mut Self>>where
Self: Sized,
fn into_phys_mem(self) -> PhysicalMemoryOnView<Self>where
Self: Sized,
fn phys_mem(&mut self) -> PhysicalMemoryOnView<Fwd<&mut Self>>where
Self: Sized,
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.