readhive/
readhive.rs

1// Copyright 2019-2025 Colin Finck <colin@reactos.org>
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4use std::env;
5use std::fs::File;
6use std::io::Read;
7
8use nt_hive::{Hive, KeyNode, KeyValueData, KeyValueDataType, Result};
9use zerocopy::SplitByteSlice;
10
11fn main() -> Result<(), String> {
12    // Parse arguments.
13    let args: Vec<String> = env::args().collect();
14    if args.len() < 2 {
15        println!("Usage: readhive <FILENAME>");
16        return Ok(());
17    }
18
19    // Read the hive file.
20    let filename = &args[1];
21    let mut f = File::open(filename).map_err(|e| format!("Error opening hive file: {e}"))?;
22    let mut buffer = Vec::<u8>::new();
23    f.read_to_end(&mut buffer)
24        .map_err(|e| format!("Error reading hive file: {e}"))?;
25
26    // Parse the hive.
27    let hive = Hive::new(buffer.as_ref()).map_err(|e| format!("Error parsing hive file: {e}"))?;
28
29    // Print the name of the root key node.
30    let root_key = hive
31        .root_key_node()
32        .map_err(|e| format!("Error getting root key: {e}"))?;
33    println!("{}", root_key.name().unwrap().to_string_lossy());
34
35    process_subkey(root_key, 0)?;
36
37    Ok(())
38}
39
40fn process_subkey<B>(key_node: KeyNode<B>, level: usize) -> Result<(), String>
41where
42    B: SplitByteSlice,
43{
44    // Print the names of subkeys of this node.
45    if let Some(subkeys) = key_node.subkeys() {
46        let subkeys = subkeys.map_err(|e| format!("Error getting subkeys: {e}"))?;
47
48        for key_node in subkeys {
49            let key_node = key_node.map_err(|e| format!("Error enumerating key: {e}"))?;
50            let key_name = key_node
51                .name()
52                .map_err(|e| format!("Error getting key name: {e}"))?;
53
54            print_indentation(level);
55            println!("● {key_name}");
56
57            if let Some(class_name) = key_node.class_name() {
58                let class_name =
59                    class_name.map_err(|e| format!("Error getting class name: {e}"))?;
60                print_indentation(level);
61                println!("  Class Name: {class_name}");
62            }
63
64            // Print the names of the values of this node.
65            if let Some(value_iter) = key_node.values() {
66                let value_iter =
67                    value_iter.map_err(|e| format!("Error creating value iterator: {e}"))?;
68
69                for value in value_iter {
70                    let value = value.map_err(|e| format!("Error enumerating value: {e}"))?;
71
72                    let mut value_name = value
73                        .name()
74                        .map_err(|e| format!("Error getting value name: {e}"))?
75                        .to_string_lossy();
76                    if value_name.is_empty() {
77                        value_name.push_str("(Default)");
78                    }
79
80                    let value_type = value
81                        .data_type()
82                        .map_err(|e| format!("Error getting value type: {e}"))?;
83
84                    let data_size = value.data_size();
85
86                    // First line: Value Name, Data Type, and Data Size
87                    print_indentation(level);
88                    println!("  ○ {value_name} - {value_type:?} - {data_size}");
89
90                    // Second line: The actual Value Data
91                    print_indentation(level);
92                    print!("    ");
93
94                    match value_type {
95                        KeyValueDataType::RegSZ | KeyValueDataType::RegExpandSZ => {
96                            let string_data = value
97                                .string_data()
98                                .map_err(|e| format!("Error getting string data: {e}"))?;
99                            println!("{string_data}")
100                        }
101                        KeyValueDataType::RegBinary => {
102                            let binary_data = value
103                                .data()
104                                .map_err(|e| format!("Error getting binary data: {e}"))?;
105                            match binary_data {
106                                KeyValueData::Small(data) => println!("{data:?}"),
107                                KeyValueData::Big(_iter) => println!("BIG DATA"),
108                            }
109                        }
110                        KeyValueDataType::RegDWord | KeyValueDataType::RegDWordBigEndian => {
111                            let dword_data = value
112                                .dword_data()
113                                .map_err(|e| format!("Error getting DWORD data: {e}"))?;
114                            println!("{dword_data}")
115                        }
116                        KeyValueDataType::RegMultiSZ => {
117                            let multi_string_data = value
118                                .multi_string_data()
119                                .map_err(|e| format!("Error getting multi string data: {e}"))?
120                                .collect::<Result<Vec<_>>>()
121                                .map_err(|e| {
122                                    format!("Error getting multi string element data: {e}")
123                                })?;
124                            println!("{multi_string_data:?}")
125                        }
126                        KeyValueDataType::RegQWord => {
127                            let qword_data = value
128                                .qword_data()
129                                .map_err(|e| format!("Error getting QWORD data: {e}"))?;
130                            println!("{qword_data}")
131                        }
132                        _ => println!(),
133                    }
134                }
135            }
136
137            // Process subkeys.
138            process_subkey(key_node, level + 1)?;
139        }
140    }
141
142    Ok(())
143}
144
145fn print_indentation(level: usize) {
146    for _i in 0..level {
147        print!("  ");
148    }
149}