vmi_os_windows/comps/hive/
key_control_block.rs1use once_cell::unsync::OnceCell;
2use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead};
3
4use super::{WindowsHive, WindowsHiveCellIndex, WindowsKeyNode};
5use crate::{ArchAdapter, WindowsError, WindowsOs, offset};
6
7pub struct WindowsKeyControlBlock<'a, Driver>
17where
18 Driver: VmiRead,
19 Driver::Architecture: ArchAdapter<Driver>,
20{
21 vmi: VmiState<'a, WindowsOs<Driver>>,
23
24 va: Va,
26
27 name_block: OnceCell<Va>,
29}
30
31impl<Driver> VmiVa for WindowsKeyControlBlock<'_, Driver>
32where
33 Driver: VmiRead,
34 Driver::Architecture: ArchAdapter<Driver>,
35{
36 fn va(&self) -> Va {
37 self.va
38 }
39}
40
41impl<'a, Driver> WindowsKeyControlBlock<'a, Driver>
42where
43 Driver: VmiRead,
44 Driver::Architecture: ArchAdapter<Driver>,
45{
46 pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
48 Self {
49 vmi,
50 va,
51 name_block: OnceCell::new(),
52 }
53 }
54
55 pub fn refcount(&self) -> Result<u64, VmiError> {
61 let CM_KEY_CONTROL_BLOCK = offset!(self.vmi, _CM_KEY_CONTROL_BLOCK);
62
63 let refcount = self
64 .vmi
65 .read_field(self.va, &CM_KEY_CONTROL_BLOCK.RefCount)?;
66
67 Ok(refcount)
68 }
69
70 pub fn discarded(&self) -> Result<bool, VmiError> {
80 let CM_KEY_CONTROL_BLOCK = offset!(self.vmi, _CM_KEY_CONTROL_BLOCK);
81
82 let discarded = self
83 .vmi
84 .read_field(self.va, &CM_KEY_CONTROL_BLOCK.Discarded)?;
85
86 Ok(CM_KEY_CONTROL_BLOCK.Discarded.extract(discarded) != 0)
87 }
88
89 pub fn parent(&self) -> Result<Option<WindowsKeyControlBlock<'a, Driver>>, VmiError> {
95 let CM_KEY_CONTROL_BLOCK = offset!(self.vmi, _CM_KEY_CONTROL_BLOCK);
96
97 let parent_kcb = self
98 .vmi
99 .read_va_native(self.va + CM_KEY_CONTROL_BLOCK.ParentKcb.offset())?;
100
101 if parent_kcb.is_null() {
102 return Ok(None);
103 }
104
105 Ok(Some(WindowsKeyControlBlock::new(self.vmi, parent_kcb)))
106 }
107
108 pub fn name(&self) -> Result<String, VmiError> {
117 let CM_NAME_CONTROL_BLOCK = offset!(self.vmi, _CM_NAME_CONTROL_BLOCK);
118
119 let name_block = self.name_block()?;
120
121 let compressed = self
122 .vmi
123 .read_field(name_block, &CM_NAME_CONTROL_BLOCK.Compressed)?;
124
125 let compressed = CM_NAME_CONTROL_BLOCK.Compressed.extract(compressed) != 0;
126
127 let name_length = self
128 .vmi
129 .read_field(name_block, &CM_NAME_CONTROL_BLOCK.NameLength)?;
130
131 if compressed {
132 self.vmi.read_string_limited(
133 name_block + CM_NAME_CONTROL_BLOCK.Name.offset(),
134 name_length as usize,
135 )
136 }
137 else {
138 self.vmi.read_string_utf16_limited(
139 name_block + CM_NAME_CONTROL_BLOCK.Name.offset(),
140 name_length as usize,
141 )
142 }
143 }
144
145 fn name_block(&self) -> Result<Va, VmiError> {
147 self.name_block
148 .get_or_try_init(|| {
149 let CM_KEY_CONTROL_BLOCK = offset!(self.vmi, _CM_KEY_CONTROL_BLOCK);
150
151 let name_block = self
152 .vmi
153 .read_va_native(self.va + CM_KEY_CONTROL_BLOCK.NameBlock.offset())?;
154
155 if name_block.is_null() {
156 return Err(
157 WindowsError::CorruptedStruct("CM_KEY_CONTROL_BLOCK.NameBlock").into(),
158 );
159 }
160
161 Ok(name_block)
162 })
163 .copied()
164 }
165
166 pub fn hive(&self) -> Result<Option<WindowsHive<'a, Driver>>, VmiError> {
172 let CM_KEY_CONTROL_BLOCK = offset!(self.vmi, _CM_KEY_CONTROL_BLOCK);
173
174 let key_hive = self
175 .vmi
176 .read_va_native(self.va + CM_KEY_CONTROL_BLOCK.KeyHive.offset())?;
177
178 if key_hive.is_null() {
179 return Ok(None);
180 }
181
182 Ok(Some(WindowsHive::new(self.vmi, key_hive)))
183 }
184
185 pub fn key_node(&self) -> Result<Option<WindowsKeyNode<'a, Driver>>, VmiError> {
192 let CM_KEY_CONTROL_BLOCK = offset!(self.vmi, _CM_KEY_CONTROL_BLOCK);
193
194 let hive = match self.hive()? {
195 Some(hive) => hive,
196 None => return Ok(None),
197 };
198
199 let key_cell = self
200 .vmi
201 .read_u32(self.va + CM_KEY_CONTROL_BLOCK.KeyCell.offset())?;
202
203 if key_cell == 0 {
204 return Ok(None);
205 }
206
207 Ok(hive
208 .cell(WindowsHiveCellIndex::new(key_cell))?
209 .map(|va| WindowsKeyNode::new(self.vmi, hive.va, va)))
210 }
211}