1use once_cell::unsync::OnceCell;
2use vmi_core::{
3 Architecture, MemoryAccess, Va, VmiDriver, VmiError, VmiState, VmiVa,
4 os::{VmiOsRegion, VmiOsRegionKind},
5};
6
7use super::{WindowsControlArea, macros::impl_offsets};
8use crate::{ArchAdapter, OffsetsExt, WindowsOs};
9
10pub struct WindowsRegion<'a, Driver>
20where
21 Driver: VmiDriver,
22 Driver::Architecture: Architecture + ArchAdapter<Driver>,
23{
24 vmi: VmiState<'a, Driver, WindowsOs<Driver>>,
26
27 va: Va,
29
30 vad_flags: OnceCell<u64>,
32}
33
34impl<Driver> VmiVa for WindowsRegion<'_, Driver>
35where
36 Driver: VmiDriver,
37 Driver::Architecture: Architecture + ArchAdapter<Driver>,
38{
39 fn va(&self) -> Va {
40 self.va
41 }
42}
43
44impl<Driver> std::fmt::Debug for WindowsRegion<'_, Driver>
45where
46 Driver: VmiDriver,
47 Driver::Architecture: Architecture + ArchAdapter<Driver>,
48{
49 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
50 let start = self.start();
51 let end = self.end();
52 let protection = self.protection();
53 f.debug_struct("WindowsOsRegion")
56 .field("start", &start)
57 .field("end", &end)
58 .field("protection", &protection)
59 .finish()
61 }
62}
63
64impl<'a, Driver> WindowsRegion<'a, Driver>
65where
66 Driver: VmiDriver,
67 Driver::Architecture: Architecture + ArchAdapter<Driver>,
68{
69 impl_offsets!();
70
71 pub fn new(vmi: VmiState<'a, Driver, WindowsOs<Driver>>, vad: Va) -> Self {
73 Self {
74 vmi,
75 va: vad,
76 vad_flags: OnceCell::new(),
77 }
78 }
79
80 pub fn starting_vpn(&self) -> Result<u64, VmiError> {
87 let offsets = self.offsets();
88 let MMVAD_SHORT = &offsets._MMVAD_SHORT;
89
90 let starting_vpn_low = self.vmi.read_field(self.va, &MMVAD_SHORT.StartingVpn)?;
91 let starting_vpn_high = match &MMVAD_SHORT.StartingVpnHigh {
92 Some(StartingVpnHigh) => self.vmi.read_field(self.va, StartingVpnHigh)?,
93 None => 0,
94 };
95
96 Ok((starting_vpn_high << 32) | starting_vpn_low)
97 }
98
99 pub fn ending_vpn(&self) -> Result<u64, VmiError> {
106 let offsets = self.offsets();
107 let MMVAD_SHORT = &offsets._MMVAD_SHORT;
108
109 let ending_vpn_low = self.vmi.read_field(self.va, &MMVAD_SHORT.EndingVpn)?;
110 let ending_vpn_high = match &MMVAD_SHORT.EndingVpnHigh {
111 Some(EndingVpnHigh) => self.vmi.read_field(self.va, EndingVpnHigh)?,
112 None => 0,
113 };
114
115 Ok((ending_vpn_high << 32) | ending_vpn_low)
116 }
117
118 pub fn vad_flags(&self) -> Result<u64, VmiError> {
128 self.vad_flags
129 .get_or_try_init(|| {
130 let offsets = self.offsets();
131 let MMVAD_SHORT = &offsets._MMVAD_SHORT;
132
133 self.vmi.read_field(self.va, &MMVAD_SHORT.VadFlags)
134 })
135 .copied()
136 }
137
138 pub fn vad_type(&self) -> Result<u8, VmiError> {
144 let offsets = self.offsets();
145 let MMVAD_FLAGS = &offsets._MMVAD_FLAGS;
146
147 let vad_flags = self.vad_flags()?;
148 Ok(MMVAD_FLAGS.VadType.extract(vad_flags) as u8)
149 }
150
151 pub fn vad_protection(&self) -> Result<u8, VmiError> {
157 let offsets = self.offsets();
158 let MMVAD_FLAGS = &offsets._MMVAD_FLAGS;
159
160 let flags = self.vad_flags()?;
161 let protection = MMVAD_FLAGS.Protection.extract(flags) as u8;
162
163 Ok(protection)
164 }
165
166 pub fn private_memory(&self) -> Result<bool, VmiError> {
172 let offsets = self.offsets();
173 let MMVAD_FLAGS = &offsets._MMVAD_FLAGS;
174
175 let vad_flags = self.vad_flags()?;
176 Ok(MMVAD_FLAGS.PrivateMemory.extract(vad_flags) != 0)
177 }
178
179 pub fn mem_commit(&self) -> Result<bool, VmiError> {
186 let offsets = self.offsets();
187 let MMVAD_FLAGS = &offsets._MMVAD_FLAGS;
188 let MMVAD_SHORT = &offsets._MMVAD_SHORT;
189
190 let vad_flags = self.vad_flags()?;
191
192 let mem_commit = match MMVAD_FLAGS.MemCommit {
196 Some(MemCommit) => MemCommit.extract(vad_flags) != 0,
198 None => match (&self.offsets().ext(), MMVAD_SHORT.VadFlags1) {
199 (Some(OffsetsExt::V2(offsets)), Some(VadFlags1)) => {
201 let MMVAD_FLAGS1 = &offsets._MMVAD_FLAGS1;
202 let vad_flags1 = self.vmi.read_field(self.va, &VadFlags1)?;
203 MMVAD_FLAGS1.MemCommit.extract(vad_flags1) != 0
204 }
205 _ => {
206 panic!("Failed to read MemCommit from VAD");
207 }
208 },
209 };
210
211 Ok(mem_commit)
212 }
213
214 pub fn left_child(&self) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
220 let offsets = self.offsets();
221 let MMVAD_SHORT = &offsets._MMVAD_SHORT;
222
223 let left_child = self.vmi.read_field(self.va, &MMVAD_SHORT.Left)?;
224
225 if left_child == 0 {
226 return Ok(None);
227 }
228
229 Ok(Some(WindowsRegion::new(self.vmi, Va(left_child))))
230 }
231
232 pub fn right_child(&self) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
238 let offsets = self.offsets();
239 let MMVAD_SHORT = &offsets._MMVAD_SHORT;
240
241 let right_child = self.vmi.read_field(self.va, &MMVAD_SHORT.Right)?;
242
243 if right_child == 0 {
244 return Ok(None);
245 }
246
247 Ok(Some(WindowsRegion::new(self.vmi, Va(right_child))))
248 }
249}
250
251impl<'a, Driver> VmiOsRegion<'a, Driver> for WindowsRegion<'a, Driver>
252where
253 Driver: VmiDriver,
254 Driver::Architecture: Architecture + ArchAdapter<Driver>,
255{
256 type Os = WindowsOs<Driver>;
257
258 fn start(&self) -> Result<Va, VmiError> {
265 Ok(Va(self.starting_vpn()? << 12))
266 }
267
268 fn end(&self) -> Result<Va, VmiError> {
275 Ok(Va((self.ending_vpn()? + 1) << 12))
276 }
277
278 fn protection(&self) -> Result<MemoryAccess, VmiError> {
284 const MM_ZERO_ACCESS: u8 = 0; const MM_READONLY: u8 = 1;
286 const MM_EXECUTE: u8 = 2;
287 const MM_EXECUTE_READ: u8 = 3;
288 const MM_READWRITE: u8 = 4; const MM_WRITECOPY: u8 = 5;
290 const MM_EXECUTE_READWRITE: u8 = 6;
291 const MM_EXECUTE_WRITECOPY: u8 = 7;
292
293 match self.vad_protection()? {
294 MM_ZERO_ACCESS => Ok(MemoryAccess::default()),
295 MM_READONLY => Ok(MemoryAccess::R),
296 MM_EXECUTE => Ok(MemoryAccess::X),
297 MM_EXECUTE_READ => Ok(MemoryAccess::RX),
298 MM_READWRITE => Ok(MemoryAccess::RW),
299 MM_WRITECOPY => Ok(MemoryAccess::RW), MM_EXECUTE_READWRITE => Ok(MemoryAccess::RWX),
301 MM_EXECUTE_WRITECOPY => Ok(MemoryAccess::RWX), _ => Ok(MemoryAccess::default()),
303 }
304 }
305
306 fn kind(&self) -> Result<VmiOsRegionKind<'a, Driver, Self::Os>, VmiError> {
308 let offsets = self.offsets();
309 let MMVAD = &offsets._MMVAD;
310 let SUBSECTION = &offsets._SUBSECTION;
311
312 if self.private_memory()? {
322 return Ok(VmiOsRegionKind::Private);
323 }
324
325 let subsection = Va(self.vmi.read_field(self.va, &MMVAD.Subsection)?);
326 let control_area = Va(self.vmi.read_field(subsection, &SUBSECTION.ControlArea)?);
327
328 let region_kind = WindowsControlArea::new(self.vmi, control_area);
329
330 const VadImageMap: u8 = 2;
331 let vad_type = self.vad_type()?;
332 if vad_type == VadImageMap {
333 Ok(VmiOsRegionKind::MappedImage(region_kind))
334 }
335 else {
336 Ok(VmiOsRegionKind::MappedData(region_kind))
337 }
338 }
339}