pub const VERACRYPT_PATHS: &[&str] = &[
r"SOFTWARE\VeraCrypt",
r"SOFTWARE\Wow6432Node\VeraCrypt",
r"SYSTEM\CurrentControlSet\Services\veracrypt",
r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\VeraCrypt",
];
pub const BITLOCKER_PATHS: &[&str] = &[
r"SOFTWARE\Policies\Microsoft\FVE",
r"SYSTEM\CurrentControlSet\Control\BitLockerStatus",
r"SYSTEM\CurrentControlSet\Services\BDESVC",
r"SYSTEM\CurrentControlSet\Services\fvevol",
];
pub const EFS_PATHS: &[&str] = &[
r"SOFTWARE\Policies\Microsoft\Windows\System",
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS",
r"SOFTWARE\Policies\Microsoft\Windows NT\CurrentVersion\EFS",
];
pub const SEVENZIP_PATHS: &[&str] = &[
r"SOFTWARE\7-Zip",
r"SOFTWARE\Wow6432Node\7-Zip",
r"Software\7-Zip",
];
pub const WINRAR_PATHS: &[&str] = &[
r"SOFTWARE\WinRAR",
r"SOFTWARE\WinRAR SFX",
r"Software\WinRAR",
];
pub const TOR_PATHS: &[&str] = &[r"SOFTWARE\Tor Project", r"SOFTWARE\Wow6432Node\Tor Project"];
pub fn all_encryption_paths() -> impl Iterator<Item = &'static str> {
VERACRYPT_PATHS
.iter()
.chain(BITLOCKER_PATHS.iter())
.chain(EFS_PATHS.iter())
.chain(SEVENZIP_PATHS.iter())
.chain(WINRAR_PATHS.iter())
.chain(TOR_PATHS.iter())
.copied()
}
pub fn is_encryption_tool_path(path: &str) -> bool {
let lower = path.to_ascii_lowercase();
all_encryption_paths().any(|entry| lower.contains(&entry.to_ascii_lowercase()))
}
pub const RANSOMWARE_EXTENSIONS: &[&str] = &[
".wcry", ".wnry", ".wncry", ".locky", ".zepto", ".odin", ".cerber", ".cerber2",
".cerber3",
".locked",
".encrypted",
".crypt",
".crypz",
".cryp1",
".crinf",
".r5a",
".XData",
".cobra", ".dharma",
".phobos", ".ryuk", ".conti", ".hive", ".BlackCat",
".alphv", ".revil", ".sodinokibi",
".darkside",
".chaos",
".zeppelin",
".paymen45",
".eking", ".acute", ".scarab",
".globe",
".stampado",
".kr3",
".crypted",
".enc",
".fucked",
];
pub fn is_ransomware_extension(ext: &str) -> bool {
let normalized = if ext.starts_with('.') {
ext.to_ascii_lowercase()
} else {
format!(".{}", ext.to_ascii_lowercase())
};
RANSOMWARE_EXTENSIONS
.iter()
.any(|e| e.to_ascii_lowercase() == normalized)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn veracrypt_paths_contains_hklm_key() {
assert!(VERACRYPT_PATHS.contains(&r"SOFTWARE\VeraCrypt"));
}
#[test]
fn bitlocker_paths_contains_fve_policy() {
assert!(BITLOCKER_PATHS.contains(&r"SOFTWARE\Policies\Microsoft\FVE"));
}
#[test]
fn sevenzip_paths_contains_hklm_key() {
assert!(SEVENZIP_PATHS.contains(&r"SOFTWARE\7-Zip"));
}
#[test]
fn all_encryption_paths_includes_tor() {
assert!(all_encryption_paths().any(|p| p == r"SOFTWARE\Tor Project"));
}
#[test]
fn all_encryption_paths_covers_all_tools() {
let all: Vec<_> = all_encryption_paths().collect();
for path in [
VERACRYPT_PATHS[0],
BITLOCKER_PATHS[0],
EFS_PATHS[0],
SEVENZIP_PATHS[0],
WINRAR_PATHS[0],
TOR_PATHS[0],
] {
assert!(
all.contains(&path),
"Missing path in all_encryption_paths: {path}"
);
}
}
#[test]
fn is_encryption_tool_path_veracrypt_matches() {
assert!(is_encryption_tool_path(r"SOFTWARE\VeraCrypt\MRUList"));
}
#[test]
fn is_encryption_tool_path_case_insensitive() {
assert!(is_encryption_tool_path(r"software\veracrypt"));
}
#[test]
fn is_encryption_tool_path_unrelated_returns_false() {
assert!(!is_encryption_tool_path(r"SOFTWARE\Microsoft\Office"));
}
#[test]
fn ransomware_extensions_contains_wcry() {
assert!(RANSOMWARE_EXTENSIONS.contains(&".wcry"));
}
#[test]
fn ransomware_extensions_contains_locky() {
assert!(RANSOMWARE_EXTENSIONS.contains(&".locky"));
}
#[test]
fn ransomware_extensions_contains_conti() {
assert!(RANSOMWARE_EXTENSIONS.contains(&".conti"));
}
#[test]
fn detects_wcry_with_dot() {
assert!(is_ransomware_extension(".wcry"));
}
#[test]
fn detects_wcry_without_dot() {
assert!(is_ransomware_extension("wcry"));
}
#[test]
fn detects_locky_uppercase() {
assert!(is_ransomware_extension(".LOCKY"));
}
#[test]
fn detects_ryuk() {
assert!(is_ransomware_extension(".ryuk"));
}
#[test]
fn detects_conti() {
assert!(is_ransomware_extension(".conti"));
}
#[test]
fn detects_blackcat() {
assert!(is_ransomware_extension(".BlackCat"));
}
#[test]
fn does_not_flag_docx() {
assert!(!is_ransomware_extension(".docx"));
}
#[test]
fn does_not_flag_exe() {
assert!(!is_ransomware_extension(".exe"));
}
#[test]
fn empty_string_not_ransomware_ext() {
assert!(!is_ransomware_extension(""));
}
}