vmi_os_windows/comps/object/
process.rs1use vmi_arch_amd64::Cr3;
2use vmi_core::{
3 Architecture, Pa, Va, VmiDriver, VmiError, VmiState, VmiVa,
4 os::{ProcessId, ProcessObject, ThreadObject, VmiOsImageArchitecture, VmiOsProcess},
5};
6
7use super::{
8 super::{
9 WindowsHandleTable, WindowsPeb, WindowsRegion, WindowsSession, macros::impl_offsets,
10 peb::WindowsWow64Kind,
11 },
12 WindowsObject, WindowsThread,
13};
14use crate::{
15 ArchAdapter, ListEntryIterator, OffsetsExt, TreeNodeIterator, WindowsOs,
16 offsets::{v1, v2},
17};
18
19pub struct WindowsProcess<'a, Driver>
29where
30 Driver: VmiDriver,
31 Driver::Architecture: Architecture + ArchAdapter<Driver>,
32{
33 vmi: VmiState<'a, Driver, WindowsOs<Driver>>,
35
36 va: Va,
38}
39
40impl<'a, Driver> From<WindowsProcess<'a, Driver>> for WindowsObject<'a, Driver>
41where
42 Driver: VmiDriver,
43 Driver::Architecture: Architecture + ArchAdapter<Driver>,
44{
45 fn from(value: WindowsProcess<'a, Driver>) -> Self {
46 Self::new(value.vmi, value.va)
47 }
48}
49
50impl<Driver> VmiVa for WindowsProcess<'_, Driver>
51where
52 Driver: VmiDriver,
53 Driver::Architecture: Architecture + ArchAdapter<Driver>,
54{
55 fn va(&self) -> Va {
56 self.va
57 }
58}
59
60impl<'a, Driver> WindowsProcess<'a, Driver>
61where
62 Driver: VmiDriver,
63 Driver::Architecture: Architecture + ArchAdapter<Driver>,
64{
65 impl_offsets!();
66
67 pub fn new(vmi: VmiState<'a, Driver, WindowsOs<Driver>>, process: ProcessObject) -> Self {
69 Self { vmi, va: process.0 }
70 }
71
72 pub fn peb(&self) -> Result<Option<WindowsPeb<'a, Driver>>, VmiError> {
81 let offsets = self.offsets();
82 let EPROCESS = &offsets._EPROCESS;
83
84 let root = self.translation_root()?;
85
86 let wow64 = self
87 .vmi
88 .read_va_native(self.va + EPROCESS.WoW64Process.offset())?;
89
90 if wow64.is_null() {
91 let peb64 = self.vmi.read_va_native(self.va + EPROCESS.Peb.offset())?;
92
93 if peb64.is_null() {
94 return Ok(None);
95 }
96
97 Ok(Some(WindowsPeb::new(
98 self.vmi,
99 peb64,
100 root,
101 WindowsWow64Kind::Native,
102 )))
103 }
104 else {
105 let peb32 = match &offsets.ext {
106 Some(OffsetsExt::V1(_)) => wow64,
107 Some(OffsetsExt::V2(v2)) => self
108 .vmi
109 .read_va_native(wow64 + v2._EWOW64PROCESS.Peb.offset())?,
110 None => panic!("OffsetsExt not set"),
111 };
112
113 if peb32.is_null() {
114 return Ok(None);
115 }
116
117 Ok(Some(WindowsPeb::new(
118 self.vmi,
119 peb32,
120 root,
121 WindowsWow64Kind::X86,
122 )))
123 }
124 }
125
126 pub fn session(&self) -> Result<Option<WindowsSession<'a, Driver>>, VmiError> {
128 let offsets = self.offsets();
129 let EPROCESS = &offsets._EPROCESS;
130
131 let session = self
132 .vmi
133 .read_va_native(self.va + EPROCESS.Session.offset())?;
134
135 if session.is_null() {
136 return Ok(None);
137 }
138
139 Ok(Some(WindowsSession::new(self.vmi, session)))
140 }
141
142 pub fn handle_table(&self) -> Result<Option<WindowsHandleTable<'a, Driver>>, VmiError> {
148 let offsets = self.offsets();
149 let EPROCESS = &offsets._EPROCESS;
150
151 let handle_table = self
152 .vmi
153 .read_va_native(self.va + EPROCESS.ObjectTable.offset())?;
154
155 if handle_table.is_null() {
156 return Ok(None);
157 }
158
159 Ok(Some(WindowsHandleTable::new(self.vmi, handle_table)))
160 }
161
162 pub fn vad_root(&self) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
169 let node = match &self.offsets().ext() {
170 Some(OffsetsExt::V1(offsets)) => self.vad_root_v1(offsets)?,
171 Some(OffsetsExt::V2(offsets)) => self.vad_root_v2(offsets)?,
172 None => panic!("OffsetsExt not set"),
173 };
174
175 if node.is_null() {
176 return Ok(None);
177 }
178
179 Ok(Some(WindowsRegion::new(self.vmi, node)))
180 }
181
182 fn vad_root_v1(&self, offsets_ext: &v1::Offsets) -> Result<Va, VmiError> {
183 let offsets = self.offsets();
184 let EPROCESS = &offsets._EPROCESS;
185 let MM_AVL_TABLE = &offsets_ext._MM_AVL_TABLE;
186
187 let vad_root = self.va + EPROCESS.VadRoot.offset() + MM_AVL_TABLE.BalancedRoot.offset();
190
191 Ok(vad_root)
192 }
193
194 fn vad_root_v2(&self, offsets_ext: &v2::Offsets) -> Result<Va, VmiError> {
195 let offsets = self.offsets();
196 let EPROCESS = &offsets._EPROCESS;
197 let RTL_AVL_TREE = &offsets_ext._RTL_AVL_TREE;
198
199 let vad_root = self
202 .vmi
203 .read_va_native(self.va + EPROCESS.VadRoot.offset() + RTL_AVL_TREE.Root.offset())?;
204
205 Ok(vad_root)
206 }
207
208 pub fn vad_hint(&self) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
218 let node = match &self.offsets().ext() {
219 Some(OffsetsExt::V1(offsets)) => self.vad_hint_v1(offsets)?,
220 Some(OffsetsExt::V2(offsets)) => self.vad_hint_v2(offsets)?,
221 None => panic!("OffsetsExt not set"),
222 };
223
224 if node.is_null() {
225 return Ok(None);
226 }
227
228 Ok(Some(WindowsRegion::new(self.vmi, node)))
229 }
230
231 fn vad_hint_v1(&self, offsets_ext: &v1::Offsets) -> Result<Va, VmiError> {
232 let offsets = self.offsets();
233 let EPROCESS = &offsets._EPROCESS;
234 let MM_AVL_TABLE = &offsets_ext._MM_AVL_TABLE;
235
236 self.vmi
237 .read_va_native(self.va + EPROCESS.VadRoot.offset() + MM_AVL_TABLE.NodeHint.offset())
238 }
239
240 fn vad_hint_v2(&self, _offsets_ext: &v2::Offsets) -> Result<Va, VmiError> {
241 let offsets = self.offsets();
242 let EPROCESS = &offsets._EPROCESS;
243
244 let VadHint = EPROCESS
245 .VadHint
246 .expect("VadHint is not present in common offsets");
247
248 self.vmi.read_va_native(self.va + VadHint.offset())
249 }
250}
251
252impl<'a, Driver> VmiOsProcess<'a, Driver> for WindowsProcess<'a, Driver>
253where
254 Driver: VmiDriver,
255 Driver::Architecture: Architecture + ArchAdapter<Driver>,
256{
257 type Os = WindowsOs<Driver>;
258
259 fn id(&self) -> Result<ProcessId, VmiError> {
265 let offsets = self.offsets();
266 let EPROCESS = &offsets._EPROCESS;
267
268 let result = self
269 .vmi
270 .read_u32(self.va + EPROCESS.UniqueProcessId.offset())?;
271
272 Ok(ProcessId(result))
273 }
274
275 fn object(&self) -> Result<ProcessObject, VmiError> {
277 Ok(ProcessObject(self.va))
278 }
279
280 fn name(&self) -> Result<String, VmiError> {
286 let offsets = self.offsets();
287 let EPROCESS = &offsets._EPROCESS;
288
289 self.vmi
290 .read_string(self.va + EPROCESS.ImageFileName.offset())
291 }
292
293 fn parent_id(&self) -> Result<ProcessId, VmiError> {
299 let offsets = self.offsets();
300 let EPROCESS = &offsets._EPROCESS;
301
302 let result = self
303 .vmi
304 .read_u32(self.va + EPROCESS.InheritedFromUniqueProcessId.offset())?;
305
306 Ok(ProcessId(result))
307 }
308
309 fn architecture(&self) -> Result<VmiOsImageArchitecture, VmiError> {
317 let offsets = self.offsets();
318 let EPROCESS = &offsets._EPROCESS;
319
320 let wow64process = self
321 .vmi
322 .read_va_native(self.va + EPROCESS.WoW64Process.offset())?;
323
324 if wow64process.is_null() {
325 Ok(VmiOsImageArchitecture::Amd64)
326 }
327 else {
328 Ok(VmiOsImageArchitecture::X86)
329 }
330 }
331
332 fn translation_root(&self) -> Result<Pa, VmiError> {
338 let offsets = self.offsets();
339 let KPROCESS = &offsets._KPROCESS;
340
341 let root = Cr3(self
348 .vmi
349 .read_va_native(self.va + KPROCESS.DirectoryTableBase.offset())?
350 .0);
351
352 Ok(root.into())
353 }
354
355 fn user_translation_root(&self) -> Result<Pa, VmiError> {
364 let offsets = self.offsets();
365 let KPROCESS = &offsets._KPROCESS;
366 let UserDirectoryTableBase = match &KPROCESS.UserDirectoryTableBase {
367 Some(UserDirectoryTableBase) => UserDirectoryTableBase,
368 None => return self.translation_root(),
369 };
370
371 let root = Cr3(self
372 .vmi
373 .read_va_native(self.va + UserDirectoryTableBase.offset())?
374 .0);
375
376 if root.0 < Driver::Architecture::PAGE_SIZE {
377 return self.translation_root();
378 }
379
380 Ok(root.into())
381 }
382
383 fn image_base(&self) -> Result<Va, VmiError> {
389 let offsets = self.offsets();
390 let EPROCESS = &offsets._EPROCESS;
391
392 self.vmi
393 .read_va_native(self.va + EPROCESS.SectionBaseAddress.offset())
394 }
395
396 fn regions(
402 &self,
403 ) -> Result<impl Iterator<Item = Result<WindowsRegion<'a, Driver>, VmiError>>, VmiError> {
404 let iterator = match self.vad_root()? {
405 Some(vad_root) => TreeNodeIterator::new(self.vmi, vad_root.va()),
406 None => TreeNodeIterator::empty(self.vmi),
407 };
408
409 Ok(iterator.map(move |result| result.map(|vad| WindowsRegion::new(self.vmi, vad))))
410 }
411
412 fn find_region(&self, address: Va) -> Result<Option<WindowsRegion<'a, Driver>>, VmiError> {
426 let vad = match self.vad_hint()? {
427 Some(vad) => vad,
428 None => return Ok(None),
429 };
430
431 let vpn = address.0 >> 12;
432
433 if vpn >= vad.starting_vpn()? && vpn <= vad.ending_vpn()? {
434 return Ok(Some(vad));
435 }
436
437 let mut next = self.vad_root()?;
438 while let Some(vad) = next {
439 if vpn < vad.starting_vpn()? {
440 next = vad.left_child()?;
441 }
442 else if vpn > vad.ending_vpn()? {
443 next = vad.right_child()?;
444 }
445 else {
446 return Ok(Some(vad));
447 }
448 }
449
450 Ok(None)
451 }
452
453 fn threads(
464 &self,
465 ) -> Result<
466 impl Iterator<Item = Result<<Self::Os as vmi_core::VmiOs<Driver>>::Thread<'a>, VmiError>>,
467 VmiError,
468 > {
469 let offsets = self.offsets();
470 let EPROCESS = &offsets._EPROCESS;
471 let ETHREAD = &offsets._ETHREAD;
472
473 Ok(ListEntryIterator::new(
474 self.vmi,
475 self.va + EPROCESS.ThreadListHead.offset(),
476 ETHREAD.ThreadListEntry.offset(),
477 )
478 .map(move |result| result.map(|entry| WindowsThread::new(self.vmi, ThreadObject(entry)))))
479 }
480
481 fn is_valid_address(&self, address: Va) -> Result<Option<bool>, VmiError> {
486 if Driver::Architecture::is_page_present_or_transition(self.vmi, address)? {
508 return Ok(Some(true));
509 }
510
511 let vad = match self.find_region(address)? {
512 Some(vad) => vad,
513 None => return Ok(Some(false)),
514 };
515
516 const MM_ZERO_ACCESS: u8 = 0; const MM_DECOMMIT: u8 = 0x10; const MM_NOACCESS: u8 = 0x18; const VadImageMap: u8 = 2;
521
522 if matches!(
523 vad.vad_protection()?,
524 MM_ZERO_ACCESS | MM_DECOMMIT | MM_NOACCESS
525 ) {
526 return Ok(Some(false));
527 }
528
529 Ok(Some(
530 (vad.private_memory()? && vad.mem_commit()?) ||
532
533 (!vad.private_memory()? && vad.vad_type()? == VadImageMap),
543 ))
544 }
545}