vmi_os_windows/comps/
handle_table.rs1use once_cell::unsync::OnceCell;
2use vmi_core::{Architecture, Va, VmiDriver, VmiError, VmiState, VmiVa};
3
4use super::{WindowsHandleTableEntry, macros::impl_offsets};
5use crate::{ArchAdapter, HandleTableEntryIterator, WindowsOs};
6
7pub struct WindowsHandleTable<'a, Driver>
16where
17 Driver: VmiDriver,
18 Driver::Architecture: Architecture + ArchAdapter<Driver>,
19{
20 vmi: VmiState<'a, Driver, WindowsOs<Driver>>,
22
23 va: Va,
25
26 table_code: OnceCell<u64>,
28
29 next_handle_needing_pool: OnceCell<u64>,
31}
32
33impl<Driver> VmiVa for WindowsHandleTable<'_, Driver>
34where
35 Driver: VmiDriver,
36 Driver::Architecture: Architecture + ArchAdapter<Driver>,
37{
38 fn va(&self) -> Va {
39 self.va
40 }
41}
42
43impl<'a, Driver> WindowsHandleTable<'a, Driver>
44where
45 Driver: VmiDriver,
46 Driver::Architecture: Architecture + ArchAdapter<Driver>,
47{
48 impl_offsets!();
49
50 pub fn new(vmi: VmiState<'a, Driver, WindowsOs<Driver>>, va: Va) -> Self {
52 Self {
53 vmi,
54 va,
55 table_code: OnceCell::new(),
56 next_handle_needing_pool: OnceCell::new(),
57 }
58 }
59
60 pub fn table_code(&self) -> Result<u64, VmiError> {
70 self.table_code
71 .get_or_try_init(|| {
72 let offsets = self.offsets();
73 let HANDLE_TABLE = &offsets._HANDLE_TABLE;
74
75 self.vmi.read_field(self.va, &HANDLE_TABLE.TableCode)
76 })
77 .copied()
78 }
79
80 pub fn next_handle_needing_pool(&self) -> Result<u64, VmiError> {
93 self.next_handle_needing_pool
94 .get_or_try_init(|| {
95 let offsets = self.offsets();
96 let HANDLE_TABLE = &offsets._HANDLE_TABLE;
97
98 self.vmi
99 .read_field(self.va, &HANDLE_TABLE.NextHandleNeedingPool)
100 })
101 .copied()
102 }
103
104 pub fn iter(&'a self) -> Result<HandleTableEntryIterator<'a, Driver>, VmiError> {
115 Ok(HandleTableEntryIterator::new(self))
116 }
117
118 pub fn lookup(
129 &self,
130 handle: u64,
131 ) -> Result<Option<WindowsHandleTableEntry<'a, Driver>>, VmiError> {
132 const SIZEOF_POINTER: u64 = 8;
133 const SIZEOF_HANDLE_TABLE_ENTRY: u64 = 16;
134
135 const LOWLEVEL_COUNT: u64 = 256; const MIDLEVEL_COUNT: u64 = 512; const LEVEL_CODE_MASK: u64 = 3;
139 const HANDLE_VALUE_INC: u64 = 4;
140
141 let mut index = handle & !0b11;
144
145 if index >= self.next_handle_needing_pool()? {
147 return Ok(None);
148 }
149
150 let table_code = self.table_code()?;
151 let level = table_code & LEVEL_CODE_MASK;
152 let table = Va(table_code - level);
153
154 let entry = match level {
155 0 => table + index * (SIZEOF_HANDLE_TABLE_ENTRY / HANDLE_VALUE_INC),
156
157 1 => {
158 let table2 = table;
159 let i = index % (LOWLEVEL_COUNT * HANDLE_VALUE_INC);
160
161 index -= i;
162 let j = index / (LOWLEVEL_COUNT * HANDLE_VALUE_INC);
163
164 let table1 = self.vmi.read_va_native(table2 + j * SIZEOF_POINTER)?;
165
166 table1 + i * (SIZEOF_HANDLE_TABLE_ENTRY / HANDLE_VALUE_INC)
167 }
168
169 2 => {
170 let table3 = table;
171 let i = index % (LOWLEVEL_COUNT * HANDLE_VALUE_INC);
172
173 index -= i;
174 let mut k = index / (LOWLEVEL_COUNT * HANDLE_VALUE_INC);
175
176 let j = k % MIDLEVEL_COUNT;
177 k -= j;
178 k /= MIDLEVEL_COUNT;
179
180 let table2 = self.vmi.read_va_native(table3 + k * SIZEOF_POINTER)?;
181 let table1 = self.vmi.read_va_native(table2 + j * SIZEOF_POINTER)?;
182
183 table1 + i * (SIZEOF_HANDLE_TABLE_ENTRY / HANDLE_VALUE_INC)
184 }
185
186 _ => unreachable!(),
187 };
188
189 Ok(Some(WindowsHandleTableEntry::new(self.vmi, entry)))
190 }
191}