Skip to main content

vmi_os_windows/iter/
directory.rs

1use std::iter::FusedIterator;
2
3use vmi_core::{Registers as _, Va, VmiError, VmiState, driver::VmiRead};
4
5use crate::{ArchAdapter, WindowsObject, WindowsOs};
6
7/// An iterator for traversing objects stored in a Windows
8/// `_OBJECT_DIRECTORY`.
9///
10/// Walks every hash bucket in the directory and, for each bucket, follows
11/// the `_OBJECT_DIRECTORY_ENTRY.ChainLink` chain.
12pub struct DirectoryObjectIterator<'a, Driver>
13where
14    Driver: VmiRead,
15    Driver::Architecture: ArchAdapter<Driver>,
16{
17    /// VMI state.
18    vmi: VmiState<'a, WindowsOs<Driver>>,
19
20    /// Virtual address of the `_OBJECT_DIRECTORY`.
21    directory_va: Va,
22
23    /// Offset of `_OBJECT_DIRECTORY.HashBuckets`.
24    hash_buckets_offset: u64,
25
26    /// Offset of `_OBJECT_DIRECTORY_ENTRY.ChainLink`.
27    chain_link_offset: u64,
28
29    /// Offset of `_OBJECT_DIRECTORY_ENTRY.Object`.
30    object_offset: u64,
31
32    /// Index of the next hash bucket to read.
33    bucket: u64,
34
35    /// Next entry in the current bucket's chain, or `None` if the
36    /// iterator needs to advance to the following bucket.
37    entry: Option<Va>,
38}
39
40impl<'a, Driver> DirectoryObjectIterator<'a, Driver>
41where
42    Driver: VmiRead,
43    Driver::Architecture: ArchAdapter<Driver>,
44{
45    /// Creates a new directory object iterator.
46    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, directory_va: Va) -> Self {
47        let offsets = &vmi.underlying_os().offsets;
48        let OBJECT_DIRECTORY = &offsets._OBJECT_DIRECTORY;
49        let OBJECT_DIRECTORY_ENTRY = &offsets._OBJECT_DIRECTORY_ENTRY;
50
51        let hash_buckets_offset = OBJECT_DIRECTORY.HashBuckets.offset();
52        let chain_link_offset = OBJECT_DIRECTORY_ENTRY.ChainLink.offset();
53        let object_offset = OBJECT_DIRECTORY_ENTRY.Object.offset();
54
55        Self {
56            vmi,
57            directory_va,
58            hash_buckets_offset,
59            chain_link_offset,
60            object_offset,
61            bucket: 0,
62            entry: None,
63        }
64    }
65
66    /// Walks to the next directory entry.
67    fn walk_next(&mut self) -> Result<Option<WindowsObject<'a, Driver>>, VmiError> {
68        const BUCKET_COUNT: u64 = 37;
69
70        let address_width = self.vmi.registers().address_width() as u64;
71
72        loop {
73            let entry = match self.entry.take() {
74                Some(entry) => entry,
75                None => {
76                    if self.bucket >= BUCKET_COUNT {
77                        return Ok(None);
78                    }
79
80                    let hash_bucket = self.vmi.read_va_native(
81                        self.directory_va + self.hash_buckets_offset + self.bucket * address_width,
82                    )?;
83                    self.bucket += 1;
84
85                    if hash_bucket.is_null() {
86                        continue;
87                    }
88
89                    hash_bucket
90                }
91            };
92
93            let object = self.vmi.read_va_native(entry + self.object_offset)?;
94            let next = self.vmi.read_va_native(entry + self.chain_link_offset)?;
95
96            self.entry = if next.is_null() { None } else { Some(next) };
97
98            return Ok(Some(WindowsObject::new(self.vmi, object)));
99        }
100    }
101}
102
103impl<'a, Driver> Iterator for DirectoryObjectIterator<'a, Driver>
104where
105    Driver: VmiRead,
106    Driver::Architecture: ArchAdapter<Driver>,
107{
108    type Item = Result<WindowsObject<'a, Driver>, VmiError>;
109
110    fn next(&mut self) -> Option<Self::Item> {
111        self.walk_next().transpose()
112    }
113}
114
115impl<Driver> FusedIterator for DirectoryObjectIterator<'_, Driver>
116where
117    Driver: VmiRead,
118    Driver::Architecture: ArchAdapter<Driver>,
119{
120}