vmi_os_windows/comps/hive/key_index.rs
1use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead};
2
3use crate::{ArchAdapter, WindowsError, WindowsOs, offset};
4
5/// A subkey index cell of a registry key.
6///
7/// The Configuration Manager walks `_CM_KEY_INDEX` cells to enumerate a
8/// `_CM_KEY_NODE`'s children. Four variants share the same shape and are
9/// distinguished by the signature. `il`, `fl`, and `hl` are leaf lists.
10/// `ir` is a root index list whose entries point at leaf lists.
11///
12/// # Implementation Details
13///
14/// Corresponds to `_CM_KEY_INDEX`.
15pub struct WindowsKeyIndex<'a, Driver>
16where
17 Driver: VmiRead,
18 Driver::Architecture: ArchAdapter<Driver>,
19{
20 /// The VMI state.
21 vmi: VmiState<'a, WindowsOs<Driver>>,
22
23 /// Address of the `_CM_KEY_INDEX` structure.
24 va: Va,
25}
26
27impl<Driver> VmiVa for WindowsKeyIndex<'_, Driver>
28where
29 Driver: VmiRead,
30 Driver::Architecture: ArchAdapter<Driver>,
31{
32 fn va(&self) -> Va {
33 self.va
34 }
35}
36
37impl<'a, Driver> WindowsKeyIndex<'a, Driver>
38where
39 Driver: VmiRead,
40 Driver::Architecture: ArchAdapter<Driver>,
41{
42 /// Signature of a plain leaf list (`il`).
43 ///
44 /// Each entry is a single `HCELL_INDEX`.
45 ///
46 /// # Implementation Details
47 ///
48 /// Corresponds to `CM_KEY_INDEX_LEAF`.
49 pub const INDEX_LEAF_SIGNATURE: u16 = 0x696c;
50
51 /// Signature of a fast leaf list (`fl`).
52 ///
53 /// Each entry pairs an `HCELL_INDEX` with a 4-byte name hint.
54 ///
55 /// # Implementation Details
56 ///
57 /// Corresponds to `CM_KEY_FAST_LEAF`.
58 pub const FAST_LEAF_SIGNATURE: u16 = 0x666c;
59
60 /// Signature of a hash leaf list (`hl`).
61 ///
62 /// Each entry pairs an `HCELL_INDEX` with an NT name hash.
63 ///
64 /// # Implementation Details
65 ///
66 /// Corresponds to `CM_KEY_HASH_LEAF`.
67 pub const HASH_LEAF_SIGNATURE: u16 = 0x686c;
68
69 /// Signature of a root index list (`ir`).
70 ///
71 /// Each entry is an `HCELL_INDEX` pointing to a leaf list.
72 ///
73 /// # Implementation Details
74 ///
75 /// Corresponds to `CM_KEY_INDEX_ROOT`.
76 pub const INDEX_ROOT_SIGNATURE: u16 = 0x6972;
77
78 /// Creates a new key index.
79 pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
80 Self { vmi, va }
81 }
82
83 /// Returns the signature of the index.
84 ///
85 /// # Implementation Details
86 ///
87 /// Corresponds to `_CM_KEY_INDEX.Signature`.
88 pub fn signature(&self) -> Result<u16, VmiError> {
89 let CM_KEY_INDEX = offset!(self.vmi, _CM_KEY_INDEX);
90
91 self.vmi.read_u16(self.va + CM_KEY_INDEX.Signature.offset())
92 }
93
94 /// Returns the number of entries in the list.
95 ///
96 /// # Implementation Details
97 ///
98 /// Corresponds to `_CM_KEY_INDEX.Count`.
99 pub fn count(&self) -> Result<u16, VmiError> {
100 let CM_KEY_INDEX = offset!(self.vmi, _CM_KEY_INDEX);
101
102 self.vmi.read_u16(self.va + CM_KEY_INDEX.Count.offset())
103 }
104
105 /// Returns the address of the first entry in the index.
106 ///
107 /// # Implementation Details
108 ///
109 /// Corresponds to `_CM_KEY_INDEX.List`.
110 pub fn list(&self) -> Result<Va, VmiError> {
111 let CM_KEY_INDEX = offset!(self.vmi, _CM_KEY_INDEX);
112
113 Ok(self.va + CM_KEY_INDEX.List.offset())
114 }
115
116 /// Returns the byte size of one entry.
117 ///
118 /// 4 bytes for `il` and `ir`. 8 bytes for `fl` and `hl`, which pair
119 /// each `HCELL_INDEX` with a 4-byte name hint or hash.
120 ///
121 /// Reads the signature. Prefer [`entry_size_for`] when the signature is
122 /// already in scope.
123 ///
124 /// [`entry_size_for`]: Self::entry_size_for
125 pub fn entry_size(&self) -> Result<u64, VmiError> {
126 Self::entry_size_for(self.signature()?)
127 }
128
129 /// Returns the byte size of one entry for a given index signature.
130 ///
131 /// Variant of [`entry_size`] that takes the signature directly, avoiding
132 /// the read.
133 ///
134 /// [`entry_size`]: Self::entry_size
135 pub fn entry_size_for(signature: u16) -> Result<u64, VmiError> {
136 match signature {
137 // `_CM_KEY_INDEX.List` is `HCELL_INDEX[]`, sizeof(HCELL_INDEX) == 4.
138 Self::INDEX_LEAF_SIGNATURE | Self::INDEX_ROOT_SIGNATURE => Ok(4),
139 // `_CM_KEY_FAST_INDEX.List` is `CM_INDEX[]`, sizeof(CM_INDEX) == 8.
140 Self::FAST_LEAF_SIGNATURE | Self::HASH_LEAF_SIGNATURE => Ok(8),
141 _ => Err(WindowsError::CorruptedStruct("CM_KEY_INDEX.Signature").into()),
142 }
143 }
144}