1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! Provides functions to interact with memory.
use core::{fmt, ptr, mem};
use crate::sys::*;
use crate::utils::{self, Result};
///Convenient wrapper over [MEMORY_BASIC_INFORMATION](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx)
pub struct Info(pub MEMORY_BASIC_INFORMATION);
impl Info {
#[inline]
///Returns region's base address
///
///Memory can be read from this address up to `<base> + <region size>`
///
///You can get this pointer by accessing inner structure `self.0.BaseAddress`
pub fn base_addr(&self) -> usize {
self.0.BaseAddress as usize
}
#[inline]
///Returns Allocation base.
///
///You can get this pointer by accessing inner structure `self.0.AllocationBase`
pub fn alloc_base(&self) -> usize {
self.0.AllocationBase as usize
}
#[inline]
///Returns memory size.
pub fn size(&self) -> SIZE_T {
self.0.RegionSize
}
#[inline]
///Returns whether memory is committed or not.
///
///Basically it is in use currently
pub fn is_commit(&self) -> bool {
self.0.State == MEM_COMMIT
}
#[inline]
///Returns whether memory is free or not.
pub fn is_free(&self) -> bool {
self.0.State == MEM_FREE
}
#[inline]
///Returns whether memory is reserved or not.
///
///This space is not backed by actual physical storage.
pub fn is_reserved(&self) -> bool {
self.0.State == MEM_RESERVE
}
}
impl fmt::Debug for Info {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Info {{ BaseAddress={:p}, AllocationBase={:p}, AllocationProtect={}, RegionSize={}, State={}, Protect={}, Type={} }}",
self.0.BaseAddress, self.0.AllocationBase, self.0.AllocationProtect, self.0.RegionSize, self.0.State, self.0.Protect, self.0.Type)
}
}
///Iterator over memory regions
///
///Returns memory addresses
pub struct Virtual {
handle: HANDLE,
addr: *const u8
}
impl Virtual {
///Creates new instance to retrieve memory regions of provided process.
///
///It is assumed that handle is valid, if it is not then nothing can be retrieved.
pub fn new(handle: HANDLE) -> Self {
Virtual {
handle,
addr: ptr::null()
}
}
}
impl Iterator for Virtual {
type Item = Info;
fn next(&mut self) -> Option<Self::Item> {
virtual_query_ex(self.handle, self.addr as *const c_void).ok().map(|info| {
self.addr = unsafe { self.addr.add(info.size()) };
info
})
}
}
///Retrieves information about virtual memory of specified process.
///
///Wrapper over `VirtualQueryEx`
///
///In case no information is available i.e. `VirtualQueryEx` returns 0
///function returns None.
///
///# Note:
///
///When using this function on process of different bitness it might not work correctly.
pub fn virtual_query_ex(handle: HANDLE, base: *const c_void) -> Result<Info> {
let mut info: MEMORY_BASIC_INFORMATION = unsafe { mem::zeroed() };
if unsafe { VirtualQueryEx(handle, base, &mut info as *mut _, mem::size_of_val(&info) as SIZE_T) } != 0 {
Ok(Info(info))
}
else {
Err(utils::get_last_error())
}
}