1use crate::{
2 err::ForensicError,
3 traits::registry::{RegHiveKey, RegValue, RegistryKeyInfo, RegistryReader},
4};
5use std::{cell::RefCell, collections::BTreeMap};
6
7use super::time::Filetime;
8
9#[derive(Clone, Debug)]
11pub struct TestingRegistry {
12 pub cell: BTreeMap<String, MountedCell>,
13 pub cached: RefCell<BTreeMap<RegHiveKey, String>>,
14 pub counter: RefCell<isize>,
15}
16
17impl Default for TestingRegistry {
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23impl TestingRegistry {
24 pub fn empty() -> Self {
25 Self {
26 cell: BTreeMap::new(),
27 cached: RefCell::new(basic_cache()),
28 counter: RefCell::default(),
29 }
30 }
31 pub fn new() -> Self {
32 Self {
33 cell: basic_registry(),
34 cached: RefCell::new(basic_cache()),
35 counter: RefCell::new(0),
36 }
37 }
38 pub fn increase_counter(&self) -> isize {
39 let mut borrowed = self.counter.borrow_mut();
40 let ret = *borrowed;
41 *borrowed += 1;
42 ret
43 }
44 pub fn add_value(&mut self, path: &str, value: &str, data: RegValue) {
45 let (hkey, rest) = match path.split_once(|v| v == '/' || v == '\\') {
46 Some(v) => v,
47 None => {
48 return self
49 .cell
50 .entry(path.to_string())
51 .or_insert(MountedCell::new(path))
52 .add_value("", value, data)
53 }
54 };
55 self.cell
56 .entry(hkey.to_string())
57 .or_insert(MountedCell::new(hkey))
58 .add_value(rest, value, data);
59 }
60 pub fn contains(&self, path: &str) -> bool {
61 let (hkey, rest) = match path.split_once(|v| v == '/' || v == '\\') {
62 Some(v) => v,
63 None => return self.cell.contains_key(path),
64 };
65 let hive = match self.cell.get(hkey) {
66 Some(v) => v,
67 None => return false,
68 };
69 hive.contains_key(rest)
70 }
71 pub fn get_value(&self, path: &str, value: &str) -> Option<RegValue> {
72 let (hkey, rest) = match path.split_once(|v| v == '/' || v == '\\') {
73 Some(v) => v,
74 None => (path, ""),
75 };
76 let hive = match self.cell.get(hkey) {
77 Some(v) => v,
78 None => return None,
79 };
80 hive.get_value(rest, value)
81 }
82 pub fn get_values(&self, path: &str) -> Option<Vec<String>> {
83 let (hkey, rest) = match path.split_once(|v| v == '/' || v == '\\') {
84 Some(v) => v,
85 None => (path, ""),
86 };
87 let hive = match self.cell.get(hkey) {
88 Some(v) => v,
89 None => return None,
90 };
91 Some(hive.get_values(rest))
92 }
93 pub fn get_keys(&self, path: &str) -> Option<Vec<String>> {
94 let (hkey, rest) = match path.split_once(|v| v == '/' || v == '\\') {
95 Some(v) => v,
96 None => (path, ""),
97 };
98 let hive = match self.cell.get(hkey) {
99 Some(v) => v,
100 None => return None,
101 };
102 Some(hive.get_keys(rest))
103 }
104}
105
106#[derive(Clone, Debug, Default)]
107pub struct MountedCell {
108 pub name: String,
109 pub keys: BTreeMap<String, MountedCell>,
110 pub values: BTreeMap<String, RegValue>,
111}
112impl MountedCell {
113 pub fn new(name: &str) -> Self {
114 Self {
115 name: name.into(),
116 keys: BTreeMap::new(),
117 values: BTreeMap::new(),
118 }
119 }
120 pub fn add_key(&mut self, path: &str) {
121 if path.is_empty() {
122 return;
123 }
124 let (first, rest) = match path.split_once(|v| v == '/' || v == '\\') {
125 Some(v) => v,
126 None => {
127 self.keys
128 .entry(path.to_string())
129 .or_insert(MountedCell::new(path))
130 .add_key(path);
131 return;
132 }
133 };
134 self.keys
135 .entry(first.to_string())
136 .or_insert(MountedCell::new(first))
137 .add_key(rest);
138 }
139 pub fn contains_key(&self, path: &str) -> bool {
140 let (first, rest) = match path.split_once(|v| v == '/' || v == '\\') {
141 Some(v) => v,
142 None => return self.keys.contains_key(path),
143 };
144 let hive = match self.keys.get(first) {
145 Some(v) => v,
146 None => return false,
147 };
148 hive.contains_key(rest)
149 }
150 pub fn add_value(&mut self, path: &str, value: &str, data: RegValue) {
151 if path.is_empty() {
152 self.values.insert(value.into(), data);
153 return;
154 }
155 let (first, rest) = match path.split_once(|v| v == '/' || v == '\\') {
156 Some(v) => v,
157 None => {
158 self.keys
159 .entry(path.to_string())
160 .or_insert(MountedCell::new(path))
161 .add_value("", value, data);
162 return;
163 }
164 };
165 self.keys
166 .entry(first.to_string())
167 .or_insert(MountedCell::new(first))
168 .add_value(rest, value, data);
169 }
170 pub fn get_value(&self, path: &str, value: &str) -> Option<RegValue> {
171 if path.is_empty() {
172 return self.values.get(value).cloned();
173 }
174 let (first, rest) = match path.split_once(|v| v == '/' || v == '\\') {
175 Some(v) => v,
176 None => return self.keys.get(path)?.get_value("", value),
177 };
178 self.keys.get(first)?.get_value(rest, value)
179 }
180 pub fn get_values(&self, path: &str) -> Vec<String> {
181 if path.is_empty() {
182 return self
183 .values
184 .keys()
185 .map(|v| v.to_string())
186 .collect();
187 }
188 let (first, rest) = match path.split_once(|v| v == '/' || v == '\\') {
189 Some(v) => v,
190 None => {
191 return match self.keys.get(path) {
192 Some(v) => v.get_values(""),
193 None => Vec::new(),
194 }
195 }
196 };
197 match self.keys.get(first) {
198 Some(v) => v.get_values(rest),
199 None => Vec::new(),
200 }
201 }
202 pub fn get_keys(&self, path: &str) -> Vec<String> {
203 if path.is_empty() {
204 return self
205 .keys
206 .keys()
207 .map(|v| v.to_string())
208 .collect();
209 }
210 let (first, rest) = match path.split_once(|v| v == '/' || v == '\\') {
211 Some(v) => v,
212 None => {
213 return match self.keys.get(path) {
214 Some(v) => v.get_keys(""),
215 None => Vec::new(),
216 }
217 }
218 };
219 match self.keys.get(first) {
220 Some(v) => v.get_keys(rest),
221 None => Vec::new(),
222 }
223 }
224}
225
226impl RegistryReader for TestingRegistry {
227 fn from_file(
228 &self,
229 _file: Box<dyn crate::traits::vfs::VirtualFile>,
230 ) -> crate::err::ForensicResult<Box<dyn RegistryReader>> {
231 Ok(Box::new(TestingRegistry::new()))
232 }
233
234 fn from_fs(
235 &self,
236 _fs: Box<dyn crate::traits::vfs::VirtualFileSystem>,
237 ) -> crate::err::ForensicResult<Box<dyn RegistryReader>> {
238 Ok(Box::new(TestingRegistry::new()))
239 }
240
241 fn open_key(
242 &self,
243 hkey: crate::traits::registry::RegHiveKey,
244 key_name: &str,
245 ) -> crate::err::ForensicResult<crate::traits::registry::RegHiveKey> {
246 let mut borrowed = self.cached.borrow_mut();
247 let (hkey, path) = match borrowed.get(&hkey) {
248 Some(v) => {
249 let full_path = format!("{}\\{}", v, key_name);
250 if !self.contains(&full_path) {
251 return Err(ForensicError::missing_string(format!(
252 "Key path {} not found",
253 full_path
254 )));
255 }
256 let handle = self.increase_counter();
257 (handle, full_path)
258 }
259 None => return Err(ForensicError::missing_str("Hkey not found")),
260 };
261 borrowed.insert(RegHiveKey::Hkey(hkey), path);
262 Ok(RegHiveKey::Hkey(hkey))
263 }
264
265 fn read_value(
266 &self,
267 hkey: crate::traits::registry::RegHiveKey,
268 value_name: &str,
269 ) -> crate::err::ForensicResult<RegValue> {
270 let borrowed = self.cached.borrow();
271 let key_path = borrowed
272 .get(&hkey)
273 .ok_or_else(|| ForensicError::missing_str("HKey not found"))?;
274 let value = self.get_value(key_path, value_name).ok_or_else(|| {
275 ForensicError::missing_string(format!("Value {}\\{} not found", key_path, value_name))
276 })?;
277 Ok(value)
278 }
279
280 fn enumerate_values(
281 &self,
282 hkey: crate::traits::registry::RegHiveKey,
283 ) -> crate::err::ForensicResult<Vec<String>> {
284 let borrowed = self.cached.borrow();
285 let key_path = borrowed
286 .get(&hkey)
287 .ok_or_else(|| ForensicError::missing_str("HKey not found"))?;
288 let value = self.get_values(key_path).ok_or_else(|| {
289 ForensicError::missing_string(format!("Values for {} not found", key_path))
290 })?;
291 Ok(value)
292 }
293
294 fn enumerate_keys(
295 &self,
296 hkey: crate::traits::registry::RegHiveKey,
297 ) -> crate::err::ForensicResult<Vec<String>> {
298 let borrowed = self.cached.borrow();
299 let key_path = borrowed
300 .get(&hkey)
301 .ok_or_else(|| ForensicError::missing_str("HKey not found"))?;
302 let value = self.get_keys(key_path).ok_or_else(|| {
303 ForensicError::missing_string(format!("Keys for {} not found", key_path))
304 })?;
305 Ok(value)
306 }
307
308 fn key_at(
309 &self,
310 hkey: crate::traits::registry::RegHiveKey,
311 pos: u32,
312 ) -> crate::err::ForensicResult<String> {
313 let borrowed = self.cached.borrow();
314 let key_path = borrowed
315 .get(&hkey)
316 .ok_or_else(|| ForensicError::missing_str("HKey not found"))?;
317 let mut value = self.get_keys(key_path).ok_or_else(|| {
318 ForensicError::missing_string(format!("Keys for {} not found", key_path))
319 })?;
320 let pos = pos as usize;
321 if pos > value.len() {
322 return Err(ForensicError::NoMoreData);
323 }
324 Ok(value.remove(pos))
325 }
326
327 fn value_at(
328 &self,
329 hkey: crate::traits::registry::RegHiveKey,
330 pos: u32,
331 ) -> crate::err::ForensicResult<String> {
332 let borrowed = self.cached.borrow();
333 let key_path = borrowed
334 .get(&hkey)
335 .ok_or_else(|| ForensicError::missing_str("HKey not found"))?;
336 let mut value = self.get_values(key_path).ok_or_else(|| {
337 ForensicError::missing_string(format!("Values for {} not found", key_path))
338 })?;
339 let pos = pos as usize;
340 if pos > value.len() {
341 return Err(ForensicError::NoMoreData);
342 }
343 Ok(value.remove(pos))
344 }
345
346 fn key_info(&self, hkey: RegHiveKey) -> crate::err::ForensicResult<crate::traits::registry::RegistryKeyInfo> {
347 let borrowed = self.cached.borrow();
348 let key_path = borrowed
349 .get(&hkey)
350 .ok_or_else(|| ForensicError::missing_str("HKey not found"))?;
351 let value = self.get_values(key_path).ok_or_else(|| {
352 ForensicError::missing_string(format!("Values for {} not found", key_path))
353 })?;
354 let keys = self.get_keys(key_path).ok_or_else(|| {
355 ForensicError::missing_string(format!("Values for {} not found", key_path))
356 })?;
357 Ok(RegistryKeyInfo {
358 last_write_time : Filetime::new(0),
359 subkeys : keys.len() as u32,
360 values : value.len() as u32,
361 max_subkey_name_length : keys.iter().map(|v| v.len()).fold(0, |acc, e| e.max(acc)) as u32,
362 max_value_name_length: value.iter().map(|v| v.len()).fold(0, |acc, e| e.max(acc)) as u32,
363 max_value_length: 0,
364 })
365 }
366}
367fn basic_cache() -> BTreeMap<RegHiveKey, String> {
368 {
369 let mut map = BTreeMap::new();
370 for (k, p) in [
371 (RegHiveKey::HkeyLocalMachine, "HKLM"),
372 (RegHiveKey::HkeyCurrentUser, "HKCU"),
373 (RegHiveKey::HkeyUsers, "HKU"),
374 (RegHiveKey::HkeyClassesRoot, "HKCR"),
375 ] {
376 map.insert(k, p.to_string());
377 }
378 map
379 }
380}
381
382fn basic_registry() -> BTreeMap<String, MountedCell> {
383 let mut map = BTreeMap::new();
384 for k in ["HKLM", "HKCU", "HKCR"] {
385 map.insert(k.to_string(), MountedCell::new(k));
386 }
387 let mut hkcu_cell = MountedCell::new("HKU");
388 hkcu_cell.add_value(
389 "S-1-5-21-1366093794-4292800403-1155380978-513\\Volatile Environment",
390 "USERPROFILE",
391 RegValue::from_str(r"C:\Users\Tester"),
392 );
393 hkcu_cell.add_value(
394 "S-1-5-21-1366093794-4292800403-1155380978-513\\Volatile Environment",
395 "APPDATA",
396 RegValue::from_str(r"C:\Users\Tester\AppData\Roaming"),
397 );
398 hkcu_cell.add_value(
399 "S-1-5-21-1366093794-4292800403-1155380978-513\\Volatile Environment",
400 "LOCALAPPDATA",
401 RegValue::from_str(r"C:\Users\Tester\AppData\Local"),
402 );
403 hkcu_cell.add_value(
404 "S-1-5-21-1366093794-4292800403-1155380978-513\\Volatile Environment",
405 "USERDOMAIN",
406 RegValue::from_str(r"TestMachine"),
407 );
408 hkcu_cell.add_value(
409 "S-1-5-21-1366093794-4292800403-1155380978-513\\Volatile Environment",
410 "USERNAME",
411 RegValue::from_str(r"Tester"),
412 );
413 map.insert("HKU".into(), hkcu_cell);
414 map
415}
416
417pub fn init_testing_logger() {
418 let rcv = crate::notifications::testing_notifier_dummy();
419 std::thread::spawn(move || loop {
420 let msg = match rcv.recv() {
421 Ok(v) => v,
422 Err(_) => return,
423 };
424 println!(
425 "{:?} - {} - {}:{} - {}",
426 msg.r#type, msg.module, msg.file, msg.line, msg.data
427 );
428 });
429 let rcv = crate::logging::testing_logger_dummy();
430 std::thread::spawn(move || loop {
431 let msg = match rcv.recv() {
432 Ok(v) => v,
433 Err(_) => return,
434 };
435 println!(
436 "{:?} - {} - {}:{} - {}",
437 msg.level, msg.module, msg.file, msg.line, msg.data
438 );
439 });
440}