forensic_rs/traits/registry/
mod.rs

1use crate::{
2    err::{ForensicError, ForensicResult}, utils::time::Filetime
3};
4
5use super::vfs::{VirtualFile, VirtualFileSystem};
6
7pub const HKCR : RegHiveKey = RegHiveKey::HkeyClassesRoot;
8pub const HKC : RegHiveKey = RegHiveKey::HkeyCurrentConfig;
9pub const HKCU : RegHiveKey = RegHiveKey::HkeyCurrentUser;
10pub const HKLM : RegHiveKey = RegHiveKey::HkeyLocalMachine;
11pub const HKU : RegHiveKey = RegHiveKey::HkeyUsers;
12
13pub mod extra;
14
15#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
16pub enum RegHiveKey {
17    HkeyClassesRoot,
18    HkeyCurrentConfig,
19    HkeyCurrentUser,
20    HkeyDynData,
21    HkeyLocalMachine,
22    KkeyPerformanceData,
23    HkeyPerformanceNlstext,
24    HkeyPerformanceText,
25    HkeyUsers,
26    Hkey(isize),
27}
28
29#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
30pub enum RegValue {
31    Binary(Vec<u8>),
32    MultiSZ(Vec<String>),
33    ExpandSZ(String),
34    SZ(String),
35    DWord(u32),
36    QWord(u64),
37}
38
39impl RegValue {
40    pub fn from_str(v : &str) -> RegValue {
41        RegValue::SZ(v.to_string())
42    }
43    pub fn from_string(v : String) -> RegValue {
44        RegValue::SZ(v.clone())
45    }
46    pub fn from_u32(v : u32) -> RegValue {
47        RegValue::DWord(v)
48    }
49    pub fn from_u64(v : u64) -> RegValue {
50        RegValue::QWord(v)
51    }
52}
53
54impl Into<RegValue> for String {
55    fn into(self) -> RegValue {
56        RegValue::SZ(self)
57    }
58}
59
60impl Into<RegValue> for &str {
61    fn into(self) -> RegValue {
62        RegValue::SZ(self.to_string())
63    }
64}
65
66impl Into<RegValue> for u32 {
67    fn into(self) -> RegValue {
68        RegValue::DWord(self)
69    }
70}
71
72impl Into<RegValue> for u64 {
73    fn into(self) -> RegValue {
74        RegValue::QWord(self)
75    }
76}
77impl Into<RegValue> for i32 {
78    fn into(self) -> RegValue {
79        RegValue::DWord(self as u32)
80    }
81}
82
83impl Into<RegValue> for i64 {
84    fn into(self) -> RegValue {
85        RegValue::QWord(self as u64)
86    }
87}
88impl Into<RegValue> for usize {
89    fn into(self) -> RegValue {
90        #[cfg(target_pointer_width="32")] 
91        {
92            RegValue::DWord(self as u32)
93        }
94        #[cfg(target_pointer_width="16")] 
95        {
96            RegValue::DWord(self as u32)
97        }
98        #[cfg(target_pointer_width="64")] 
99        {
100            RegValue::QWord(self as u64)
101        }
102    }
103}
104
105impl Into<RegValue> for Vec<u8> {
106    fn into(self) -> RegValue {
107        RegValue::Binary(self)
108    }
109}
110
111impl From<Vec<String>> for RegValue {
112    fn from(value: Vec<String>) -> Self {
113        RegValue::MultiSZ(value)
114    }
115}
116impl From<&[u8]> for RegValue {
117    fn from(value: &[u8]) -> Self {
118        let mut vc = Vec::with_capacity(value.len());
119        for v in value {
120            vc.push(*v);
121        }
122        RegValue::Binary(vc)
123    }
124}
125impl From<&[String]> for RegValue {
126    fn from(value: &[String]) -> Self {
127        let mut vc = Vec::with_capacity(value.len());
128        for v in value {
129            vc.push(v.clone());
130        }
131        RegValue::MultiSZ(vc)
132    }
133}
134impl From<&[&String]> for RegValue {
135    fn from(value: &[&String]) -> Self {
136        let mut vc = Vec::with_capacity(value.len());
137        for &v in value {
138            vc.push(v.clone());
139        }
140        RegValue::MultiSZ(vc)
141    }
142}
143impl From<&[&str]> for RegValue {
144    fn from(value: &[&str]) -> Self {
145        let mut vc = Vec::with_capacity(value.len());
146        for &v in value {
147            vc.push(v.to_string());
148        }
149        RegValue::MultiSZ(vc)
150    }
151}
152
153impl TryFrom<RegValue> for String {
154    type Error = ForensicError;
155    fn try_from(value : RegValue) -> Result<Self, Self::Error> {
156        match value {
157            RegValue::MultiSZ(v) => Ok(v.join("\n")),
158            RegValue::ExpandSZ(v) => Ok(v),
159            RegValue::SZ(v) => Ok(v),
160            _ => Err(ForensicError::CastError),
161        }
162    }
163}
164impl TryFrom<RegValue> for u32 {
165    type Error = ForensicError;
166    fn try_from(value : RegValue) -> Result<Self, Self::Error> {
167        match value {
168            RegValue::DWord(v) => Ok(v),
169            RegValue::QWord(v) => Ok(v as u32),
170            _ => Err(ForensicError::CastError),
171        }
172    }
173}
174impl TryFrom<RegValue> for u64 {
175    type Error = ForensicError;
176    fn try_from(value : RegValue) -> Result<Self, Self::Error> {
177        match value {
178            RegValue::DWord(v) => Ok(v as u64),
179            RegValue::QWord(v) => Ok(v),
180            _ => Err(ForensicError::CastError),
181        }
182    }
183}
184impl TryFrom<RegValue> for Vec<u8> {
185    type Error = ForensicError;
186    fn try_from(value : RegValue) -> Result<Self, Self::Error> {
187        match value {
188            RegValue::Binary(v) => Ok(v),
189            _ => Err(ForensicError::CastError),
190        }
191    }
192}
193
194#[derive(Clone, Copy, Debug, Default)]
195pub struct RegistryKeyInfo {
196    pub subkeys : u32,
197    pub max_subkey_name_length : u32,
198    pub values : u32,
199    pub max_value_name_length : u32,
200    pub max_value_length : u32,
201    pub last_write_time : Filetime
202
203}
204
205/// It allows decoupling the registry access library from the analysis library.
206pub trait RegistryReader {
207    /// Mounts a registry reader in a hive file
208    fn from_file(&self, file: Box<dyn VirtualFile>) -> ForensicResult<Box<dyn RegistryReader>>;
209    /// The Windows registry consists of numerous hives and we need access to all of them.
210    fn from_fs(&self, fs: Box<dyn VirtualFileSystem>) -> ForensicResult<Box<dyn RegistryReader>>;
211    /// Opens a registry key. If the registry reader is a file based one it needs to do the same thing that the Window Kernel does:
212    /// store a Map with the association of keys with the path they point to.
213    fn open_key(&self, hkey: RegHiveKey, key_name: &str) -> ForensicResult<RegHiveKey>;
214    fn read_value(&self, hkey: RegHiveKey, value_name: &str) -> ForensicResult<RegValue>;
215    fn enumerate_values(&self, hkey: RegHiveKey) -> ForensicResult<Vec<String>>;
216    fn enumerate_keys(&self, hkey: RegHiveKey) -> ForensicResult<Vec<String>>;
217    fn key_at(&self, hkey: RegHiveKey, pos: u32) -> ForensicResult<String>;
218    fn value_at(&self, hkey: RegHiveKey, pos: u32) -> ForensicResult<String>;
219    /// Retrieves information about the key. Emulates RegQueryInfoKey
220    fn key_info(&self, hkey: RegHiveKey) -> ForensicResult<RegistryKeyInfo>;
221    /// Closes a handle to the specified registry key.
222    #[allow(unused_variables)]
223    fn close_key(&self, hkey: RegHiveKey) {}
224
225    /// Get the same value as the env var "%SystemRoot%"". It's usually "C:\Windows"
226    fn get_system_root(&self) -> ForensicResult<String> {
227        let key = self.open_key(
228            RegHiveKey::HkeyLocalMachine,
229            "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
230        )?;
231        let value = self.read_value(key, "SystemRoot")?;
232        Ok(value.try_into()?)
233    }
234
235    fn list_users(&self) -> ForensicResult<Vec<String>> {
236        let mut users = self.enumerate_keys(RegHiveKey::HkeyUsers)?;
237        users.retain(|v| v.starts_with("S-") && !v.ends_with("_Classes"));
238        Ok(users)
239    }
240
241    /// Get the current build of Windows: See "RTM build" in https://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions
242    fn windows_build(&self) -> ForensicResult<u32> {
243        let key = self.open_key(
244            RegHiveKey::HkeyLocalMachine,
245            "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
246        )?;
247        let value = self.read_value(key, "CurrentBuild")?;
248        Ok(value.try_into()?)
249    }
250}
251
252/// Simplify the process of closing Registry keys
253/// 
254/// ```rust
255/// use std::collections::BTreeMap;
256/// use forensic_rs::prelude::*;
257/// use forensic_rs::utils::testing::TestingRegistry;
258/// let reader = TestingRegistry::new();
259/// let user_id = "S-1-5-21-1366093794-4292800403-1155380978-513";
260/// let user_key = reader.open_key(RegHiveKey::HkeyUsers, user_id).unwrap();
261/// let _user_info : BTreeMap<String, String> = auto_close_key(&reader, user_key, || {
262///     let volatile_key = reader.open_key(user_key, "Volatile Environment")?;
263///     auto_close_key(&reader, volatile_key, || {
264///         let mut user_info = BTreeMap::new();
265///         user_info.insert("id".into(), user_id.to_string());
266///         user_info.insert("home".into(), reader.read_value(volatile_key, "USERPROFILE")?.try_into()?);
267///         user_info.insert("app_data".into(), reader.read_value(volatile_key, "APPDATA")?.try_into()?);
268///         user_info.insert("local_app_data".into(), reader.read_value(volatile_key, "LOCALAPPDATA")?.try_into()?);
269///         user_info.insert("domain".into(), reader.read_value(volatile_key, "USERDOMAIN")?.try_into()?);
270///         user_info.insert("name".into(), reader.read_value(volatile_key, "USERNAME")?.try_into()?);
271///         Ok(user_info)
272///     })
273/// }).unwrap();
274/// ```
275pub fn auto_close_key<F, T>(reader : &dyn RegistryReader, key : RegHiveKey, operation : F) -> ForensicResult<T> where
276    F: FnOnce() -> ForensicResult<T> {
277        let result = operation();
278        reader.close_key(key);
279        result
280    }
281
282#[cfg(test)]
283mod reg_value {
284    use crate::{err::ForensicResult, traits::registry::{RegistryKeyInfo, RegistryReader}};
285
286    use super::RegValue;
287
288    #[test]
289    fn should_convert_using_try_into() {
290        let _: String = RegValue::SZ(format!("String RegValue"))
291            .try_into()
292            .expect("Must convert values");
293        let _: String = RegValue::MultiSZ(vec![format!("String RegValue")])
294            .try_into()
295            .expect("Must convert values");
296        let _: String = RegValue::ExpandSZ(format!("String RegValue"))
297            .try_into()
298            .expect("Must convert values");
299
300        let _ = TryInto::<u32>::try_into(RegValue::ExpandSZ(format!("String RegValue")))
301            .expect_err("Should return error");
302        let _ = TryInto::<u64>::try_into(RegValue::ExpandSZ(format!("String RegValue")))
303            .expect_err("Should return error");
304        let _ = TryInto::<Vec<u8>>::try_into(RegValue::ExpandSZ(format!("String RegValue")))
305            .expect_err("Should return error");
306
307        let _: u32 = RegValue::DWord(123)
308            .try_into()
309            .expect("Must convert values");
310        let _: u64 = RegValue::DWord(123)
311            .try_into()
312            .expect("Must convert values");
313
314        let _ = TryInto::<String>::try_into(RegValue::DWord(123)).expect_err("Should return error");
315        let _ =
316            TryInto::<Vec<u8>>::try_into(RegValue::DWord(123)).expect_err("Should return error");
317
318        let _: u32 = RegValue::QWord(123)
319            .clone()
320            .try_into()
321            .expect("Must convert values");
322        let _: u64 = RegValue::QWord(123)
323            .try_into()
324            .expect("Must convert values");
325
326        let _ = TryInto::<String>::try_into(RegValue::QWord(123)).expect_err("Should return error");
327        let _ =
328            TryInto::<Vec<u8>>::try_into(RegValue::QWord(123)).expect_err("Should return error");
329
330        let _: Vec<u8> = RegValue::Binary((1..255).collect())
331            .try_into()
332            .expect("Must convert values");
333        let _ = TryInto::<u32>::try_into(RegValue::Binary((1..255).collect()))
334            .expect_err("Should return error");
335        let _ = TryInto::<u32>::try_into(RegValue::Binary((1..255).collect()))
336            .expect_err("Should return error");
337        let _ = TryInto::<u32>::try_into(RegValue::Binary((1..255).collect()))
338            .expect_err("Should return error");
339    }
340
341    #[test]
342    fn should_generate_dummy_registry_reader() {
343        struct RegReader {}
344        impl RegistryReader for RegReader {
345            fn from_file(
346                &self,
347                _file: Box<dyn crate::traits::vfs::VirtualFile>,
348            ) -> crate::err::ForensicResult<Box<dyn RegistryReader>> {
349                Ok(Box::new(RegReader{}))
350            }
351
352            fn from_fs(
353                &self,
354                _fs: Box<dyn crate::traits::vfs::VirtualFileSystem>,
355            ) -> crate::err::ForensicResult<Box<dyn RegistryReader>> {
356                Ok(Box::new(RegReader{}))
357            }
358
359            fn open_key(
360                &self,
361                _hkey: crate::traits::registry::RegHiveKey,
362                _key_name: &str,
363            ) -> crate::err::ForensicResult<crate::traits::registry::RegHiveKey> {
364                Ok(crate::traits::registry::RegHiveKey::HkeyClassesRoot)
365            }
366
367            fn read_value(
368                &self,
369                _hkey: crate::traits::registry::RegHiveKey,
370                _value_name: &str,
371            ) -> crate::err::ForensicResult<RegValue> {
372                Ok(RegValue::SZ(format!("123")))
373            }
374
375            fn enumerate_values(
376                &self,
377                _hkey: crate::traits::registry::RegHiveKey,
378            ) -> crate::err::ForensicResult<Vec<String>> {
379                Ok(vec![format!("123")])
380            }
381
382            fn enumerate_keys(
383                &self,
384                _hkey: crate::traits::registry::RegHiveKey,
385            ) -> crate::err::ForensicResult<Vec<String>> {
386                Ok(vec![format!("123")])
387            }
388
389            fn key_at(
390                &self,
391                _hkey: crate::traits::registry::RegHiveKey,
392                _pos: u32,
393            ) -> crate::err::ForensicResult<String> {
394                Ok(format!("123"))
395            }
396
397            fn value_at(
398                &self,
399                _hkey: crate::traits::registry::RegHiveKey,
400                _pos: u32,
401            ) -> crate::err::ForensicResult<String> {
402                Ok(format!("123"))
403            }
404            fn key_info(&self, _hkey: crate::traits::registry::RegHiveKey) -> ForensicResult<crate::traits::registry::RegistryKeyInfo>{
405                Ok(RegistryKeyInfo::default())
406            }
407        }
408
409        let reader = RegReader {};
410        let mut reader : Box<dyn RegistryReader> = Box::new(reader);
411        fn tst(reg : &mut Box<dyn RegistryReader>) -> ForensicResult<()>{
412            assert_eq!("123",reg.key_at(crate::traits::registry::RegHiveKey::HkeyClassesRoot, 123)?);
413            Ok(())
414        }
415        tst(&mut reader).unwrap();
416    }
417}