Skip to main content

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}