vmi_os_windows/comps/
handle_table.rs1use once_cell::unsync::OnceCell;
2use vmi_core::{Registers as _, Va, VmiError, VmiState, VmiVa, driver::VmiRead};
3
4use super::WindowsHandleTableEntry;
5use crate::{ArchAdapter, HandleTableEntryIterator, OffsetsExt, WindowsOs, offset};
6
7pub struct WindowsHandleTable<'a, Driver>
16where
17 Driver: VmiRead,
18 Driver::Architecture: ArchAdapter<Driver>,
19{
20 vmi: VmiState<'a, 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: VmiRead,
36 Driver::Architecture: ArchAdapter<Driver>,
37{
38 fn va(&self) -> Va {
39 self.va
40 }
41}
42
43impl<'a, Driver> WindowsHandleTable<'a, Driver>
44where
45 Driver: VmiRead,
46 Driver::Architecture: ArchAdapter<Driver>,
47{
48 pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
50 Self {
51 vmi,
52 va,
53 table_code: OnceCell::new(),
54 next_handle_needing_pool: OnceCell::new(),
55 }
56 }
57
58 pub fn table_code(&self) -> Result<u64, VmiError> {
68 self.table_code
69 .get_or_try_init(|| {
70 let HANDLE_TABLE = offset!(self.vmi, _HANDLE_TABLE);
71
72 self.vmi.read_field(self.va, &HANDLE_TABLE.TableCode)
73 })
74 .copied()
75 }
76
77 pub fn next_handle_needing_pool(&self) -> Result<u64, VmiError> {
90 self.next_handle_needing_pool
91 .get_or_try_init(|| {
92 let HANDLE_TABLE = offset!(self.vmi, _HANDLE_TABLE);
93
94 self.vmi
95 .read_field(self.va, &HANDLE_TABLE.NextHandleNeedingPool)
96 })
97 .copied()
98 }
99
100 pub fn iter(
111 &self,
112 ) -> Result<
113 impl Iterator<Item = Result<(u64, WindowsHandleTableEntry<'a, Driver>), VmiError>>
114 + use<'a, Driver>,
115 VmiError,
116 > {
117 Ok(HandleTableEntryIterator::new(
118 self.vmi,
119 self.table_code()?,
120 self.next_handle_needing_pool()?,
121 ))
122 }
123
124 pub fn lookup(
135 &self,
136 handle: u64,
137 ) -> Result<Option<WindowsHandleTableEntry<'a, Driver>>, VmiError> {
138 lookup_handle_entry(
139 self.vmi,
140 self.table_code()?,
141 self.next_handle_needing_pool()?,
142 handle,
143 )
144 }
145}
146
147pub(crate) fn lookup_handle_entry<'a, Driver>(
153 vmi: VmiState<'a, WindowsOs<Driver>>,
154 table_code: u64,
155 next_handle_needing_pool: u64,
156 handle: u64,
157) -> Result<Option<WindowsHandleTableEntry<'a, Driver>>, VmiError>
158where
159 Driver: VmiRead,
160 Driver::Architecture: ArchAdapter<Driver>,
161{
162 const PAGE_SIZE: u64 = 4096;
163 const LEVEL_CODE_MASK: u64 = 3;
164 const HANDLE_VALUE_INC: u64 = 4;
165
166 let sizeof_handle_table_entry = match vmi.underlying_os().offsets.ext() {
167 Some(OffsetsExt::V1(offsets)) => offsets._HANDLE_TABLE_ENTRY.len() as u64,
168 Some(OffsetsExt::V2(offsets)) => offsets._HANDLE_TABLE_ENTRY.len() as u64,
169 None => unimplemented!(),
170 };
171
172 let address_width = vmi.registers().address_width() as u64;
173 let lowlevel_count = PAGE_SIZE / sizeof_handle_table_entry; let midlevel_count = PAGE_SIZE / address_width; let mut index = handle & !0b11;
179
180 if index >= next_handle_needing_pool {
182 return Ok(None);
183 }
184
185 let level = table_code & LEVEL_CODE_MASK;
186 let table = Va(table_code - level);
187
188 let entry = match level {
189 0 => table + index * (sizeof_handle_table_entry / HANDLE_VALUE_INC),
190
191 1 => {
192 let table2 = table;
193 let i = index % (lowlevel_count * HANDLE_VALUE_INC);
194
195 index -= i;
196 let j = index / (lowlevel_count * HANDLE_VALUE_INC);
197
198 let table1 = vmi.read_va_native(table2 + j * address_width)?;
199
200 table1 + i * (sizeof_handle_table_entry / HANDLE_VALUE_INC)
201 }
202
203 2 => {
204 let table3 = table;
205 let i = index % (lowlevel_count * HANDLE_VALUE_INC);
206
207 index -= i;
208 let mut k = index / (lowlevel_count * HANDLE_VALUE_INC);
209
210 let j = k % midlevel_count;
211 k -= j;
212 k /= midlevel_count;
213
214 let table2 = vmi.read_va_native(table3 + k * address_width)?;
215 let table1 = vmi.read_va_native(table2 + j * address_width)?;
216
217 table1 + i * (sizeof_handle_table_entry / HANDLE_VALUE_INC)
218 }
219
220 _ => unreachable!(),
221 };
222
223 Ok(Some(WindowsHandleTableEntry::new(vmi, entry)))
224}