winreg_core/
cell_reader.rs1use std::io::Cursor;
4
5use winreg_format::cells::{
6 CellHeader, CellOffset, CellSignature, RawBigData, RawKeyNode, RawKeyValue, RawSecurityKey,
7 SubkeyIndex,
8};
9
10use crate::error::{HiveError, Result};
11use crate::hive::Hive;
12
13#[derive(Debug)]
15pub enum Cell {
16 KeyNode(RawKeyNode),
17 KeyValue(RawKeyValue),
18 SecurityKey(RawSecurityKey),
19 Index(SubkeyIndex),
20 BigData(RawBigData),
21 Data(Vec<u8>),
23}
24
25impl Hive<Cursor<Vec<u8>>> {
26 pub fn read_cell_raw(&self, offset: CellOffset) -> Result<(CellHeader, Vec<u8>)> {
28 if offset.is_null() {
29 return Err(HiveError::NullOffset);
30 }
31
32 #[allow(clippy::cast_possible_truncation)]
33 let file_offset = offset.file_offset() as usize;
34 let data = self.reader.get_ref();
35
36 if file_offset + 4 > data.len() {
37 return Err(HiveError::CellOverflow {
38 offset,
39 cell_size: 0,
40 hbin_end: data.len() as u64,
41 });
42 }
43
44 let header_bytes: [u8; 4] = data
45 .get(file_offset..file_offset + 4)
46 .and_then(|s| <[u8; 4]>::try_from(s).ok())
47 .unwrap_or([0; 4]);
48 let header = CellHeader::from_bytes(&header_bytes);
49
50 if !header.is_allocated() {
51 return Err(HiveError::UnallocatedCell { offset });
52 }
53
54 let size = header.size() as usize;
55 let end = file_offset + size;
56 if end > data.len() {
57 return Err(HiveError::CellOverflow {
58 offset,
59 cell_size: header.size(),
60 hbin_end: data.len() as u64,
61 });
62 }
63
64 let body = data[file_offset + 4..end].to_vec();
65 Ok((header, body))
66 }
67
68 pub fn read_cell(&self, offset: CellOffset) -> Result<Cell> {
70 let (_header, body) = self.read_cell_raw(offset)?;
71
72 if body.len() < 2 {
73 return Ok(Cell::Data(body));
74 }
75
76 let sig_bytes: [u8; 2] = [body[0], body[1]];
77 let after_sig = &body[2..];
78
79 match CellSignature::from_bytes(&sig_bytes) {
80 Some(CellSignature::KeyNode) => {
81 let nk = RawKeyNode::parse(after_sig).ok_or(HiveError::InvalidCellSignature {
82 offset,
83 expected: "nk (valid key node)",
84 byte0: sig_bytes[0],
85 byte1: sig_bytes[1],
86 })?;
87 Ok(Cell::KeyNode(nk))
88 }
89 Some(CellSignature::KeyValue) => {
90 let vk = RawKeyValue::parse(after_sig).ok_or(HiveError::InvalidCellSignature {
91 offset,
92 expected: "vk (valid key value)",
93 byte0: sig_bytes[0],
94 byte1: sig_bytes[1],
95 })?;
96 Ok(Cell::KeyValue(vk))
97 }
98 Some(CellSignature::SecurityKey) => {
99 let sk =
100 RawSecurityKey::parse(after_sig).ok_or(HiveError::InvalidCellSignature {
101 offset,
102 expected: "sk (valid security key)",
103 byte0: sig_bytes[0],
104 byte1: sig_bytes[1],
105 })?;
106 Ok(Cell::SecurityKey(sk))
107 }
108 Some(CellSignature::FastLeaf) => {
109 let idx =
110 SubkeyIndex::parse_lf(after_sig).ok_or(HiveError::InvalidCellSignature {
111 offset,
112 expected: "lf (valid fast leaf)",
113 byte0: sig_bytes[0],
114 byte1: sig_bytes[1],
115 })?;
116 Ok(Cell::Index(idx))
117 }
118 Some(CellSignature::HashLeaf) => {
119 let idx =
120 SubkeyIndex::parse_lh(after_sig).ok_or(HiveError::InvalidCellSignature {
121 offset,
122 expected: "lh (valid hash leaf)",
123 byte0: sig_bytes[0],
124 byte1: sig_bytes[1],
125 })?;
126 Ok(Cell::Index(idx))
127 }
128 Some(CellSignature::IndexLeaf) => {
129 let idx =
130 SubkeyIndex::parse_li(after_sig).ok_or(HiveError::InvalidCellSignature {
131 offset,
132 expected: "li (valid index leaf)",
133 byte0: sig_bytes[0],
134 byte1: sig_bytes[1],
135 })?;
136 Ok(Cell::Index(idx))
137 }
138 Some(CellSignature::RootIndex) => {
139 let idx =
140 SubkeyIndex::parse_ri(after_sig).ok_or(HiveError::InvalidCellSignature {
141 offset,
142 expected: "ri (valid root index)",
143 byte0: sig_bytes[0],
144 byte1: sig_bytes[1],
145 })?;
146 Ok(Cell::Index(idx))
147 }
148 Some(CellSignature::BigData) => {
149 let db = RawBigData::parse(after_sig).ok_or(HiveError::InvalidCellSignature {
150 offset,
151 expected: "db (valid big data)",
152 byte0: sig_bytes[0],
153 byte1: sig_bytes[1],
154 })?;
155 Ok(Cell::BigData(db))
156 }
157 None => Ok(Cell::Data(body)),
158 }
159 }
160
161 pub fn read_data_cell(&self, offset: CellOffset) -> Result<Vec<u8>> {
164 let (_header, body) = self.read_cell_raw(offset)?;
165 Ok(body)
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 fn build_minimal_hive() -> Vec<u8> {
174 use winreg_format::header::BaseBlock;
175
176 let hbin_size: u32 = 4096;
177 let total_size = BaseBlock::SIZE + hbin_size as usize;
178 let mut buf = vec![0u8; total_size];
179
180 buf[0..4].copy_from_slice(b"regf");
181 buf[0x04..0x08].copy_from_slice(&1u32.to_le_bytes());
182 buf[0x08..0x0C].copy_from_slice(&1u32.to_le_bytes());
183 buf[0x14..0x18].copy_from_slice(&1u32.to_le_bytes());
184 buf[0x18..0x1C].copy_from_slice(&5u32.to_le_bytes());
185 buf[0x20..0x24].copy_from_slice(&1u32.to_le_bytes());
186 buf[0x24..0x28].copy_from_slice(&32u32.to_le_bytes()); buf[0x28..0x2C].copy_from_slice(&hbin_size.to_le_bytes());
188 buf[0x2C..0x30].copy_from_slice(&1u32.to_le_bytes());
189 let checksum = BaseBlock::compute_checksum(&buf);
190 buf[0x1FC..0x200].copy_from_slice(&checksum.to_le_bytes());
191
192 let hbin_start = BaseBlock::SIZE;
193 buf[hbin_start..hbin_start + 4].copy_from_slice(b"hbin");
194 buf[hbin_start + 4..hbin_start + 8].copy_from_slice(&0u32.to_le_bytes());
195 buf[hbin_start + 8..hbin_start + 12].copy_from_slice(&hbin_size.to_le_bytes());
196
197 let cell_start = hbin_start + 32;
199 let cell_size: i32 = -128;
200 buf[cell_start..cell_start + 4].copy_from_slice(&cell_size.to_le_bytes());
201 buf[cell_start + 4..cell_start + 6].copy_from_slice(b"nk");
202 buf[cell_start + 6..cell_start + 8].copy_from_slice(&0x0024u16.to_le_bytes()); let name_len_offset = cell_start + 4 + 2 + 70; buf[name_len_offset..name_len_offset + 2].copy_from_slice(&4u16.to_le_bytes());
206 let name_offset = name_len_offset + 4; buf[name_offset..name_offset + 4].copy_from_slice(b"root");
209
210 let free_start = cell_start + 128;
212 let free_size = (hbin_size as usize) - 32 - 128;
213 buf[free_start..free_start + 4].copy_from_slice(&(free_size as i32).to_le_bytes());
214
215 buf
216 }
217
218 #[test]
219 fn read_root_nk_cell() {
220 let hive = Hive::from_bytes(build_minimal_hive()).unwrap();
221 let root_offset = hive.root_cell_offset();
222 let cell = hive.read_cell(root_offset).unwrap();
223 match cell {
224 Cell::KeyNode(nk) => {
225 assert!(nk.is_root());
226 }
227 other => panic!("expected KeyNode, got {other:?}"),
228 }
229 }
230
231 #[test]
232 fn null_offset_returns_error() {
233 let hive = Hive::from_bytes(build_minimal_hive()).unwrap();
234 assert!(matches!(
235 hive.read_cell(CellOffset::NULL),
236 Err(HiveError::NullOffset)
237 ));
238 }
239
240 #[test]
241 fn out_of_bounds_offset_returns_error() {
242 let hive = Hive::from_bytes(build_minimal_hive()).unwrap();
243 let bad_offset = CellOffset(0xFFFFFE); assert!(matches!(
245 hive.read_cell(bad_offset),
246 Err(HiveError::CellOverflow { .. })
247 ));
248 }
249}