pub const WINDOWS_RUN_KEYS: &[&str] = &[
r"Software\Microsoft\Windows\CurrentVersion\Run",
r"Software\Microsoft\Windows\CurrentVersion\RunOnce",
r"Software\Microsoft\Windows\CurrentVersion\RunServices",
r"SYSTEM\CurrentControlSet\Services",
r"Software\Microsoft\Windows NT\CurrentVersion\Winlogon",
r"Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options",
r"Software\Classes\exefile\shell\open\command",
r"SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDlls",
r"SYSTEM\CurrentControlSet\Control\Lsa",
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",
];
pub const LINUX_PERSISTENCE_PATHS: &[&str] = &[
"/etc/cron.d",
"/etc/cron.daily",
"/etc/cron.hourly",
"/etc/cron.monthly",
"/etc/cron.weekly",
"/var/spool/cron",
"/etc/init.d",
"/etc/rc.local",
"/etc/profile.d",
"/etc/ld.so.preload",
"/etc/pam.d",
"/etc/systemd/system",
"/usr/lib/systemd/system",
"/run/systemd/system",
"~/.bashrc",
"~/.bash_profile",
"~/.profile",
"~/.config/autostart",
];
pub const MACOS_PERSISTENCE_PATHS: &[&str] = &[
"/Library/LaunchAgents",
"/Library/LaunchDaemons",
"~/Library/LaunchAgents",
"/System/Library/LaunchAgents",
"/System/Library/LaunchDaemons",
"/Library/StartupItems",
"/etc/periodic/daily",
"/etc/periodic/weekly",
"/etc/periodic/monthly",
];
pub const IFEO_PATHS: &[&str] =
&[r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options"];
pub const APPINIT_PATHS: &[&str] = &[
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",
r"SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows",
];
pub const SESSION_MANAGER_PATHS: &[&str] = &[
r"SYSTEM\CurrentControlSet\Control\Session Manager",
r"SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute",
r"SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs",
];
pub const ACTIVE_SETUP_PATHS: &[&str] = &[
r"SOFTWARE\Microsoft\Active Setup\Installed Components",
r"SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components",
];
pub const SCREENSAVER_PATHS: &[&str] = &[r"Control Panel\Desktop"];
pub const WINLOGON_PATHS: &[&str] = &[
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon",
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify",
];
pub const COM_HIJACK_PATHS: &[&str] = &[
r"SOFTWARE\Classes\CLSID",
r"SOFTWARE\Classes\WOW6432Node\CLSID",
];
pub fn all_windows_persistence_paths() -> impl Iterator<Item = &'static str> {
WINDOWS_RUN_KEYS
.iter()
.chain(IFEO_PATHS.iter())
.chain(APPINIT_PATHS.iter())
.chain(SESSION_MANAGER_PATHS.iter())
.chain(ACTIVE_SETUP_PATHS.iter())
.chain(SCREENSAVER_PATHS.iter())
.chain(WINLOGON_PATHS.iter())
.chain(COM_HIJACK_PATHS.iter())
.copied()
}
pub fn is_persistence_path(path: &str) -> bool {
let lower = path.to_ascii_lowercase();
all_windows_persistence_paths().any(|entry| lower.contains(&entry.to_ascii_lowercase()))
}
pub fn is_suspicious_ifeo_debugger(value: &str) -> bool {
if value.is_empty() {
return false;
}
let lower = value.to_ascii_lowercase();
let benign = ["ntsd", "windbg", "vsjitdebugger.exe"];
if benign.iter().any(|b| lower.contains(b)) {
return false;
}
lower.contains(r"\temp\") || lower.contains(r"\appdata\")
}
pub fn is_persistence_location(path: &str) -> bool {
let lower = path.to_ascii_lowercase();
let check = |entry: &&str| lower.contains(&entry.to_ascii_lowercase());
WINDOWS_RUN_KEYS.iter().any(check)
|| LINUX_PERSISTENCE_PATHS.iter().any(check)
|| MACOS_PERSISTENCE_PATHS.iter().any(check)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn windows_run_keys_contains_run() {
assert!(WINDOWS_RUN_KEYS.contains(&r"Software\Microsoft\Windows\CurrentVersion\Run"));
}
#[test]
fn windows_run_keys_contains_services() {
assert!(WINDOWS_RUN_KEYS.contains(&r"SYSTEM\CurrentControlSet\Services"));
}
#[test]
fn linux_persistence_contains_cron_d() {
assert!(LINUX_PERSISTENCE_PATHS.contains(&"/etc/cron.d"));
}
#[test]
fn linux_persistence_contains_ld_so_preload() {
assert!(LINUX_PERSISTENCE_PATHS.contains(&"/etc/ld.so.preload"));
}
#[test]
fn macos_persistence_contains_launch_agents() {
assert!(MACOS_PERSISTENCE_PATHS.contains(&"/Library/LaunchAgents"));
}
#[test]
fn macos_persistence_contains_launch_daemons() {
assert!(MACOS_PERSISTENCE_PATHS.contains(&"/Library/LaunchDaemons"));
}
#[test]
fn detects_windows_run_key_path() {
assert!(is_persistence_location(
r"HKCU\Software\Microsoft\Windows\CurrentVersion\Run"
));
}
#[test]
fn detects_linux_cron_path() {
assert!(is_persistence_location("/etc/cron.daily/malware"));
}
#[test]
fn detects_macos_launch_agents() {
assert!(is_persistence_location(
"/Library/LaunchAgents/com.evil.plist"
));
}
#[test]
fn detects_ld_so_preload() {
assert!(is_persistence_location("/etc/ld.so.preload"));
}
#[test]
fn does_not_flag_random_path() {
assert!(!is_persistence_location("/usr/bin/ls"));
}
#[test]
fn empty_string_not_persistence() {
assert!(!is_persistence_location(""));
}
#[test]
fn ifeo_paths_contains_ifeo_key() {
assert!(IFEO_PATHS.contains(
&r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options"
));
}
#[test]
fn appinit_paths_contains_windows_key() {
assert!(APPINIT_PATHS.contains(&r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows"));
}
#[test]
fn session_manager_paths_contains_boot_execute() {
assert!(SESSION_MANAGER_PATHS
.contains(&r"SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute"));
}
#[test]
fn all_windows_persistence_paths_contains_run_keys() {
assert!(all_windows_persistence_paths()
.any(|p| p == r"Software\Microsoft\Windows\CurrentVersion\Run"));
}
#[test]
fn is_persistence_path_run_key_matches() {
assert!(is_persistence_path(
r"Software\Microsoft\Windows\CurrentVersion\Run"
));
}
#[test]
fn is_persistence_path_ifeo_matches() {
assert!(is_persistence_path(
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe"
));
}
#[test]
fn is_persistence_path_case_insensitive() {
assert!(is_persistence_path(
r"software\microsoft\windows\currentversion\run"
));
}
#[test]
fn is_suspicious_ifeo_debugger_temp_path() {
assert!(is_suspicious_ifeo_debugger(
r"C:\Users\user\AppData\Local\Temp\evil.exe"
));
}
#[test]
fn is_suspicious_ifeo_debugger_windbg_benign() {
assert!(!is_suspicious_ifeo_debugger("windbg"));
}
}