Skip to main content

frnsc_hive/
cell.rs

1use forensic_rs::{err::ForensicError, prelude::ForensicResult};
2pub const INDEX_LEAF_SIGNATURE: &[u8; 2] = b"li";
3pub const FAST_LEAF_SIGNATURE: &[u8; 2] = b"lf";
4pub const HASH_LEAF_SIGNATURE: &[u8; 2] = b"lh";
5pub const INDEX_ROOT_SIGNATURE: &[u8; 2] = b"ri";
6pub const KEY_NODE_SIGNATURE: &[u8; 2] = b"nk";
7pub const KEY_SECURITY_SIGNATURE: &[u8; 2] = b"sk";
8pub const KEY_VALUE_SIGNATURE: &[u8; 2] = b"vk";
9
10/// Is volatile (not used, a key node on a disk isn't expected to have this flag set)
11pub const KEY_VOLATILE_FLAG: u16 = 0x0001;
12/// Is the mount point of another hive (a key node on a disk isn't expected to have this flag set)
13pub const KEY_HIVE_EXIT_FLAG: u16 = 0x0002;
14/// Is the root key for this hive
15pub const KEY_HIVE_ENTRY_FLAG: u16 = 0x0004;
16/// This key can't be deleted
17pub const KEY_NO_DELETE_FLAG: u16 = 0x0008;
18/// This key is a symlink (a target key is specified as a UTF-16LE string (REG_LINK) in a value named "SymbolicLinkValue", example: \REGISTRY\MACHINE\SOFTWARE\Classes\Wow6432Node)
19pub const KEY_SYM_LINK_FLAG: u16 = 0x0010;
20/// Key name is an ASCII string, possibly an extended ASCII string (otherwise it is a UTF-16LE string)
21pub const KEY_COMP_NAME_FLAG: u16 = 0x0020;
22/// Is a predefined handle (a handle is stored in the Number of key values field)
23pub const KEY_PREDEF_HANDLE_FLAG: u16 = 0x0040;
24
25/// Value name is an ASCII string, possibly an extended ASCII string (otherwise it is a UTF-16LE string)
26pub const VALUE_COMP_NAME_FLAG: u16 = 0x0001;
27/// Is a tombstone value (the flag is used starting from Insider Preview builds of Windows 10 "Redstone 1"), a tombstone value also has the Data type field set to REG_NONE, the Data size field set to 0, and the Data offset field set to 0xFFFFFFFF
28pub const VALUE_IS_TOMBSTONE: u16 = 0x0002;
29
30#[derive(Debug, Clone)]
31pub enum HiveCell {
32    IndexLeaf(IndexLeafCell),
33    FastLeaf(FastLeafCell),
34    HashLeaf(HashLeafCell),
35    IndexRoot(IndexRootCell),
36    KeyNode(KeyNodeCell),
37    KeyValue(KeyValueCell),
38    KeySecurity(KeySecurityCell),
39    BigData(BigDataCell),
40    Unallocated(UnallocatedCell),
41    Invalid(InvalidCell),
42}
43impl HiveCell {
44    pub fn offset(&self) -> u64 {
45        match self {
46            HiveCell::IndexLeaf(v) => v.offset,
47            HiveCell::FastLeaf(v) => v.offset,
48            HiveCell::HashLeaf(v) => v.offset,
49            HiveCell::IndexRoot(v) => v.offset,
50            HiveCell::KeyNode(v) => v.offset,
51            HiveCell::KeyValue(v) => v.offset,
52            HiveCell::KeySecurity(v) => v.offset,
53            HiveCell::BigData(v) => v.offset,
54            HiveCell::Unallocated(v) => v.offset,
55            HiveCell::Invalid(v) => v.offset,
56        }
57    }
58}
59#[derive(Debug, Clone)]
60pub struct UnallocatedCell {
61    pub offset: u64
62}
63
64#[derive(Debug, Clone)]
65pub struct InvalidCell {
66    pub offset: u64,
67    pub content: Vec<u8>,
68}
69
70#[derive(Debug, Clone)]
71pub struct IndexLeafCell {
72    /// List of offsets of the key node elements in bytes relative from the start of the hive bins data
73    pub elements: Vec<IndexLeafListElements>,
74    pub offset: u64,
75}
76#[derive(Debug, Clone)]
77pub struct IndexLeafListElements {
78    /// Key node element offset in bytes relative from the start of the hive bins data
79    pub offset: u32,
80}
81#[derive(Debug, Clone)]
82pub struct FastLeafCell {
83    pub elements: Vec<FastLeafListElements>,
84    pub offset: u64,
85}
86#[derive(Debug, Clone)]
87pub struct FastLeafListElements {
88    /// Key node offset: In bytes, relative from the start of the hive bins data
89    pub offset: u32,
90    /// The first 4 ASCII characters of a key name string (used to speed up lookups)
91    pub name_hint: String,
92}
93#[derive(Debug, Clone)]
94pub struct HashLeafCell {
95    pub elements: Vec<HashLeafListElements>,
96    pub offset: u64,
97}
98#[derive(Debug, Clone)]
99pub struct HashLeafListElements {
100    /// Key node offset: In bytes, relative from the start of the hive bins data
101    pub offset: u32,
102    /// Hash of a key name string, see below (used to speed up lookups)
103    pub name_hash: u32,
104}
105
106impl HashLeafCell {
107    pub fn hash_name(name: &str) -> u32 {
108        let mut h: u32 = 0;
109        if name.is_ascii() {
110            for &char in name.as_bytes() {
111                let char = Self::uppercase(char);
112                h = 37u32.wrapping_mul(h).wrapping_add(char);
113            }
114        } else {
115            for char in name.to_ascii_uppercase().encode_utf16() {
116                h = 37u32.wrapping_mul(h).wrapping_add(char as u32);
117            }
118        }
119        h
120    }
121
122    pub fn uppercase(v: u8) -> u32 {
123        if (b'a'..b'z').contains(&v) {
124            (b'A' + (v - b'a')) as u32
125        } else {
126            v as u32
127        }
128    }
129}
130
131/// An Index root can't point to another Index root.
132/// A subkeys list can't point to an Index root.
133/// List elements within subkeys lists referenced by a single Index root must be sorted as a whole.
134#[derive(Debug, Clone)]
135pub struct IndexRootCell {
136    pub elements: Vec<IndexRootSubkeyOffset>,
137    pub offset: u64,
138}
139#[derive(Debug, Clone)]
140pub struct IndexRootSubkeyOffset {
141    /// Subkeys list offset: In bytes, relative from the start of the hive bins data
142    pub subkeys_list_offset: u32,
143}
144
145#[derive(Debug, Clone)]
146pub struct KeyNodeCell {
147    /// Flags. Bit mask, see below
148    pub flags: u16,
149    /// Last written timestamp. FILETIME (UTC)
150    pub last_written_timestamp: u64,
151    /// Access bits. Bit mask, see below (this field is used as of Windows 8 and Windows Server 2012; in previous versions of Windows, this field is reserved and called Spare)
152    pub access_bits: u32,
153    /// Parent. Offset of a parent key node in bytes, relative from the start of the hive bins data (this field has no meaning on a disk for a root key node)
154    pub parent: u32,
155    /// Number of subkeys
156    pub number_subkeys: u32,
157    /// Number of volatile subkeys
158    pub number_volatile_subkeys: u32,
159    /// Subkeys list offset. In bytes, relative from the start of the hive bins data (also, this field may point to an Index root)
160    pub subkeys_list_offset: u32,
161    /// Volatile subkeys list offset. This field has no meaning on a disk (volatile keys are not written to a file)
162    pub volatile_subkeys_list_offset: u32,
163    /// Number of key values
164    pub number_key_values: u32,
165    /// Key values list offset. In bytes, relative from the start of the hive bins data
166    pub key_values_list_offset: u32,
167    /// Key security offset. In bytes, relative from the start of the hive bins data
168    pub key_security_offset: u32,
169    /// Class name offset. n bytes, relative from the start of the hive bins data
170    pub class_name_offset: u32,
171    /// Largest subkey class name length. In bytes
172    pub largest_subkey_class_name_length: u32,
173    /// Largest subkey name length. In bytes, a subkey name is treated as a UTF-16LE string.
174    /// Starting from Windows Vista, Windows Server 2003 SP2, and Windows XP SP3, the Largest subkey name length field has been split into 4 bit fields
175    pub largest_subkey_name_length: u16,
176    /// Virtualization control flags and User flags (Wow64 flags)
177    pub virt_and_user_flags: u8,
178    /// Enabling Breakpoints for Registry Keys using the CmpRegDebugBreakEnabled kernel variable
179    pub debug: u8,
180    /// Largest value name length. In bytes, a value name is treated as a UTF-16LE string
181    pub largest_value_name_length: u32,
182    /// Largest value data size. In bytes
183    pub largest_value_data_size: u32,
184    /// WorkVar. Cached index
185    pub work_var: u32,
186    /// Key name length. In bytes
187    pub key_name_length: u16,
188    /// Class name length. In bytes
189    pub class_name_length: u16,
190    /// ASCII (extended) string or UTF-16LE string
191    pub key_name: String,
192    pub offset: u64,
193}
194
195#[repr(C, packed)]
196pub struct KeyNodeCellPacked {
197    /// Signature "nk". ASCII string
198    pub signature: u16,
199    /// Flags. Bit mask, see below
200    pub flags: u16,
201    /// Last written timestamp. FILETIME (UTC)
202    pub last_written_timestamp: u64,
203    /// Access bits. Bit mask, see below (this field is used as of Windows 8 and Windows Server 2012; in previous versions of Windows, this field is reserved and called Spare)
204    pub access_bits: u32,
205    /// Parent. Offset of a parent key node in bytes, relative from the start of the hive bins data (this field has no meaning on a disk for a root key node)
206    pub parent: u32,
207    /// Number of subkeys
208    pub number_subkeys: u32,
209    /// Number of volatile subkeys
210    pub number_volatile_subkeys: u32,
211    /// Subkeys list offset. In bytes, relative from the start of the hive bins data (also, this field may point to an Index root)
212    pub subkeys_list_offset: u32,
213    /// Volatile subkeys list offset. This field has no meaning on a disk (volatile keys are not written to a file)
214    pub volatile_subkeys_list_offset: u32,
215    /// Number of key values
216    pub number_key_values: u32,
217    /// Key values list offset. In bytes, relative from the start of the hive bins data
218    pub key_values_list_offset: u32,
219    /// Key security offset. In bytes, relative from the start of the hive bins data
220    pub key_security_offset: u32,
221    /// Class name offset. n bytes, relative from the start of the hive bins data
222    pub class_name_offset: u32,
223    /// Largest subkey class name length. In bytes
224    pub largest_subkey_class_name_length: u32,
225    /// Largest subkey name length. In bytes, a subkey name is treated as a UTF-16LE string.
226    /// Starting from Windows Vista, Windows Server 2003 SP2, and Windows XP SP3, the Largest subkey name length field has been split into 4 bit fields
227    pub largest_subkey_name_length: u16,
228    /// Virtualization control flags and User flags (Wow64 flags)
229    pub virt_and_user_flags: u8,
230    /// Enabling Breakpoints for Registry Keys using the CmpRegDebugBreakEnabled kernel variable
231    pub debug: u8,
232    /// Largest value name length. In bytes, a value name is treated as a UTF-16LE string
233    pub largest_value_name_length: u32,
234    /// Largest value data size. In bytes
235    pub largest_value_data_size: u32,
236    /// WorkVar. Cached index
237    pub work_var: u32,
238    /// Key name length. In bytes
239    pub key_name_length: u16,
240    /// Class name length. In bytes
241    pub class_name_length: u16,
242}
243#[derive(Debug, Clone)]
244pub struct KeyValueCell {
245    pub name_length: u16,
246    pub data_size: u32,
247    pub data_offset: u32,
248    pub data_type: u32,
249    pub flags: u16,
250    pub value_name: String,
251    pub offset: u64,
252}
253#[repr(C, packed)]
254pub struct KeyValueCellPacked {
255    pub signature: u16,
256    pub name_length: u16,
257    pub data_size: u32,
258    pub data_offset: u32,
259    pub data_type: u32,
260    pub flags: u16,
261    pub spare: u16,
262}
263#[derive(Debug, Clone)]
264pub struct KeySecurityCell {
265    pub flink: u32,
266    pub blink: u32,
267    pub ref_count: u32,
268    pub sec_desc_size: u32,
269    pub sec_desc: Vec<u8>,
270    pub offset: u64,
271}
272#[repr(C, packed)]
273pub struct KeySecurityCellPacked {
274    pub signature: u16,
275    pub reserved: u16,
276    pub flink: u32,
277    pub blink: u32,
278    pub ref_count: u32,
279    pub sec_desc_size: u32,
280}
281#[derive(Debug, Clone)]
282pub struct BigDataCell {
283    pub offset: u64,
284}
285
286pub fn peek_cell(data : &[u8]) -> usize {
287    if data.len() < 4 {
288        return 0
289    }
290    let cell_len_i = i32::from_ne_bytes(data[..4].try_into().unwrap_or_default());
291    let cell_len = cell_len_i.unsigned_abs() as usize;
292    cell_len
293}
294
295pub fn read_cell(data: &[u8], offset: u64) -> ForensicResult<HiveCell> {
296    if data.len() < 6 {
297        return Err(ForensicError::bad_format_str("Invalid Cell: too small"))
298    }
299    let cell_len_i = i32::from_ne_bytes(data[..4].try_into().unwrap_or_default());
300    let cell_len = cell_len_i.unsigned_abs() as usize;
301    if cell_len_i >= 0 {
302        return Ok(HiveCell::Unallocated(UnallocatedCell { offset }));
303    }
304    let signature = &data[4..6];
305    if cell_len > data.len() {
306        return Err(ForensicError::bad_format_str("Not enough buffer size"))
307    }
308    let data = &data[4..cell_len];
309    let cell = if signature == INDEX_LEAF_SIGNATURE {
310        let cell = read_index_leaf_cell(data, offset)?;
311        HiveCell::IndexLeaf(cell)
312    } else if signature == FAST_LEAF_SIGNATURE {
313        let cell = read_fast_leaf_cell(data, offset)?;
314        HiveCell::FastLeaf(cell)
315    } else if signature == HASH_LEAF_SIGNATURE {
316        let cell = read_hash_leaf_cell(data, offset)?;
317        HiveCell::HashLeaf(cell)
318    } else if signature == INDEX_ROOT_SIGNATURE {
319        let cell = read_index_root_cell(data, offset)?;
320        HiveCell::IndexRoot(cell)
321    } else if signature == KEY_NODE_SIGNATURE {
322        let cell = read_key_node_cell(data, offset)?;
323        HiveCell::KeyNode(cell)
324    } else if signature == KEY_SECURITY_SIGNATURE {
325        let cell = read_key_security_cell(data, offset)?;
326        HiveCell::KeySecurity(cell)
327    } else if signature == KEY_VALUE_SIGNATURE {
328        let cell = read_key_value_cell(data, offset)?;
329        HiveCell::KeyValue(cell)
330    } else {
331        HiveCell::Invalid(InvalidCell {
332            offset,
333            content: data[..].to_vec(),
334        })
335    };
336    Ok(cell)
337}
338
339pub fn read_index_leaf_cell(data: &[u8], offset: u64) -> ForensicResult<IndexLeafCell> {
340    if data.len() < 4 {
341        return Err(ForensicError::bad_format_str("Invalid IndexLeafCell: too small"))
342    }
343    let signature = &data[0..2];
344    if signature != INDEX_LEAF_SIGNATURE {
345        return Err(ForensicError::bad_format_str("Invalid IndexLeafCell: invalid signature"));
346    }
347    let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
348    let total_size_elements = (n_elements as usize) * 4 + 4;
349    if total_size_elements > data.len() {
350        return Err(ForensicError::bad_format_str("Invalid IndexLeafCell: size larger than buffer"));
351    }
352    let mut offset_list = Vec::with_capacity(n_elements.into());
353    for i in (4..(4 + 4 * n_elements as usize)).step_by(4) {
354        let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
355        offset_list.push(IndexLeafListElements { offset });
356    }
357    Ok(IndexLeafCell {
358        elements: offset_list,
359        offset,
360    })
361}
362
363pub fn read_fast_leaf_cell(data: &[u8], offset: u64) -> ForensicResult<FastLeafCell> {
364    if data.len() < 4 {
365        return Err(ForensicError::bad_format_str("Invalid FastLeafCell: too small"))
366    }
367    let signature = &data[0..2];
368    if signature != FAST_LEAF_SIGNATURE {
369        return Err(ForensicError::bad_format_str("Invalid FastLeafCell: invalid signature"));
370    }
371    let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
372    let total_size_elements = (n_elements as usize) * 8 + 4;
373    if total_size_elements > data.len() {
374        return Err(ForensicError::bad_format_str("Invalid FastLeafCell: size larger than buffer"));
375    }
376    let mut offset_list = Vec::with_capacity(n_elements.into());
377    for i in (4..(4 + 8 * n_elements as usize)).step_by(8) {
378        let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
379        let data_end = match data[i + 4..i + 8].iter().position(|&v| v == 0) {
380            Some(v) => i + 4 + v,
381            None => i + 8,
382        };
383        let txt = String::from_utf8_lossy(&data[i + 4..data_end]).to_string();
384        offset_list.push(FastLeafListElements {
385            offset,
386            name_hint: txt,
387        });
388    }
389    Ok(FastLeafCell {
390        elements: offset_list,
391        offset,
392    })
393}
394
395pub fn read_hash_leaf_cell(data: &[u8], offset: u64) -> ForensicResult<HashLeafCell> {
396    if data.len() < 4 {
397        return Err(ForensicError::bad_format_str("Invalid HashLeafCell: too small"))
398    }
399    let signature = &data[0..2];
400    if signature != HASH_LEAF_SIGNATURE {
401        return Err(ForensicError::bad_format_str("Invalid HashLeafCell: invalid signature"));
402    }
403    let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
404    let total_size_elements = (n_elements as usize) * 8 + 4;
405    if total_size_elements > data.len() {
406        return Err(ForensicError::bad_format_str("Invalid HashLeafCell: size larger than buffer"));
407    }
408    let mut offset_list = Vec::with_capacity(n_elements.into());
409    for i in (4..total_size_elements).step_by(8) {
410        let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
411        let name_hash = u32::from_ne_bytes(data[i + 4..i + 8].try_into().unwrap_or_default());
412        offset_list.push(HashLeafListElements { offset, name_hash });
413    }
414    Ok(HashLeafCell {
415        elements: offset_list,
416        offset,
417    })
418}
419
420pub fn read_index_root_cell(data: &[u8], offset: u64) -> ForensicResult<IndexRootCell> {
421    if data.len() < 4 {
422        return Err(ForensicError::bad_format_str("Invalid IndexRootCell: too small"))
423    }
424    let signature = &data[0..2];
425    if signature != INDEX_ROOT_SIGNATURE {
426        return Err(ForensicError::bad_format_str("Invalid IndexRootCell: invalid signature"));
427    }
428    let n_elements = u16::from_ne_bytes(data[2..4].try_into().unwrap_or_default());
429    let total_size_elements = (n_elements as usize) * 4 + 4;
430    if total_size_elements > data.len() {
431        return Err(ForensicError::bad_format_str("Invalid IndexRootCell: size larger than buffer"));
432    }
433    let mut offset_list = Vec::with_capacity(n_elements.into());
434    for i in (4..(4 + 4 * n_elements as usize)).step_by(4) {
435        let offset = u32::from_ne_bytes(data[i..i + 4].try_into().unwrap_or_default());
436        offset_list.push(IndexRootSubkeyOffset {
437            subkeys_list_offset: offset,
438        });
439    }
440    Ok(IndexRootCell {
441        elements: offset_list,
442        offset,
443    })
444}
445
446pub fn read_key_node_cell(data: &[u8], offset: u64) -> ForensicResult<KeyNodeCell> {
447    if data.len() < 76 {
448        return Err(ForensicError::bad_format_str("Invalid KeyNode: too small"))
449    }
450    let signature = &data[0..2];
451    if signature != KEY_NODE_SIGNATURE {
452        return Err(ForensicError::bad_format_str("Invalid KeyNode: invalid signature"));
453    }
454    let (head, body, tail) = unsafe { data[0..76].align_to::<KeyNodeCellPacked>() };
455    if !head.is_empty() && !tail.is_empty() {
456        return Err(ForensicError::bad_format_str("Invalid KeyNode: structure not aligned"));
457    }
458    let packed_cell = &body[0];
459    let mut cell: KeyNodeCell = packed_cell.into();
460    cell.offset = offset;
461    if 76 + cell.key_name_length as usize > data.len() {
462        return Err(ForensicError::bad_format_str("Invalid KeyNodeCell: size larger than buffer"));
463    }
464    cell.key_name = if cell.flags & KEY_COMP_NAME_FLAG == 0 {
465        let mut arr = Vec::with_capacity(cell.key_name_length as usize);
466        for i in (76..76 + (cell.key_name_length as usize)).step_by(2) {
467            arr.push(u16::from_ne_bytes([data[i], data[i + 1]]));
468        }
469        String::from_utf16_lossy(&arr).to_string()
470    } else {
471        String::from_utf8_lossy(&data[76..76 + (cell.key_name_length as usize)]).to_string()
472    };
473    Ok(cell)
474}
475
476pub fn read_key_security_cell(data: &[u8], offset: u64) -> ForensicResult<KeySecurityCell> {
477    if data.len() < 76 {
478        return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: too small"))
479    }
480    let signature = &data[0..2];
481    if signature != KEY_SECURITY_SIGNATURE {
482        return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: invalid signature"));
483    }
484    let (head, body, tail) = unsafe { data[0..76].align_to::<KeySecurityCellPacked>() };
485    if !head.is_empty() || !tail.is_empty() {
486        return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: structure not aligned"));
487    }
488    let packed_cell = &body[0];
489    let mut cell: KeySecurityCell = packed_cell.into();
490    cell.offset = offset;
491    let sec_end_pos = 20 + cell.sec_desc_size as usize;
492    if sec_end_pos > data.len() {
493        return Err(ForensicError::bad_format_str("Invalid KeySecurityCell: size larger than buffer"));
494    }
495    for i in 20..sec_end_pos {
496        cell.sec_desc.push(data[i]);
497    }
498    Ok(cell)
499}
500
501pub fn read_key_value_cell(data: &[u8], offset: u64) -> ForensicResult<KeyValueCell> {
502    if data.len() < 20 {
503        return Err(ForensicError::bad_format_str("Invalid KeyValueCell: too small"))
504    }
505    let signature = &data[0..2];
506    if signature != KEY_VALUE_SIGNATURE {
507        return Err(ForensicError::bad_format_str("Invalid KeyValueCell: invalid signature"));
508    }
509    let (head, body, tail) = unsafe { data[0..20].align_to::<KeyValueCellPacked>() };
510    if !head.is_empty() || !tail.is_empty() {
511        return Err(ForensicError::bad_format_str("Invalid KeyValueCell: structure not aligned"));
512    }
513    let packed_cell = &body[0];
514    let mut cell: KeyValueCell = packed_cell.into();
515    cell.offset = offset;
516    let value_name_end = 20 + cell.name_length as usize;
517    if value_name_end > data.len() {
518        return Err(ForensicError::bad_format_str("Invalid KeyValueCell: size larger than buffer"));
519    }
520    if cell.name_length != 0 {
521        cell.value_name = if cell.flags & VALUE_COMP_NAME_FLAG == 0 {
522            let mut arr = Vec::with_capacity(cell.name_length as usize);
523            for i in (20..20 + (cell.name_length as usize)).step_by(2) {
524                arr.push(u16::from_ne_bytes([data[i], data[i + 1]]));
525            }
526            String::from_utf16_lossy(&arr).to_string()
527        } else {
528            String::from_utf8_lossy(&data[20..20 + (cell.name_length as usize)]).to_string()
529        };
530    }
531    Ok(cell)
532}
533
534impl From<KeyNodeCellPacked> for KeyNodeCell {
535    fn from(v: KeyNodeCellPacked) -> Self {
536        KeyNodeCell {
537            flags: v.flags,
538            last_written_timestamp: v.last_written_timestamp,
539            access_bits: v.access_bits,
540            parent: v.parent,
541            number_subkeys: v.number_subkeys,
542            number_volatile_subkeys: v.number_volatile_subkeys,
543            subkeys_list_offset: v.subkeys_list_offset,
544            volatile_subkeys_list_offset: v.volatile_subkeys_list_offset,
545            number_key_values: v.number_key_values,
546            key_values_list_offset: v.key_values_list_offset,
547            key_security_offset: v.key_security_offset,
548            class_name_offset: v.class_name_offset,
549            largest_subkey_class_name_length: v.largest_subkey_class_name_length,
550            largest_subkey_name_length: v.largest_subkey_name_length,
551            debug: v.debug,
552            virt_and_user_flags: v.virt_and_user_flags,
553            largest_value_name_length: v.largest_value_name_length,
554            largest_value_data_size: v.largest_value_data_size,
555            work_var: v.work_var,
556            key_name_length: v.key_name_length,
557            class_name_length: v.class_name_length,
558            key_name: String::new(),
559            offset: 0,
560        }
561    }
562}
563impl From<&KeyNodeCellPacked> for KeyNodeCell {
564    fn from(v: &KeyNodeCellPacked) -> Self {
565        KeyNodeCell {
566            flags: v.flags,
567            last_written_timestamp: v.last_written_timestamp,
568            access_bits: v.access_bits,
569            parent: v.parent,
570            number_subkeys: v.number_subkeys,
571            number_volatile_subkeys: v.number_volatile_subkeys,
572            subkeys_list_offset: v.subkeys_list_offset,
573            volatile_subkeys_list_offset: v.volatile_subkeys_list_offset,
574            number_key_values: v.number_key_values,
575            key_values_list_offset: v.key_values_list_offset,
576            key_security_offset: v.key_security_offset,
577            class_name_offset: v.class_name_offset,
578            largest_subkey_class_name_length: v.largest_subkey_class_name_length,
579            largest_subkey_name_length: v.largest_subkey_name_length,
580            debug: v.debug,
581            virt_and_user_flags: v.virt_and_user_flags,
582            largest_value_name_length: v.largest_value_name_length,
583            largest_value_data_size: v.largest_value_data_size,
584            work_var: v.work_var,
585            key_name_length: v.key_name_length,
586            class_name_length: v.class_name_length,
587            key_name: String::new(),
588            offset: 0,
589        }
590    }
591}
592
593impl From<KeySecurityCellPacked> for KeySecurityCell {
594    fn from(v: KeySecurityCellPacked) -> Self {
595        KeySecurityCell {
596            blink: v.blink,
597            flink: v.flink,
598            ref_count: v.ref_count,
599            sec_desc: Vec::with_capacity(v.sec_desc_size as usize),
600            sec_desc_size: v.sec_desc_size,
601            offset: 0,
602        }
603    }
604}
605impl From<&KeySecurityCellPacked> for KeySecurityCell {
606    fn from(v: &KeySecurityCellPacked) -> Self {
607        KeySecurityCell {
608            blink: v.blink,
609            flink: v.flink,
610            ref_count: v.ref_count,
611            sec_desc: Vec::with_capacity(v.sec_desc_size as usize),
612            sec_desc_size: v.sec_desc_size,
613            offset: 0,
614        }
615    }
616}
617impl From<KeyValueCellPacked> for KeyValueCell {
618    fn from(v: KeyValueCellPacked) -> Self {
619        Self {
620            name_length: v.name_length,
621            data_size: v.data_size,
622            data_offset: v.data_offset,
623            data_type: v.data_type,
624            flags: v.flags,
625            value_name: String::new(),
626            offset: 0,
627        }
628    }
629}
630impl From<&KeyValueCellPacked> for KeyValueCell {
631    fn from(v: &KeyValueCellPacked) -> Self {
632        Self {
633            name_length: v.name_length,
634            data_size: v.data_size,
635            data_offset: v.data_offset,
636            data_type: v.data_type,
637            flags: v.flags,
638            value_name: String::new(),
639            offset: 0,
640        }
641    }
642}
643
644impl InvalidCell {
645    pub fn into_reg_sz_extended(&self) -> String {
646        let s: &[u16] = unsafe {
647            std::slice::from_raw_parts(self.content.as_ptr() as *const _, self.content.len() / 2)
648        };
649        let first_zero = match s.iter().rev().position(|&v| v == 0) {
650            Some(v) => s.len() - v,
651            None => s.len(),
652        };
653        let last_zero = match s[0..first_zero].iter().rev().position(|&v| v != 0) {
654            Some(v) => first_zero - v,
655            None => s.len(),
656        };
657        String::from_utf16_lossy(&s[..last_zero])
658    }
659    pub fn into_reg_sz_ascii(&self) -> String {
660        let first_zero = match self.content.iter().rev().position(|&v| v == 0) {
661            Some(v) => self.content.len() - v,
662            None => self.content.len(),
663        };
664        let last_zero = match self.content[0..first_zero]
665            .iter()
666            .rev()
667            .position(|&v| v != 0)
668        {
669            Some(v) => first_zero - v,
670            None => self.content.len(),
671        };
672        let ret = String::from_utf8_lossy(&self.content[..last_zero]).to_string();
673        ret
674    }
675    pub fn into_dword(&self) -> u32 {
676        if self.content.len() != 4 {
677            return 0;
678        }
679        u32::from_ne_bytes(self.content[0..4].try_into().unwrap_or_default())
680    }
681    pub fn into_dword_le(&self) -> u32 {
682        if self.content.len() != 4 {
683            return 0;
684        }
685        u32::from_le_bytes(self.content[0..4].try_into().unwrap_or_default())
686    }
687    pub fn into_dword_be(&self) -> u32 {
688        if self.content.len() != 4 {
689            return 0;
690        }
691        u32::from_be_bytes(self.content[0..4].try_into().unwrap_or_default())
692    }
693    pub fn into_qword_le(&self) -> u64 {
694        if self.content.len() != 8 {
695            return 0;
696        }
697        u64::from_le_bytes(self.content[0..8].try_into().unwrap_or_default())
698    }
699}
700
701#[cfg(test)]
702mod tst {
703    use crate::cell::HashLeafCell;
704
705    #[test]
706    fn should_hash_sam_name() {
707        assert_eq!(116109, HashLeafCell::hash_name("SAM"));
708        assert_eq!(116109, HashLeafCell::hash_name("sam"));
709        assert_eq!(116109, HashLeafCell::hash_name("SaM"));
710    }
711}