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())
    }
}