1use once_cell::unsync::OnceCell;
2use vmi_core::{
3 MemoryAccess, Va, VmiError, VmiState, VmiVa,
4 driver::VmiRead,
5 os::{VmiOsRegion, VmiOsRegionKind},
6};
7
8use super::WindowsControlArea;
9use crate::{ArchAdapter, OffsetsExt, WindowsOs, offset};
10
11pub struct WindowsRegion<'a, Driver>
21where
22 Driver: VmiRead,
23 Driver::Architecture: ArchAdapter<Driver>,
24{
25 vmi: VmiState<'a, WindowsOs<Driver>>,
27
28 va: Va,
30
31 vad_flags: OnceCell<u64>,
33}
34
35impl<Driver> VmiVa for WindowsRegion<'_, Driver>
36where
37 Driver: VmiRead,
38 Driver::Architecture: ArchAdapter<Driver>,
39{
40 fn va(&self) -> Va {
41 self.va
42 }
43}
44
45impl<Driver> std::fmt::Debug for WindowsRegion<'_, Driver>
46where
47 Driver: VmiRead,
48 Driver::Architecture: ArchAdapter<Driver>,
49{
50 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
51 let start = self.start();
52 let end = self.end();
53 let protection = self.protection();
54 f.debug_struct("WindowsRegion")
57 .field("start", &start)
58 .field("end", &end)
59 .field("protection", &protection)
60 .finish()
62 }
63}
64
65impl<'a, Driver> WindowsRegion<'a, Driver>
66where
67 Driver: VmiRead,
68 Driver::Architecture: ArchAdapter<Driver>,
69{
70 pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, vad: Va) -> Self {
72 Self {
73 vmi,
74 va: vad,
75 vad_flags: OnceCell::new(),
76 }
77 }
78
79 pub fn starting_vpn(&self) -> Result<u64, VmiError> {
86 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
87
88 let starting_vpn_low = self.vmi.read_field(self.va, &MMVAD_SHORT.StartingVpn)?;
89 let starting_vpn_high = match &MMVAD_SHORT.StartingVpnHigh {
90 Some(StartingVpnHigh) => self.vmi.read_field(self.va, StartingVpnHigh)?,
91 None => 0,
92 };
93
94 Ok((starting_vpn_high << 32) | starting_vpn_low)
95 }
96
97 pub fn ending_vpn(&self) -> Result<u64, VmiError> {
104 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
105
106 let ending_vpn_low = self.vmi.read_field(self.va, &MMVAD_SHORT.EndingVpn)?;
107 let ending_vpn_high = match &MMVAD_SHORT.EndingVpnHigh {
108 Some(EndingVpnHigh) => self.vmi.read_field(self.va, EndingVpnHigh)?,
109 None => 0,
110 };
111
112 Ok((ending_vpn_high << 32) | ending_vpn_low)
113 }
114
115 pub fn vad_flags(&self) -> Result<u64, VmiError> {
125 self.vad_flags
126 .get_or_try_init(|| {
127 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
128
129 self.vmi.read_field(self.va, &MMVAD_SHORT.VadFlags)
130 })
131 .copied()
132 }
133
134 pub fn vad_type(&self) -> Result<u8, VmiError> {
140 let MMVAD_FLAGS = offset!(self.vmi, _MMVAD_FLAGS);
141
142 let vad_flags = self.vad_flags()?;
143 Ok(MMVAD_FLAGS.VadType.extract(vad_flags) as u8)
144 }
145
146 pub fn vad_protection(&self) -> Result<u8, VmiError> {
152 let MMVAD_FLAGS = offset!(self.vmi, _MMVAD_FLAGS);
153
154 let flags = self.vad_flags()?;
155 let protection = MMVAD_FLAGS.Protection.extract(flags) as u8;
156
157 Ok(protection)
158 }
159
160 pub fn private_memory(&self) -> Result<bool, VmiError> {
166 let MMVAD_FLAGS = offset!(self.vmi, _MMVAD_FLAGS);
167
168 let vad_flags = self.vad_flags()?;
169 Ok(MMVAD_FLAGS.PrivateMemory.extract(vad_flags) != 0)
170 }
171
172 pub fn commit_charge(&self) -> Result<u64, VmiError> {
179 let MMVAD_FLAGS = offset!(self.vmi, _MMVAD_FLAGS);
180 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
181
182 let commit_charge = match MMVAD_FLAGS.CommitCharge {
186 Some(CommitCharge) => {
187 let vad_flags = self.vad_flags()?;
188
189 CommitCharge.extract(vad_flags)
190 }
191 None => match (
192 &self.vmi.underlying_os().offsets.ext(),
193 MMVAD_SHORT.VadFlags1,
194 ) {
195 (Some(OffsetsExt::V2(offsets)), Some(VadFlags1)) => {
196 let MMVAD_FLAGS1 = &offsets._MMVAD_FLAGS1;
197 let vad_flags1 = self.vmi.read_field(self.va, &VadFlags1)?;
198 MMVAD_FLAGS1.CommitCharge.extract(vad_flags1)
199 }
200 _ => {
201 panic!("Failed to read CommitCharge from VAD");
202 }
203 },
204 };
205
206 Ok(commit_charge)
207 }
208
209 pub fn mem_commit(&self) -> Result<bool, VmiError> {
216 let MMVAD_FLAGS = offset!(self.vmi, _MMVAD_FLAGS);
217 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
218
219 let mem_commit = match MMVAD_FLAGS.MemCommit {
223 Some(MemCommit) => {
225 let vad_flags = self.vad_flags()?;
226
227 MemCommit.extract(vad_flags) != 0
228 }
229 None => match (
230 &self.vmi.underlying_os().offsets.ext(),
231 MMVAD_SHORT.VadFlags1,
232 ) {
233 (Some(OffsetsExt::V2(offsets)), Some(VadFlags1)) => {
235 let MMVAD_FLAGS1 = &offsets._MMVAD_FLAGS1;
236 let vad_flags1 = self.vmi.read_field(self.va, &VadFlags1)?;
237 MMVAD_FLAGS1.MemCommit.extract(vad_flags1) != 0
238 }
239 _ => {
240 panic!("Failed to read MemCommit from VAD");
241 }
242 },
243 };
244
245 Ok(mem_commit)
246 }
247
248 pub fn left_child(&self) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
254 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
255
256 let left_child = self.vmi.read_field(self.va, &MMVAD_SHORT.Left)?;
257
258 if left_child == 0 {
259 return Ok(None);
260 }
261
262 Ok(Some(WindowsRegion::new(self.vmi, Va(left_child))))
263 }
264
265 pub fn right_child(&self) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
271 let MMVAD_SHORT = offset!(self.vmi, _MMVAD_SHORT);
272
273 let right_child = self.vmi.read_field(self.va, &MMVAD_SHORT.Right)?;
274
275 if right_child == 0 {
276 return Ok(None);
277 }
278
279 Ok(Some(WindowsRegion::new(self.vmi, Va(right_child))))
280 }
281}
282
283impl<'a, Driver> VmiOsRegion<'a, Driver> for WindowsRegion<'a, Driver>
284where
285 Driver: VmiRead,
286 Driver::Architecture: ArchAdapter<Driver>,
287{
288 type Os = WindowsOs<Driver>;
289
290 fn start(&self) -> Result<Va, VmiError> {
297 Ok(Va(self.starting_vpn()? << 12))
298 }
299
300 fn end(&self) -> Result<Va, VmiError> {
307 Ok(Va((self.ending_vpn()? + 1) << 12))
308 }
309
310 fn protection(&self) -> Result<MemoryAccess, VmiError> {
316 const MM_ZERO_ACCESS: u8 = 0; const MM_READONLY: u8 = 1;
318 const MM_EXECUTE: u8 = 2;
319 const MM_EXECUTE_READ: u8 = 3;
320 const MM_READWRITE: u8 = 4; const MM_WRITECOPY: u8 = 5;
322 const MM_EXECUTE_READWRITE: u8 = 6;
323 const MM_EXECUTE_WRITECOPY: u8 = 7;
324
325 match self.vad_protection()? {
326 MM_ZERO_ACCESS => Ok(MemoryAccess::default()),
327 MM_READONLY => Ok(MemoryAccess::R),
328 MM_EXECUTE => Ok(MemoryAccess::X),
329 MM_EXECUTE_READ => Ok(MemoryAccess::RX),
330 MM_READWRITE => Ok(MemoryAccess::RW),
331 MM_WRITECOPY => Ok(MemoryAccess::RW), MM_EXECUTE_READWRITE => Ok(MemoryAccess::RWX),
333 MM_EXECUTE_WRITECOPY => Ok(MemoryAccess::RWX), _ => Ok(MemoryAccess::default()),
335 }
336 }
337
338 fn kind(&self) -> Result<VmiOsRegionKind<'a, Self::Os>, VmiError> {
340 let MMVAD = offset!(self.vmi, _MMVAD);
341 let SUBSECTION = offset!(self.vmi, _SUBSECTION);
342
343 if self.private_memory()? {
353 return Ok(VmiOsRegionKind::Private);
354 }
355
356 let subsection = Va(self.vmi.read_field(self.va, &MMVAD.Subsection)?);
357 let control_area = Va(self.vmi.read_field(subsection, &SUBSECTION.ControlArea)?);
358
359 let region_kind = WindowsControlArea::new(self.vmi, control_area);
360
361 const VadImageMap: u8 = 2;
362 let vad_type = self.vad_type()?;
363 if vad_type == VadImageMap {
364 Ok(VmiOsRegionKind::MappedImage(region_kind))
365 }
366 else {
367 Ok(VmiOsRegionKind::MappedData(region_kind))
368 }
369 }
370}