use std::io::Cursor;
use crate::hive::Hive;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)]
pub enum HiveType {
System,
Software,
NtUser,
UsrClass,
Sam,
Security,
Amcache,
Bcd,
Default,
Components,
Unknown,
}
impl std::fmt::Display for HiveType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::System => write!(f, "SYSTEM"),
Self::Software => write!(f, "SOFTWARE"),
Self::NtUser => write!(f, "NTUSER.DAT"),
Self::UsrClass => write!(f, "UsrClass.dat"),
Self::Sam => write!(f, "SAM"),
Self::Security => write!(f, "SECURITY"),
Self::Amcache => write!(f, "Amcache.hve"),
Self::Bcd => write!(f, "BCD"),
Self::Default => write!(f, "DEFAULT"),
Self::Components => write!(f, "COMPONENTS"),
Self::Unknown => write!(f, "Unknown"),
}
}
}
impl Hive<Cursor<Vec<u8>>> {
pub fn detect_hive_type(&self) -> HiveType {
let Ok(root) = self.root_key() else {
return HiveType::Unknown;
};
let Ok(subkeys) = root.subkeys() else {
return HiveType::Unknown;
};
let names: Vec<String> = subkeys
.iter()
.map(|k| k.name().to_ascii_uppercase())
.collect();
if names.contains(&"SELECT".to_string()) && names.contains(&"CONTROLSET001".to_string()) {
return HiveType::System;
}
if names.contains(&"SAM".to_string()) {
if let Ok(Some(sam)) = root.subkey("SAM") {
if let Ok(Some(_)) = sam.subkey("Domains") {
return HiveType::Sam;
}
}
}
if names.contains(&"POLICY".to_string()) {
return HiveType::Security;
}
if names.contains(&"ROOT".to_string())
|| names.contains(&"INVENTORYAPPLICATIONFILE".to_string())
{
return HiveType::Amcache;
}
if names.contains(&"DESCRIPTION".to_string()) && names.contains(&"OBJECTS".to_string()) {
return HiveType::Bcd;
}
if names.contains(&"MICROSOFT".to_string()) && names.contains(&"CLASSES".to_string()) {
return HiveType::Software;
}
if names.contains(&"SOFTWARE".to_string())
&& (names.contains(&"APPEVENTS".to_string())
|| names.contains(&"CONSOLE".to_string())
|| names.contains(&"ENVIRONMENT".to_string()))
{
return HiveType::NtUser;
}
if names.contains(&"APPEVENTS".to_string()) && !names.contains(&"SOFTWARE".to_string()) {
return HiveType::Default;
}
if root.name().to_ascii_uppercase().contains("CLASSES") {
return HiveType::UsrClass;
}
HiveType::Unknown
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hive_type_display() {
assert_eq!(HiveType::System.to_string(), "SYSTEM");
assert_eq!(HiveType::NtUser.to_string(), "NTUSER.DAT");
assert_eq!(HiveType::Amcache.to_string(), "Amcache.hve");
assert_eq!(HiveType::Software.to_string(), "SOFTWARE");
assert_eq!(HiveType::Sam.to_string(), "SAM");
assert_eq!(HiveType::Security.to_string(), "SECURITY");
assert_eq!(HiveType::Bcd.to_string(), "BCD");
assert_eq!(HiveType::Default.to_string(), "DEFAULT");
assert_eq!(HiveType::Components.to_string(), "COMPONENTS");
assert_eq!(HiveType::UsrClass.to_string(), "UsrClass.dat");
assert_eq!(HiveType::Unknown.to_string(), "Unknown");
}
}