Standardize import ordering and code formatting

This commit is contained in:
pandaadir05
2025-11-20 14:25:44 +02:00
parent 34007d11c1
commit e44f58e308
14 changed files with 823 additions and 546 deletions

View File

@@ -1,7 +1,7 @@
use crate::{GhostError, MemoryRegion, ProcessInfo, Result}; use crate::{MemoryRegion, ProcessInfo, Result};
#[cfg(windows)] #[cfg(windows)]
use crate::memory::{validate_pe_header, read_pe_header_info, PEHeaderValidation}; use crate::memory::{read_pe_header_info, validate_pe_header, PEHeaderValidation};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HollowingDetection { pub struct HollowingDetection {
@@ -15,12 +15,25 @@ pub struct HollowingDetection {
pub enum HollowingIndicator { pub enum HollowingIndicator {
UnmappedMainImage, UnmappedMainImage,
SuspiciousImageBase, SuspiciousImageBase,
MemoryLayoutAnomaly { expected_size: usize, actual_size: usize }, MemoryLayoutAnomaly {
expected_size: usize,
actual_size: usize,
},
MismatchedPEHeader, MismatchedPEHeader,
InvalidPEHeader { validation: String }, InvalidPEHeader {
CorruptedPEStructure { address: usize, reason: String }, validation: String,
UnusualEntryPoint { address: usize }, },
SuspiciousMemoryGaps { gap_count: usize, largest_gap: usize }, CorruptedPEStructure {
address: usize,
reason: String,
},
UnusualEntryPoint {
address: usize,
},
SuspiciousMemoryGaps {
gap_count: usize,
largest_gap: usize,
},
} }
impl std::fmt::Display for HollowingIndicator { impl std::fmt::Display for HollowingIndicator {
@@ -28,8 +41,15 @@ impl std::fmt::Display for HollowingIndicator {
match self { match self {
Self::UnmappedMainImage => write!(f, "Main executable image appears unmapped"), Self::UnmappedMainImage => write!(f, "Main executable image appears unmapped"),
Self::SuspiciousImageBase => write!(f, "Image base address is suspicious"), Self::SuspiciousImageBase => write!(f, "Image base address is suspicious"),
Self::MemoryLayoutAnomaly { expected_size, actual_size } => { Self::MemoryLayoutAnomaly {
write!(f, "Memory layout anomaly: expected {:#x}, found {:#x}", expected_size, actual_size) expected_size,
actual_size,
} => {
write!(
f,
"Memory layout anomaly: expected {:#x}, found {:#x}",
expected_size, actual_size
)
} }
Self::MismatchedPEHeader => write!(f, "PE header mismatch detected"), Self::MismatchedPEHeader => write!(f, "PE header mismatch detected"),
Self::InvalidPEHeader { validation } => { Self::InvalidPEHeader { validation } => {
@@ -41,14 +61,22 @@ impl std::fmt::Display for HollowingIndicator {
Self::UnusualEntryPoint { address } => { Self::UnusualEntryPoint { address } => {
write!(f, "Entry point at unusual location: {:#x}", address) write!(f, "Entry point at unusual location: {:#x}", address)
} }
Self::SuspiciousMemoryGaps { gap_count, largest_gap } => { Self::SuspiciousMemoryGaps {
write!(f, "{} memory gaps detected, largest: {:#x} bytes", gap_count, largest_gap) gap_count,
largest_gap,
} => {
write!(
f,
"{} memory gaps detected, largest: {:#x} bytes",
gap_count, largest_gap
)
} }
} }
} }
} }
/// Process hollowing detection engine /// Process hollowing detection engine
#[derive(Debug)]
pub struct HollowingDetector; pub struct HollowingDetector;
impl HollowingDetector { impl HollowingDetector {
@@ -147,7 +175,13 @@ impl HollowingDetector {
// Calculate total executable memory size // Calculate total executable memory size
let total_executable: usize = regions let total_executable: usize = regions
.iter() .iter()
.filter(|r| matches!(r.protection, crate::MemoryProtection::ReadExecute | crate::MemoryProtection::ReadWriteExecute)) .filter(|r| {
matches!(
r.protection,
crate::MemoryProtection::ReadExecute
| crate::MemoryProtection::ReadWriteExecute
)
})
.map(|r| r.size) .map(|r| r.size)
.sum(); .sum();
@@ -241,7 +275,11 @@ impl HollowingDetector {
} }
#[cfg(windows)] #[cfg(windows)]
fn validate_pe_headers(&self, pid: u32, regions: &[MemoryRegion]) -> Option<HollowingIndicator> { fn validate_pe_headers(
&self,
pid: u32,
regions: &[MemoryRegion],
) -> Option<HollowingIndicator> {
// Focus on main executable IMAGE regions // Focus on main executable IMAGE regions
let image_regions: Vec<_> = regions let image_regions: Vec<_> = regions
.iter() .iter()
@@ -251,44 +289,42 @@ impl HollowingDetector {
for region in image_regions { for region in image_regions {
match validate_pe_header(pid, region.base_address) { match validate_pe_header(pid, region.base_address) {
Ok(validation) => { Ok(validation) => match validation {
match validation { PEHeaderValidation::Valid => continue,
PEHeaderValidation::Valid => continue, PEHeaderValidation::InvalidDosSignature => {
PEHeaderValidation::InvalidDosSignature => { return Some(HollowingIndicator::InvalidPEHeader {
return Some(HollowingIndicator::InvalidPEHeader { validation: "Invalid DOS signature (not MZ)".to_string(),
validation: "Invalid DOS signature (not MZ)".to_string(), });
});
}
PEHeaderValidation::InvalidNtSignature => {
return Some(HollowingIndicator::InvalidPEHeader {
validation: "Invalid NT signature (not PE)".to_string(),
});
}
PEHeaderValidation::InvalidHeaderOffset => {
return Some(HollowingIndicator::InvalidPEHeader {
validation: "Invalid PE header offset".to_string(),
});
}
PEHeaderValidation::MismatchedImageBase => {
return Some(HollowingIndicator::CorruptedPEStructure {
address: region.base_address,
reason: "Image base mismatch - possible hollowing".to_string(),
});
}
PEHeaderValidation::SuspiciousEntryPoint => {
return Some(HollowingIndicator::InvalidPEHeader {
validation: "Suspicious entry point location".to_string(),
});
}
PEHeaderValidation::CorruptedHeader => {
return Some(HollowingIndicator::CorruptedPEStructure {
address: region.base_address,
reason: "Corrupted PE header structure".to_string(),
});
}
PEHeaderValidation::NotPE => continue,
} }
} PEHeaderValidation::InvalidNtSignature => {
return Some(HollowingIndicator::InvalidPEHeader {
validation: "Invalid NT signature (not PE)".to_string(),
});
}
PEHeaderValidation::InvalidHeaderOffset => {
return Some(HollowingIndicator::InvalidPEHeader {
validation: "Invalid PE header offset".to_string(),
});
}
PEHeaderValidation::MismatchedImageBase => {
return Some(HollowingIndicator::CorruptedPEStructure {
address: region.base_address,
reason: "Image base mismatch - possible hollowing".to_string(),
});
}
PEHeaderValidation::SuspiciousEntryPoint => {
return Some(HollowingIndicator::InvalidPEHeader {
validation: "Suspicious entry point location".to_string(),
});
}
PEHeaderValidation::CorruptedHeader => {
return Some(HollowingIndicator::CorruptedPEStructure {
address: region.base_address,
reason: "Corrupted PE header structure".to_string(),
});
}
PEHeaderValidation::NotPE => continue,
},
Err(_) => { Err(_) => {
// Could not read memory - might be suspicious but don't report // Could not read memory - might be suspicious but don't report
continue; continue;
@@ -300,7 +336,11 @@ impl HollowingDetector {
} }
#[cfg(not(windows))] #[cfg(not(windows))]
fn validate_pe_headers(&self, _pid: u32, _regions: &[MemoryRegion]) -> Option<HollowingIndicator> { fn validate_pe_headers(
&self,
_pid: u32,
_regions: &[MemoryRegion],
) -> Option<HollowingIndicator> {
// PE validation is Windows-specific // PE validation is Windows-specific
None None
} }
@@ -317,8 +357,11 @@ impl HollowingDetector {
let executable_regions: Vec<_> = regions let executable_regions: Vec<_> = regions
.iter() .iter()
.filter(|r| { .filter(|r| {
matches!(r.protection, crate::MemoryProtection::ReadExecute | crate::MemoryProtection::ReadWriteExecute) matches!(
&& r.region_type == "PRIVATE" r.protection,
crate::MemoryProtection::ReadExecute
| crate::MemoryProtection::ReadWriteExecute
) && r.region_type == "PRIVATE"
}) })
.collect(); .collect();

View File

@@ -4,9 +4,7 @@
//! used for process injection (T1055.003, T1055.012). //! used for process injection (T1055.003, T1055.012).
//! On Linux, it detects LD_PRELOAD and LD_LIBRARY_PATH based injection. //! On Linux, it detects LD_PRELOAD and LD_LIBRARY_PATH based injection.
use crate::{GhostError, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Type of hook detected. /// Type of hook detected.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
@@ -78,18 +76,18 @@ mod platform {
use std::collections::HashMap; use std::collections::HashMap;
use windows::Win32::Foundation::CloseHandle; use windows::Win32::Foundation::CloseHandle;
use windows::Win32::System::Diagnostics::Debug::ReadProcessMemory; use windows::Win32::System::Diagnostics::Debug::ReadProcessMemory;
use windows::Win32::System::LibraryLoader::{ use windows::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress, LoadLibraryW};
GetModuleHandleW, GetProcAddress, LoadLibraryW,
};
use windows::Win32::System::ProcessStatus::{ use windows::Win32::System::ProcessStatus::{
EnumProcessModulesEx, GetModuleBaseNameW, GetModuleInformation, LIST_MODULES_ALL, EnumProcessModulesEx, GetModuleBaseNameW, GetModuleInformation, LIST_MODULES_ALL,
MODULEINFO, MODULEINFO,
}; };
use windows::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ}; use windows::Win32::System::Threading::{
OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ,
};
use windows::Win32::UI::WindowsAndMessaging::{ use windows::Win32::UI::WindowsAndMessaging::{
WH_CALLWNDPROC, WH_CALLWNDPROCRET, WH_CBT, WH_DEBUG, WH_FOREGROUNDIDLE, WH_GETMESSAGE, WH_CALLWNDPROC, WH_CALLWNDPROCRET, WH_CBT, WH_DEBUG, WH_FOREGROUNDIDLE, WH_GETMESSAGE,
WH_JOURNALPLAYBACK, WH_JOURNALRECORD, WH_KEYBOARD, WH_KEYBOARD_LL, WH_MOUSE, WH_JOURNALPLAYBACK, WH_JOURNALRECORD, WH_KEYBOARD, WH_KEYBOARD_LL, WH_MOUSE, WH_MOUSE_LL,
WH_MOUSE_LL, WH_MSGFILTER, WH_SHELL, WH_SYSMSGFILTER, WH_MSGFILTER, WH_SHELL, WH_SYSMSGFILTER,
}; };
/// Critical APIs commonly hooked for injection. /// Critical APIs commonly hooked for injection.
@@ -151,10 +149,14 @@ mod platform {
let mut hooks = Vec::new(); let mut hooks = Vec::new();
unsafe { unsafe {
let handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, target_pid) let handle = OpenProcess(
.map_err(|e| GhostError::Process { PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
message: format!("Failed to open process: {}", e), false,
})?; target_pid,
)
.map_err(|e| GhostError::Process {
message: format!("Failed to open process: {}", e),
})?;
// Get loaded modules in target process // Get loaded modules in target process
let mut modules = [windows::Win32::Foundation::HMODULE::default(); 1024]; let mut modules = [windows::Win32::Foundation::HMODULE::default(); 1024];
@@ -407,11 +409,10 @@ mod platform {
/// Detect LD_PRELOAD environment variable in process. /// Detect LD_PRELOAD environment variable in process.
fn detect_ld_preload(pid: u32) -> Result<Vec<HookInfo>> { fn detect_ld_preload(pid: u32) -> Result<Vec<HookInfo>> {
let environ_path = format!("/proc/{}/environ", pid); let environ_path = format!("/proc/{}/environ", pid);
let environ_content = fs::read_to_string(&environ_path).map_err(|e| { let environ_content =
GhostError::Process { fs::read_to_string(&environ_path).map_err(|e| GhostError::Process {
message: format!("Failed to read process environment: {}", e), message: format!("Failed to read process environment: {}", e),
} })?;
})?;
let mut hooks = Vec::new(); let mut hooks = Vec::new();
@@ -442,11 +443,10 @@ mod platform {
/// Detect LD_LIBRARY_PATH environment variable manipulation. /// Detect LD_LIBRARY_PATH environment variable manipulation.
fn detect_ld_library_path(pid: u32) -> Result<Vec<HookInfo>> { fn detect_ld_library_path(pid: u32) -> Result<Vec<HookInfo>> {
let environ_path = format!("/proc/{}/environ", pid); let environ_path = format!("/proc/{}/environ", pid);
let environ_content = fs::read_to_string(&environ_path).map_err(|e| { let environ_content =
GhostError::Process { fs::read_to_string(&environ_path).map_err(|e| GhostError::Process {
message: format!("Failed to read process environment: {}", e), message: format!("Failed to read process environment: {}", e),
} })?;
})?;
let mut hooks = Vec::new(); let mut hooks = Vec::new();
@@ -476,25 +476,18 @@ mod platform {
/// Check if a library path is suspicious. /// Check if a library path is suspicious.
fn is_suspicious_library_path(path: &str) -> bool { fn is_suspicious_library_path(path: &str) -> bool {
// Suspicious patterns // Suspicious patterns
let suspicious_patterns = [ let suspicious_patterns = ["/tmp/", "/dev/shm/", "/var/tmp/", ".", "..", "/home/"];
"/tmp/",
"/dev/shm/",
"/var/tmp/",
".",
"..",
"/home/",
];
suspicious_patterns.iter().any(|&pattern| path.contains(pattern)) suspicious_patterns
.iter()
.any(|&pattern| path.contains(pattern))
} }
/// Detect ptrace attachment (debugging/injection). /// Detect ptrace attachment (debugging/injection).
fn detect_ptrace_attachment(pid: u32) -> Result<bool> { fn detect_ptrace_attachment(pid: u32) -> Result<bool> {
let status_path = format!("/proc/{}/status", pid); let status_path = format!("/proc/{}/status", pid);
let status_content = fs::read_to_string(&status_path).map_err(|e| { let status_content = fs::read_to_string(&status_path).map_err(|e| GhostError::Process {
GhostError::Process { message: format!("Failed to read process status: {}", e),
message: format!("Failed to read process status: {}", e),
}
})?; })?;
// Look for TracerPid field // Look for TracerPid field
@@ -519,10 +512,8 @@ mod platform {
/// Detect suspicious loaded libraries. /// Detect suspicious loaded libraries.
fn detect_suspicious_libraries(pid: u32) -> Result<Vec<HookInfo>> { fn detect_suspicious_libraries(pid: u32) -> Result<Vec<HookInfo>> {
let maps_path = format!("/proc/{}/maps", pid); let maps_path = format!("/proc/{}/maps", pid);
let maps_content = fs::read_to_string(&maps_path).map_err(|e| { let maps_content = fs::read_to_string(&maps_path).map_err(|e| GhostError::Process {
GhostError::Process { message: format!("Failed to read process maps: {}", e),
message: format!("Failed to read process maps: {}", e),
}
})?; })?;
let mut hooks = Vec::new(); let mut hooks = Vec::new();
@@ -563,29 +554,23 @@ mod platform {
/// Check if a library path is suspicious. /// Check if a library path is suspicious.
fn is_suspicious_library(path: &str) -> bool { fn is_suspicious_library(path: &str) -> bool {
// Libraries in these locations are often used for injection // Libraries in these locations are often used for injection
let suspicious_locations = [ let suspicious_locations = ["/tmp/", "/dev/shm/", "/var/tmp/", "/home/"];
"/tmp/",
"/dev/shm/",
"/var/tmp/",
"/home/",
];
// Check if library is in a suspicious location // Check if library is in a suspicious location
if suspicious_locations.iter().any(|&loc| path.starts_with(loc)) { if suspicious_locations
.iter()
.any(|&loc| path.starts_with(loc))
{
return true; return true;
} }
// Check for libraries with suspicious names // Check for libraries with suspicious names
let suspicious_names = [ let suspicious_names = ["inject", "hook", "cheat", "hack", "rootkit"];
"inject",
"hook",
"cheat",
"hack",
"rootkit",
];
let path_lower = path.to_lowercase(); let path_lower = path.to_lowercase();
suspicious_names.iter().any(|&name| path_lower.contains(name)) suspicious_names
.iter()
.any(|&name| path_lower.contains(name))
} }
pub fn get_hook_type_name(_hook_type: u32) -> &'static str { pub fn get_hook_type_name(_hook_type: u32) -> &'static str {
@@ -596,7 +581,7 @@ mod platform {
#[cfg(not(any(windows, target_os = "linux")))] #[cfg(not(any(windows, target_os = "linux")))]
mod platform { mod platform {
use super::HookDetectionResult; use super::HookDetectionResult;
use crate::{GhostError, Result}; use crate::Result;
pub fn detect_hook_injection(_target_pid: u32) -> Result<HookDetectionResult> { pub fn detect_hook_injection(_target_pid: u32) -> Result<HookDetectionResult> {
// Hook detection is not implemented for this platform // Hook detection is not implemented for this platform

View File

@@ -73,42 +73,42 @@ pub mod yara_engine;
pub use anomaly::{AnomalyDetector, AnomalyScore, ProcessFeatures}; pub use anomaly::{AnomalyDetector, AnomalyScore, ProcessFeatures};
pub use behavioral_ml::{ pub use behavioral_ml::{
AdvancedBehavioralML, BehavioralAnalysisResult, PredictedTechnique, BehavioralAnomaly, AdvancedBehavioralML, BehavioralAnalysisResult, BehavioralAnomaly, ModelConsensus,
ModelConsensus, TemporalAnalysis, RiskLevel PredictedTechnique, RiskLevel, TemporalAnalysis,
}; };
pub use config::{DetectionConfig, ProcessFilter}; pub use config::{DetectionConfig, ProcessFilter};
pub use detection::{DetectionEngine, DetectionResult, ThreatLevel}; pub use detection::{DetectionEngine, DetectionResult, ThreatLevel};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub use ebpf::{EbpfDetector, EbpfEvent, EbpfError, EbpfStatistics}; pub use ebpf::{EbpfDetector, EbpfError, EbpfEvent, EbpfStatistics};
pub use error::{GhostError, Result}; pub use error::{GhostError, Result};
pub use evasion::{ pub use evasion::{
EvasionDetector, EvasionResult, EvasionTechnique, EvasionSeverity, BehaviorAnalyzer, EnvironmentChecker, EvasionDetector, EvasionResult, EvasionSeverity,
TimingAnalyzer, EnvironmentChecker, BehaviorAnalyzer, ObfuscationDetector EvasionTechnique, ObfuscationDetector, TimingAnalyzer,
}; };
pub use hollowing::{HollowingDetection, HollowingDetector, HollowingIndicator}; pub use hollowing::{HollowingDetection, HollowingDetector, HollowingIndicator};
pub use hooks::{detect_hook_injection, HookDetectionResult, HookInfo}; pub use hooks::{detect_hook_injection, HookDetectionResult, HookInfo};
pub use live_feeds::{LiveThreatFeeds, ThreatFeed, FeedType}; pub use live_feeds::{FeedType, LiveThreatFeeds, ThreatFeed};
pub use memory::{MemoryProtection, MemoryRegion}; pub use memory::{MemoryProtection, MemoryRegion};
pub use mitre_attack::{ pub use mitre_attack::{
MitreAttackEngine, MitreAnalysisResult, AttackTechnique, AttackTactic, ThreatActor, AttackTactic, AttackTechnique, DetectedTechnique, KillChainAnalysis, MitreAnalysisResult,
DetectedTechnique, TacticCoverage, ThreatActorMatch, KillChainAnalysis, RiskAssessment MitreAttackEngine, RiskAssessment, TacticCoverage, ThreatActor, ThreatActorMatch,
}; };
pub use ml_cloud::{CloudMLEngine, InferenceResult, MLModel, ThreatPrediction, ThreatSeverity}; pub use ml_cloud::{CloudMLEngine, InferenceResult, MLModel, ThreatPrediction, ThreatSeverity};
pub use neural_memory::{ pub use neural_memory::{
NeuralMemoryAnalyzer, NeuralAnalysisResult, DetectedPattern, DetectedEvasion, DetectedEvasion, DetectedPattern, EvasionCategory, MemoryAnomaly, NeuralAnalysisResult,
PolymorphicIndicator, MemoryAnomaly, NeuralInsights, PatternType, EvasionCategory NeuralInsights, NeuralMemoryAnalyzer, PatternType, PolymorphicIndicator,
}; };
pub use process::ProcessInfo; pub use process::ProcessInfo;
pub use shellcode::{ShellcodeDetection, ShellcodeDetector}; pub use shellcode::{ShellcodeDetection, ShellcodeDetector};
pub use streaming::{ pub use streaming::{
EventStreamingSystem, EventChannel, StreamingEvent, EventType, EventSeverity, Alert, AlertManager, AlertRule, CorrelationEngine, EventChannel, EventSeverity,
AlertManager, Alert, AlertRule, CorrelationEngine, NotificationSystem EventStreamingSystem, EventType, NotificationSystem, StreamingEvent,
}; };
pub use thread::ThreadInfo; pub use thread::ThreadInfo;
pub use threat_intel::{ pub use threat_intel::{
ThreatIntelligence, ThreatContext, IndicatorOfCompromise, Campaign, IndicatorOfCompromise, IocType, SophisticationLevel, ThreatActor as ThreatIntelActor,
ThreatActor as ThreatIntelActor, Campaign, IocType, SophisticationLevel ThreatContext, ThreatIntelligence,
}; };
pub use yara_engine::{ pub use yara_engine::{
DynamicYaraEngine, YaraRuleSource, YaraScanResult, RuleMatch, ThreatLevel as YaraThreatLevel DynamicYaraEngine, RuleMatch, ThreatLevel as YaraThreatLevel, YaraRuleSource, YaraScanResult,
}; };

View File

@@ -1,7 +1,7 @@
use crate::GhostError; use crate::GhostError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, Duration}; use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LiveThreatFeeds { pub struct LiveThreatFeeds {

View File

@@ -1,7 +1,7 @@
use crate::{ProcessInfo, MemoryRegion, ThreadInfo, GhostError}; use crate::{GhostError, MemoryRegion, ProcessInfo, ThreadInfo};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, Duration}; use std::time::{Duration, SystemTime};
/// MITRE ATT&CK Framework Integration Engine /// MITRE ATT&CK Framework Integration Engine
/// Provides comprehensive technique mapping, threat actor profiling, and tactical analysis /// Provides comprehensive technique mapping, threat actor profiling, and tactical analysis
@@ -74,7 +74,7 @@ pub enum Platform {
Linux, Linux,
MacOS, MacOS,
Android, Android,
iOS, IOS,
Cloud, Cloud,
Network, Network,
Container, Container,
@@ -344,7 +344,7 @@ pub enum EvidenceType {
NetworkActivity, NetworkActivity,
FileSystem, FileSystem,
Registry, Registry,
API_Calls, ApiCalls,
Timing, Timing,
} }
@@ -370,114 +370,125 @@ impl MitreAttackEngine {
fn initialize_techniques(&mut self) -> Result<(), GhostError> { fn initialize_techniques(&mut self) -> Result<(), GhostError> {
// Process Injection (T1055) // Process Injection (T1055)
self.techniques.insert("T1055".to_string(), AttackTechnique { self.techniques.insert(
id: "T1055".to_string(), "T1055".to_string(),
name: "Process Injection".to_string(), AttackTechnique {
description: "Adversaries may inject code into processes to evade process-based defenses".to_string(), id: "T1055".to_string(),
tactics: vec!["TA0004".to_string(), "TA0005".to_string()], // Defense Evasion, Privilege Escalation name: "Process Injection".to_string(),
platforms: vec![Platform::Windows, Platform::Linux, Platform::MacOS], description:
data_sources: vec![ "Adversaries may inject code into processes to evade process-based defenses"
DataSource { .to_string(),
tactics: vec!["TA0004".to_string(), "TA0005".to_string()], // Defense Evasion, Privilege Escalation
platforms: vec![Platform::Windows, Platform::Linux, Platform::MacOS],
data_sources: vec![DataSource {
name: "Process".to_string(), name: "Process".to_string(),
data_component: "Process Access".to_string(), data_component: "Process Access".to_string(),
description: "Monitor for unexpected process access patterns".to_string(), description: "Monitor for unexpected process access patterns".to_string(),
}, }],
], detection_methods: vec![DetectionMethod {
detection_methods: vec![
DetectionMethod {
method_type: DetectionType::BehavioralAnalysis, method_type: DetectionType::BehavioralAnalysis,
description: "Monitor for unusual cross-process activity".to_string(), description: "Monitor for unusual cross-process activity".to_string(),
effectiveness: 0.85, effectiveness: 0.85,
false_positive_rate: 0.1, false_positive_rate: 0.1,
}, }],
], mitigations: vec![Mitigation {
mitigations: vec![
Mitigation {
id: "M1040".to_string(), id: "M1040".to_string(),
name: "Behavior Prevention on Endpoint".to_string(), name: "Behavior Prevention on Endpoint".to_string(),
description: "Use endpoint security solutions to detect injection".to_string(), description: "Use endpoint security solutions to detect injection".to_string(),
implementation_difficulty: DifficultyLevel::Medium, implementation_difficulty: DifficultyLevel::Medium,
effectiveness: 0.8, effectiveness: 0.8,
}, }],
], sub_techniques: vec!["T1055.001".to_string(), "T1055.002".to_string()],
sub_techniques: vec!["T1055.001".to_string(), "T1055.002".to_string()], kill_chain_phases: vec![
kill_chain_phases: vec![KillChainPhase::Installation, KillChainPhase::ActionsOnObjectives], KillChainPhase::Installation,
threat_actors: vec!["APT1".to_string(), "APT29".to_string()], KillChainPhase::ActionsOnObjectives,
references: vec![ ],
Reference { threat_actors: vec!["APT1".to_string(), "APT29".to_string()],
references: vec![Reference {
source: "MITRE ATT&CK".to_string(), source: "MITRE ATT&CK".to_string(),
url: "https://attack.mitre.org/techniques/T1055/".to_string(), url: "https://attack.mitre.org/techniques/T1055/".to_string(),
description: "Process Injection".to_string(), description: "Process Injection".to_string(),
}, }],
], },
}); );
// Process Hollowing (T1055.012) // Process Hollowing (T1055.012)
self.techniques.insert("T1055.012".to_string(), AttackTechnique { self.techniques.insert(
id: "T1055.012".to_string(), "T1055.012".to_string(),
name: "Process Hollowing".to_string(), AttackTechnique {
description: "Adversaries may inject malicious code into suspended and hollowed processes".to_string(), id: "T1055.012".to_string(),
tactics: vec!["TA0004".to_string(), "TA0005".to_string()], name: "Process Hollowing".to_string(),
platforms: vec![Platform::Windows], description:
data_sources: vec![ "Adversaries may inject malicious code into suspended and hollowed processes"
DataSource { .to_string(),
tactics: vec!["TA0004".to_string(), "TA0005".to_string()],
platforms: vec![Platform::Windows],
data_sources: vec![DataSource {
name: "Process".to_string(), name: "Process".to_string(),
data_component: "Process Creation".to_string(), data_component: "Process Creation".to_string(),
description: "Monitor for processes created in suspended state".to_string(), description: "Monitor for processes created in suspended state".to_string(),
}, }],
], detection_methods: vec![DetectionMethod {
detection_methods: vec![
DetectionMethod {
method_type: DetectionType::EndpointDetection, method_type: DetectionType::EndpointDetection,
description: "Detect hollowing through memory analysis".to_string(), description: "Detect hollowing through memory analysis".to_string(),
effectiveness: 0.9, effectiveness: 0.9,
false_positive_rate: 0.05, false_positive_rate: 0.05,
}, }],
], mitigations: vec![],
mitigations: vec![], sub_techniques: vec![],
sub_techniques: vec![], kill_chain_phases: vec![KillChainPhase::Installation],
kill_chain_phases: vec![KillChainPhase::Installation], threat_actors: vec!["APT29".to_string(), "Lazarus Group".to_string()],
threat_actors: vec!["APT29".to_string(), "Lazarus Group".to_string()], references: vec![],
references: vec![], },
}); );
Ok(()) Ok(())
} }
fn initialize_tactics(&mut self) -> Result<(), GhostError> { fn initialize_tactics(&mut self) -> Result<(), GhostError> {
self.tactics.insert("TA0004".to_string(), AttackTactic { self.tactics.insert(
id: "TA0004".to_string(), "TA0004".to_string(),
name: "Defense Evasion".to_string(), AttackTactic {
description: "Techniques that adversaries use to avoid detection".to_string(), id: "TA0004".to_string(),
techniques: vec!["T1055".to_string()], name: "Defense Evasion".to_string(),
matrix_position: 4, description: "Techniques that adversaries use to avoid detection".to_string(),
}); techniques: vec!["T1055".to_string()],
matrix_position: 4,
},
);
self.tactics.insert("TA0005".to_string(), AttackTactic { self.tactics.insert(
id: "TA0005".to_string(), "TA0005".to_string(),
name: "Privilege Escalation".to_string(), AttackTactic {
description: "Techniques that adversaries use to gain higher-level permissions".to_string(), id: "TA0005".to_string(),
techniques: vec!["T1055".to_string()], name: "Privilege Escalation".to_string(),
matrix_position: 5, description: "Techniques that adversaries use to gain higher-level permissions"
}); .to_string(),
techniques: vec!["T1055".to_string()],
matrix_position: 5,
},
);
Ok(()) Ok(())
} }
fn initialize_threat_actors(&mut self) -> Result<(), GhostError> { fn initialize_threat_actors(&mut self) -> Result<(), GhostError> {
self.threat_actors.insert("APT29".to_string(), ThreatActor { self.threat_actors.insert(
id: "G0016".to_string(), "APT29".to_string(),
name: "APT29".to_string(), ThreatActor {
aliases: vec!["Cozy Bear".to_string(), "The Dukes".to_string()], id: "G0016".to_string(),
description: "Russian state-sponsored threat group".to_string(), name: "APT29".to_string(),
country: Some("Russia".to_string()), aliases: vec!["Cozy Bear".to_string(), "The Dukes".to_string()],
motivation: vec![Motivation::Espionage], description: "Russian state-sponsored threat group".to_string(),
sophistication: SophisticationLevel::StateSponsored, country: Some("Russia".to_string()),
techniques: vec!["T1055".to_string(), "T1055.012".to_string()], motivation: vec![Motivation::Espionage],
campaigns: vec!["Operation Ghost".to_string()], sophistication: SophisticationLevel::StateSponsored,
first_seen: SystemTime::now() - Duration::from_secs(365 * 24 * 3600 * 10), // 10 years ago techniques: vec!["T1055".to_string(), "T1055.012".to_string()],
last_activity: SystemTime::now() - Duration::from_secs(30 * 24 * 3600), // 30 days ago campaigns: vec!["Operation Ghost".to_string()],
}); first_seen: SystemTime::now() - Duration::from_secs(365 * 24 * 3600 * 10), // 10 years ago
last_activity: SystemTime::now() - Duration::from_secs(30 * 24 * 3600), // 30 days ago
},
);
Ok(()) Ok(())
} }
@@ -501,7 +512,9 @@ impl MitreAttackEngine {
memory_regions: &[MemoryRegion], memory_regions: &[MemoryRegion],
threads: &[ThreadInfo], threads: &[ThreadInfo],
) -> Result<MitreAnalysisResult, GhostError> { ) -> Result<MitreAnalysisResult, GhostError> {
let detected_techniques = self.detect_techniques(process, memory_regions, threads).await?; let detected_techniques = self
.detect_techniques(process, memory_regions, threads)
.await?;
let tactics_coverage = self.analyze_tactics_coverage(&detected_techniques)?; let tactics_coverage = self.analyze_tactics_coverage(&detected_techniques)?;
let threat_actor_matches = self.match_threat_actors(&detected_techniques)?; let threat_actor_matches = self.match_threat_actors(&detected_techniques)?;
let campaign_indicators = self.analyze_campaign_indicators(&detected_techniques)?; let campaign_indicators = self.analyze_campaign_indicators(&detected_techniques)?;
@@ -529,8 +542,13 @@ impl MitreAttackEngine {
let mut detected = Vec::new(); let mut detected = Vec::new();
// Check for Process Injection indicators // Check for Process Injection indicators
let rwx_regions = memory_regions.iter() let rwx_regions = memory_regions
.filter(|r| r.protection.is_readable() && r.protection.is_writable() && r.protection.is_executable()) .iter()
.filter(|r| {
r.protection.is_readable()
&& r.protection.is_writable()
&& r.protection.is_executable()
})
.count(); .count();
if rwx_regions > 0 { if rwx_regions > 0 {
@@ -538,14 +556,12 @@ impl MitreAttackEngine {
detected.push(DetectedTechnique { detected.push(DetectedTechnique {
technique: technique.clone(), technique: technique.clone(),
confidence: 0.8, confidence: 0.8,
evidence: vec![ evidence: vec![Evidence {
Evidence { evidence_type: EvidenceType::MemoryPattern,
evidence_type: EvidenceType::MemoryPattern, description: format!("Found {} RWX memory regions", rwx_regions),
description: format!("Found {} RWX memory regions", rwx_regions), confidence: 0.9,
confidence: 0.9, source: "Memory Analysis".to_string(),
source: "Memory Analysis".to_string(), }],
},
],
sub_technique_id: None, sub_technique_id: None,
detection_timestamp: SystemTime::now(), detection_timestamp: SystemTime::now(),
}); });
@@ -558,14 +574,13 @@ impl MitreAttackEngine {
detected.push(DetectedTechnique { detected.push(DetectedTechnique {
technique: technique.clone(), technique: technique.clone(),
confidence: 0.7, confidence: 0.7,
evidence: vec![ evidence: vec![Evidence {
Evidence { evidence_type: EvidenceType::ProcessBehavior,
evidence_type: EvidenceType::ProcessBehavior, description: "Suspicious memory layout consistent with hollowing"
description: "Suspicious memory layout consistent with hollowing".to_string(), .to_string(),
confidence: 0.7, confidence: 0.7,
source: "Process Analysis".to_string(), source: "Process Analysis".to_string(),
}, }],
],
sub_technique_id: Some("T1055.012".to_string()), sub_technique_id: Some("T1055.012".to_string()),
detection_timestamp: SystemTime::now(), detection_timestamp: SystemTime::now(),
}); });
@@ -575,11 +590,15 @@ impl MitreAttackEngine {
Ok(detected) Ok(detected)
} }
fn analyze_tactics_coverage(&self, detected_techniques: &[DetectedTechnique]) -> Result<Vec<TacticCoverage>, GhostError> { fn analyze_tactics_coverage(
&self,
detected_techniques: &[DetectedTechnique],
) -> Result<Vec<TacticCoverage>, GhostError> {
let mut coverage = Vec::new(); let mut coverage = Vec::new();
for tactic in self.tactics.values() { for tactic in self.tactics.values() {
let techniques_detected = detected_techniques.iter() let techniques_detected = detected_techniques
.iter()
.filter(|dt| dt.technique.tactics.contains(&tactic.id)) .filter(|dt| dt.technique.tactics.contains(&tactic.id))
.count(); .count();
@@ -601,17 +620,22 @@ impl MitreAttackEngine {
Ok(coverage) Ok(coverage)
} }
fn match_threat_actors(&self, detected_techniques: &[DetectedTechnique]) -> Result<Vec<ThreatActorMatch>, GhostError> { fn match_threat_actors(
&self,
detected_techniques: &[DetectedTechnique],
) -> Result<Vec<ThreatActorMatch>, GhostError> {
let mut matches = Vec::new(); let mut matches = Vec::new();
for actor in self.threat_actors.values() { for actor in self.threat_actors.values() {
let matching_techniques: Vec<String> = detected_techniques.iter() let matching_techniques: Vec<String> = detected_techniques
.iter()
.filter(|dt| actor.techniques.contains(&dt.technique.id)) .filter(|dt| actor.techniques.contains(&dt.technique.id))
.map(|dt| dt.technique.id.clone()) .map(|dt| dt.technique.id.clone())
.collect(); .collect();
if !matching_techniques.is_empty() { if !matching_techniques.is_empty() {
let match_confidence = matching_techniques.len() as f32 / actor.techniques.len() as f32; let match_confidence =
matching_techniques.len() as f32 / actor.techniques.len() as f32;
matches.push(ThreatActorMatch { matches.push(ThreatActorMatch {
threat_actor: actor.clone(), threat_actor: actor.clone(),
@@ -625,11 +649,17 @@ impl MitreAttackEngine {
Ok(matches) Ok(matches)
} }
fn analyze_campaign_indicators(&self, _detected_techniques: &[DetectedTechnique]) -> Result<Vec<CampaignIndicator>, GhostError> { fn analyze_campaign_indicators(
&self,
_detected_techniques: &[DetectedTechnique],
) -> Result<Vec<CampaignIndicator>, GhostError> {
Ok(Vec::new()) // Simplified implementation Ok(Vec::new()) // Simplified implementation
} }
fn analyze_kill_chain(&self, detected_techniques: &[DetectedTechnique]) -> Result<KillChainAnalysis, GhostError> { fn analyze_kill_chain(
&self,
detected_techniques: &[DetectedTechnique],
) -> Result<KillChainAnalysis, GhostError> {
let mut completed_phases = Vec::new(); let mut completed_phases = Vec::new();
for technique in detected_techniques { for technique in detected_techniques {
@@ -651,10 +681,17 @@ impl MitreAttackEngine {
}) })
} }
fn assess_risk(&self, detected_techniques: &[DetectedTechnique]) -> Result<RiskAssessment, GhostError> { fn assess_risk(
&self,
detected_techniques: &[DetectedTechnique],
) -> Result<RiskAssessment, GhostError> {
let technique_count = detected_techniques.len() as f32; let technique_count = detected_techniques.len() as f32;
let avg_confidence = if !detected_techniques.is_empty() { let avg_confidence = if !detected_techniques.is_empty() {
detected_techniques.iter().map(|dt| dt.confidence).sum::<f32>() / technique_count detected_techniques
.iter()
.map(|dt| dt.confidence)
.sum::<f32>()
/ technique_count
} else { } else {
0.0 0.0
}; };
@@ -676,17 +713,18 @@ impl MitreAttackEngine {
attack_likelihood: avg_confidence, attack_likelihood: avg_confidence,
potential_impact: 0.8, // Simulated potential_impact: 0.8, // Simulated
urgency_level, urgency_level,
risk_factors: vec![ risk_factors: vec![RiskFactor {
RiskFactor { factor_name: "Multiple Techniques Detected".to_string(),
factor_name: "Multiple Techniques Detected".to_string(), risk_contribution: 0.6,
risk_contribution: 0.6, description: "Multiple attack techniques increase overall risk".to_string(),
description: "Multiple attack techniques increase overall risk".to_string(), }],
},
],
}) })
} }
fn recommend_mitigations(&self, detected_techniques: &[DetectedTechnique]) -> Result<Vec<MitigationRecommendation>, GhostError> { fn recommend_mitigations(
&self,
detected_techniques: &[DetectedTechnique],
) -> Result<Vec<MitigationRecommendation>, GhostError> {
let mut recommendations = Vec::new(); let mut recommendations = Vec::new();
for technique in detected_techniques { for technique in detected_techniques {
@@ -719,6 +757,10 @@ impl MitreAttackEngine {
} }
pub fn get_framework_stats(&self) -> (usize, usize, usize) { pub fn get_framework_stats(&self) -> (usize, usize, usize) {
(self.techniques.len(), self.tactics.len(), self.threat_actors.len()) (
self.techniques.len(),
self.tactics.len(),
self.threat_actors.len(),
)
} }
} }

View File

@@ -1,7 +1,7 @@
use crate::{ProcessInfo, MemoryRegion, GhostError}; use crate::{GhostError, MemoryRegion, ProcessInfo};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, Duration}; use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudMLEngine { pub struct CloudMLEngine {
@@ -112,7 +112,10 @@ impl CloudMLEngine {
// Simulate ML inference // Simulate ML inference
let start_time = SystemTime::now(); let start_time = SystemTime::now();
let threat_level = if memory_regions.iter().any(|r| r.protection.is_executable() && r.protection.is_writable()) { let threat_level = if memory_regions
.iter()
.any(|r| r.protection.is_executable() && r.protection.is_writable())
{
ThreatSeverity::High ThreatSeverity::High
} else if memory_regions.len() > 50 { } else if memory_regions.len() > 50 {
ThreatSeverity::Medium ThreatSeverity::Medium
@@ -122,13 +125,11 @@ impl CloudMLEngine {
let prediction = ThreatPrediction { let prediction = ThreatPrediction {
threat_level, threat_level,
technique_predictions: vec![ technique_predictions: vec![TechniquePrediction {
TechniquePrediction { technique_id: "T1055".to_string(),
technique_id: "T1055".to_string(), technique_name: "Process Injection".to_string(),
technique_name: "Process Injection".to_string(), confidence: 0.85,
confidence: 0.85, }],
},
],
anomaly_score: 0.75, anomaly_score: 0.75,
}; };
@@ -140,11 +141,14 @@ impl CloudMLEngine {
}; };
// Cache result // Cache result
self.cache.insert(cache_key, CachedPrediction { self.cache.insert(
result: result.clone(), cache_key,
timestamp: SystemTime::now(), CachedPrediction {
ttl: Duration::from_secs(300), // 5 minutes result: result.clone(),
}); timestamp: SystemTime::now(),
ttl: Duration::from_secs(300), // 5 minutes
},
);
Ok(result) Ok(result)
} }

View File

@@ -1,7 +1,6 @@
use crate::{ProcessInfo, MemoryRegion, GhostError}; use crate::{GhostError, MemoryRegion, ProcessInfo};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, Duration};
#[derive(Debug)] #[derive(Debug)]
pub struct NeuralMemoryAnalyzer { pub struct NeuralMemoryAnalyzer {
@@ -143,7 +142,7 @@ impl NeuralMemoryAnalyzer {
pub async fn analyze_memory_regions( pub async fn analyze_memory_regions(
&mut self, &mut self,
process: &ProcessInfo, _process: &ProcessInfo,
memory_regions: &[MemoryRegion], memory_regions: &[MemoryRegion],
) -> Result<NeuralAnalysisResult, GhostError> { ) -> Result<NeuralAnalysisResult, GhostError> {
// Extract features // Extract features
@@ -178,15 +177,23 @@ impl NeuralMemoryAnalyzer {
features.push(memory_regions.len() as f32); features.push(memory_regions.len() as f32);
// Protection features // Protection features
let rwx_count = memory_regions.iter() let rwx_count = memory_regions
.filter(|r| r.protection.is_readable() && r.protection.is_writable() && r.protection.is_executable()) .iter()
.filter(|r| {
r.protection.is_readable()
&& r.protection.is_writable()
&& r.protection.is_executable()
})
.count() as f32; .count() as f32;
features.push(rwx_count); features.push(rwx_count);
Ok(features) Ok(features)
} }
async fn run_neural_ensemble(&self, features: &[f32]) -> Result<Vec<ModelPrediction>, GhostError> { async fn run_neural_ensemble(
&self,
features: &[f32],
) -> Result<Vec<ModelPrediction>, GhostError> {
let mut predictions = Vec::new(); let mut predictions = Vec::new();
for network in &self.neural_networks { for network in &self.neural_networks {
@@ -197,7 +204,11 @@ impl NeuralMemoryAnalyzer {
Ok(predictions) Ok(predictions)
} }
async fn simulate_neural_inference(&self, network: &NeuralNetwork, _features: &[f32]) -> Result<ModelPrediction, GhostError> { async fn simulate_neural_inference(
&self,
network: &NeuralNetwork,
_features: &[f32],
) -> Result<ModelPrediction, GhostError> {
let prediction = network.accuracy * 0.5; // Simulate prediction let prediction = network.accuracy * 0.5; // Simulate prediction
Ok(ModelPrediction { Ok(ModelPrediction {
@@ -213,7 +224,8 @@ impl NeuralMemoryAnalyzer {
return 0.0; return 0.0;
} }
let weighted_sum: f32 = predictions.iter() let weighted_sum: f32 = predictions
.iter()
.map(|p| p.prediction * p.confidence) .map(|p| p.prediction * p.confidence)
.sum(); .sum();
let total_weight: f32 = predictions.iter().map(|p| p.confidence).sum(); let total_weight: f32 = predictions.iter().map(|p| p.confidence).sum();

View File

@@ -54,8 +54,8 @@ mod platform {
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
TH32CS_SNAPPROCESS, TH32CS_SNAPPROCESS,
}; };
use windows::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION};
use windows::Win32::System::ProcessStatus::GetProcessImageFileNameW; use windows::Win32::System::ProcessStatus::GetProcessImageFileNameW;
use windows::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION};
pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> { pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> {
let mut processes = Vec::new(); let mut processes = Vec::new();
@@ -163,13 +163,14 @@ mod platform {
fn get_process_info(pid: u32) -> Result<ProcessInfo> { fn get_process_info(pid: u32) -> Result<ProcessInfo> {
let stat_path = format!("/proc/{}/stat", pid); let stat_path = format!("/proc/{}/stat", pid);
let stat_content = let stat_content = fs::read_to_string(&stat_path).context("Failed to read process stat")?;
fs::read_to_string(&stat_path).context("Failed to read process stat")?;
let (name, ppid, thread_count) = parse_stat(&stat_content)?; let (name, ppid, thread_count) = parse_stat(&stat_content)?;
let exe_path = format!("/proc/{}/exe", pid); let exe_path = format!("/proc/{}/exe", pid);
let path = fs::read_link(&exe_path).ok().map(|p| p.to_string_lossy().into_owned()); let path = fs::read_link(&exe_path)
.ok()
.map(|p| p.to_string_lossy().into_owned());
Ok(ProcessInfo { Ok(ProcessInfo {
pid, pid,
@@ -219,7 +220,9 @@ mod platform {
use anyhow::Result; use anyhow::Result;
pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> { pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> {
Err(anyhow::anyhow!("Process enumeration not supported on this platform")) Err(anyhow::anyhow!(
"Process enumeration not supported on this platform"
))
} }
} }

View File

@@ -1,5 +1,3 @@
use crate::{GhostError, Result};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ShellcodeSignature { pub struct ShellcodeSignature {
pub pattern: Vec<u8>, pub pattern: Vec<u8>,
@@ -17,6 +15,7 @@ pub struct ShellcodeDetection {
} }
/// Common shellcode patterns and signatures /// Common shellcode patterns and signatures
#[derive(Debug)]
pub struct ShellcodeDetector { pub struct ShellcodeDetector {
signatures: Vec<ShellcodeSignature>, signatures: Vec<ShellcodeSignature>,
} }
@@ -298,8 +297,12 @@ impl ShellcodeDetector {
// Linux x64 execve pattern // Linux x64 execve pattern
self.signatures.push(ShellcodeSignature { self.signatures.push(ShellcodeSignature {
pattern: vec![0x48, 0x31, 0xD2, 0x48, 0xBB, 0xFF, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x73, 0x68], // xor rdx, rdx; mov rbx, "/bin/sh" pattern: vec![
mask: vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], 0x48, 0x31, 0xD2, 0x48, 0xBB, 0xFF, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x73, 0x68,
], // xor rdx, rdx; mov rbx, "/bin/sh"
mask: vec![
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
],
name: "Linux x64 execve /bin/sh", name: "Linux x64 execve /bin/sh",
confidence: 0.98, confidence: 0.98,
}); });
@@ -466,7 +469,11 @@ impl ShellcodeDetector {
} }
} }
fn check_instruction_patterns(&self, data: &[u8], base_address: usize) -> Option<ShellcodeDetection> { fn check_instruction_patterns(
&self,
data: &[u8],
base_address: usize,
) -> Option<ShellcodeDetection> {
if data.len() < 32 { if data.len() < 32 {
return None; return None;
} }
@@ -479,10 +486,10 @@ impl ShellcodeDetector {
match data[i] { match data[i] {
0xEB => suspicious_instructions += 1, // Short jump 0xEB => suspicious_instructions += 1, // Short jump
0xE9 => suspicious_instructions += 1, // Near jump 0xE9 => suspicious_instructions += 1, // Near jump
0xFF if data.get(i + 1).map_or(false, |&b| (b & 0x38) == 0x20) => { 0xFF if data.get(i + 1).is_some_and(|&b| (b & 0x38) == 0x20) => {
suspicious_instructions += 2; // Indirect jump suspicious_instructions += 2; // Indirect jump
} }
0x0F if data.get(i + 1).map_or(false, |&b| b == 0x05) => { 0x0F if data.get(i + 1).is_some_and(|&b| b == 0x05) => {
suspicious_instructions += 2; // SYSCALL suspicious_instructions += 2; // SYSCALL
} }
_ => {} _ => {}

View File

@@ -1,9 +1,9 @@
use crate::{DetectionResult, EvasionResult, ProcessInfo, ThreatContext, ThreatLevel};
use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{SystemTime, Duration}; use std::time::{Duration, SystemTime};
use tokio::sync::{broadcast, mpsc}; use tokio::sync::{broadcast, mpsc};
use serde::{Serialize, Deserialize};
use crate::{DetectionResult, ThreatLevel, ProcessInfo, ThreatContext, EvasionResult};
/// Real-time Event Streaming and Alerting System /// Real-time Event Streaming and Alerting System
/// Provides configurable alerting, correlation, and notification capabilities /// Provides configurable alerting, correlation, and notification capabilities
@@ -519,6 +519,12 @@ pub struct EventBuffer {
retention_period: Duration, retention_period: Duration,
} }
impl Default for EventStreamingSystem {
fn default() -> Self {
Self::new()
}
}
impl EventStreamingSystem { impl EventStreamingSystem {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -526,12 +532,18 @@ impl EventStreamingSystem {
alert_manager: AlertManager::new(), alert_manager: AlertManager::new(),
correlation_engine: CorrelationEngine::new(), correlation_engine: CorrelationEngine::new(),
notification_system: NotificationSystem::new(), notification_system: NotificationSystem::new(),
event_buffer: Arc::new(Mutex::new(EventBuffer::new(10000, Duration::from_secs(3600)))), event_buffer: Arc::new(Mutex::new(EventBuffer::new(
10000,
Duration::from_secs(3600),
))),
} }
} }
/// Publish a detection event /// Publish a detection event
pub async fn publish_detection_event(&mut self, detection: DetectionResult) -> Result<(), Box<dyn std::error::Error>> { pub async fn publish_detection_event(
&mut self,
detection: DetectionResult,
) -> Result<(), Box<dyn std::error::Error>> {
let event = StreamingEvent { let event = StreamingEvent {
event_id: format!("det_{}", uuid::Uuid::new_v4()), event_id: format!("det_{}", uuid::Uuid::new_v4()),
timestamp: SystemTime::now(), timestamp: SystemTime::now(),
@@ -556,11 +568,16 @@ impl EventStreamingSystem {
tags: vec!["process-injection".to_string(), "detection".to_string()], tags: vec!["process-injection".to_string(), "detection".to_string()],
}; };
self.publish_event(EventChannel::DetectionEvents, event).await self.publish_event(EventChannel::DetectionEvents, event)
.await
} }
/// Publish an evasion detection event /// Publish an evasion detection event
pub async fn publish_evasion_event(&mut self, evasion: EvasionResult, process: &ProcessInfo) -> Result<(), Box<dyn std::error::Error>> { pub async fn publish_evasion_event(
&mut self,
evasion: EvasionResult,
_process: &ProcessInfo,
) -> Result<(), Box<dyn std::error::Error>> {
let severity = if evasion.sophistication_score > 0.8 { let severity = if evasion.sophistication_score > 0.8 {
EventSeverity::Critical EventSeverity::Critical
} else if evasion.sophistication_score > 0.6 { } else if evasion.sophistication_score > 0.6 {
@@ -589,11 +606,16 @@ impl EventStreamingSystem {
tags: vec!["evasion".to_string(), "anti-analysis".to_string()], tags: vec!["evasion".to_string(), "anti-analysis".to_string()],
}; };
self.publish_event(EventChannel::EvasionDetection, event).await self.publish_event(EventChannel::EvasionDetection, event)
.await
} }
/// Publish a generic event to specified channel /// Publish a generic event to specified channel
async fn publish_event(&mut self, channel: EventChannel, event: StreamingEvent) -> Result<(), Box<dyn std::error::Error>> { async fn publish_event(
&mut self,
channel: EventChannel,
event: StreamingEvent,
) -> Result<(), Box<dyn std::error::Error>> {
// Add to event buffer for correlation // Add to event buffer for correlation
{ {
let mut buffer = self.event_buffer.lock().unwrap(); let mut buffer = self.event_buffer.lock().unwrap();
@@ -614,7 +636,10 @@ impl EventStreamingSystem {
Ok(()) Ok(())
} }
async fn handle_correlated_incident(&mut self, incident: CorrelatedIncident) -> Result<(), Box<dyn std::error::Error>> { async fn handle_correlated_incident(
&mut self,
incident: CorrelatedIncident,
) -> Result<(), Box<dyn std::error::Error>> {
println!("Correlated incident detected: {}", incident.title); println!("Correlated incident detected: {}", incident.title);
// Create alert for correlated incident // Create alert for correlated incident
@@ -653,6 +678,12 @@ impl EventStreamingSystem {
} }
} }
impl Default for EventPublisher {
fn default() -> Self {
Self::new()
}
}
impl EventPublisher { impl EventPublisher {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -661,7 +692,11 @@ impl EventPublisher {
} }
} }
pub async fn publish(&mut self, channel: EventChannel, event: StreamingEvent) -> Result<(), Box<dyn std::error::Error>> { pub async fn publish(
&mut self,
channel: EventChannel,
event: StreamingEvent,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(sender) = self.channels.get(&channel) { if let Some(sender) = self.channels.get(&channel) {
sender.send(event)?; sender.send(event)?;
} }
@@ -669,11 +704,10 @@ impl EventPublisher {
} }
pub fn subscribe(&mut self, channel: EventChannel) -> broadcast::Receiver<StreamingEvent> { pub fn subscribe(&mut self, channel: EventChannel) -> broadcast::Receiver<StreamingEvent> {
let sender = self.channels.entry(channel.clone()) let sender = self.channels.entry(channel.clone()).or_insert_with(|| {
.or_insert_with(|| { let (tx, _) = broadcast::channel(1000);
let (tx, _) = broadcast::channel(1000); tx
tx });
});
let receiver = sender.subscribe(); let receiver = sender.subscribe();
*self.subscribers.entry(channel).or_insert(0) += 1; *self.subscribers.entry(channel).or_insert(0) += 1;
@@ -681,6 +715,12 @@ impl EventPublisher {
} }
} }
impl Default for AlertManager {
fn default() -> Self {
Self::new()
}
}
impl AlertManager { impl AlertManager {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -691,8 +731,13 @@ impl AlertManager {
} }
} }
pub async fn evaluate_alerts(&mut self, event: &StreamingEvent) -> Result<(), Box<dyn std::error::Error>> { pub async fn evaluate_alerts(
let triggered_rules: Vec<AlertRule> = self.alert_rules.iter() &mut self,
event: &StreamingEvent,
) -> Result<(), Box<dyn std::error::Error>> {
let triggered_rules: Vec<AlertRule> = self
.alert_rules
.iter()
.filter(|rule| rule.enabled && self.evaluate_rule_conditions(rule, event)) .filter(|rule| rule.enabled && self.evaluate_rule_conditions(rule, event))
.cloned() .cloned()
.collect(); .collect();
@@ -734,7 +779,11 @@ impl AlertManager {
}) })
} }
async fn trigger_alert(&mut self, rule: &AlertRule, event: &StreamingEvent) -> Result<(), Box<dyn std::error::Error>> { async fn trigger_alert(
&mut self,
rule: &AlertRule,
event: &StreamingEvent,
) -> Result<(), Box<dyn std::error::Error>> {
let alert = Alert { let alert = Alert {
alert_id: format!("alert_{}", uuid::Uuid::new_v4()), alert_id: format!("alert_{}", uuid::Uuid::new_v4()),
rule_id: rule.rule_id.clone(), rule_id: rule.rule_id.clone(),
@@ -769,13 +818,20 @@ impl AlertManager {
notification_count: 0, notification_count: 0,
}; };
self.active_alerts.insert(alert.alert_id.clone(), active_alert); self.active_alerts
.insert(alert.alert_id.clone(), active_alert);
self.alert_history.push(alert); self.alert_history.push(alert);
Ok(()) Ok(())
} }
} }
impl Default for CorrelationEngine {
fn default() -> Self {
Self::new()
}
}
impl CorrelationEngine { impl CorrelationEngine {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -789,10 +845,13 @@ impl CorrelationEngine {
} }
} }
pub async fn correlate_event(&mut self, event: &StreamingEvent) -> Result<Option<CorrelatedIncident>, Box<dyn std::error::Error>> { pub async fn correlate_event(
&mut self,
event: &StreamingEvent,
) -> Result<Option<CorrelatedIncident>, Box<dyn std::error::Error>> {
// Simplified correlation logic // Simplified correlation logic
for rule in &self.correlation_rules { for rule in &self.correlation_rules {
if let Some(incident) = self.evaluate_correlation_rule(rule, event) { if let Some(_incident) = self.evaluate_correlation_rule(rule, event) {
self.incident_tracker.incident_counter += 1; self.incident_tracker.incident_counter += 1;
let incident_id = format!("incident_{}", self.incident_tracker.incident_counter); let incident_id = format!("incident_{}", self.incident_tracker.incident_counter);
@@ -810,7 +869,9 @@ impl CorrelationEngine {
status: IncidentStatus::Open, status: IncidentStatus::Open,
}; };
self.incident_tracker.incidents.insert(incident_id, correlated_incident.clone()); self.incident_tracker
.incidents
.insert(incident_id, correlated_incident.clone());
return Ok(Some(correlated_incident)); return Ok(Some(correlated_incident));
} }
} }
@@ -818,13 +879,23 @@ impl CorrelationEngine {
Ok(None) Ok(None)
} }
fn evaluate_correlation_rule(&self, rule: &CorrelationRule, event: &StreamingEvent) -> Option<()> { fn evaluate_correlation_rule(
&self,
_rule: &CorrelationRule,
_event: &StreamingEvent,
) -> Option<()> {
// Simplified correlation rule evaluation // Simplified correlation rule evaluation
// In a real implementation, this would be much more sophisticated // In a real implementation, this would be much more sophisticated
Some(()) Some(())
} }
} }
impl Default for NotificationSystem {
fn default() -> Self {
Self::new()
}
}
impl NotificationSystem { impl NotificationSystem {
pub fn new() -> Self { pub fn new() -> Self {
let (tx, _) = mpsc::channel(1000); let (tx, _) = mpsc::channel(1000);
@@ -836,20 +907,35 @@ impl NotificationSystem {
} }
pub fn add_email_channel(&mut self, name: String, config: SmtpConfig) { pub fn add_email_channel(&mut self, name: String, config: SmtpConfig) {
let channel = EmailChannel { smtp_config: config }; let channel = EmailChannel {
smtp_config: config,
};
self.channels.insert(name, Box::new(channel)); self.channels.insert(name, Box::new(channel));
} }
pub fn add_slack_channel(&mut self, name: String, webhook_url: String, default_channel: String) { pub fn add_slack_channel(
let channel = SlackChannel { webhook_url, default_channel }; &mut self,
name: String,
webhook_url: String,
default_channel: String,
) {
let channel = SlackChannel {
webhook_url,
default_channel,
};
self.channels.insert(name, Box::new(channel)); self.channels.insert(name, Box::new(channel));
} }
pub fn add_webhook_channel(&mut self, name: String, endpoint_url: String, headers: HashMap<String, String>) { pub fn add_webhook_channel(
&mut self,
name: String,
endpoint_url: String,
headers: HashMap<String, String>,
) {
let channel = WebhookChannel { let channel = WebhookChannel {
endpoint_url, endpoint_url,
headers, headers,
auth_token: None auth_token: None,
}; };
self.channels.insert(name, Box::new(channel)); self.channels.insert(name, Box::new(channel));
} }
@@ -879,7 +965,8 @@ impl EventBuffer {
pub fn get_events_in_window(&self, window: Duration) -> Vec<&StreamingEvent> { pub fn get_events_in_window(&self, window: Duration) -> Vec<&StreamingEvent> {
let cutoff_time = SystemTime::now() - window; let cutoff_time = SystemTime::now() - window;
self.events.iter() self.events
.iter()
.filter(|e| e.timestamp >= cutoff_time) .filter(|e| e.timestamp >= cutoff_time)
.collect() .collect()
} }

View File

@@ -1,9 +1,9 @@
use crate::{
DetectionEngine, DetectionResult, MemoryProtection, MemoryRegion, ProcessInfo, ThreadInfo,
ThreatLevel,
};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::{
DetectionEngine, DetectionResult, ThreatLevel, ProcessInfo, MemoryRegion,
ThreadInfo, MemoryProtection, EvasionResult, ThreatContext
};
/// Comprehensive Testing Framework for Ghost Detection Engine /// Comprehensive Testing Framework for Ghost Detection Engine
/// Provides unit tests, integration tests, and performance benchmarks /// Provides unit tests, integration tests, and performance benchmarks
@@ -189,10 +189,10 @@ pub struct ProcessAnalysisBenchmark {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ComplexityLevel { pub enum ComplexityLevel {
Simple, // Basic process with minimal memory regions Simple, // Basic process with minimal memory regions
Moderate, // Standard process with normal memory layout Moderate, // Standard process with normal memory layout
Complex, // Process with many threads and memory regions Complex, // Process with many threads and memory regions
Extreme, // Heavily loaded process with maximum complexity Extreme, // Heavily loaded process with maximum complexity
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -205,10 +205,10 @@ pub struct MemoryScanningBenchmark {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ScanAlgorithm { pub enum ScanAlgorithm {
Linear, Linear,
Boyer_Moore, BoyerMoore,
Knuth_Morris_Pratt, KnuthMorrisPratt,
Aho_Corasick, AhoCorasick,
SIMD_Optimized, SimdOptimized,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -234,9 +234,9 @@ pub struct SystemScanBenchmark {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ScanDepth { pub enum ScanDepth {
Surface, // Basic process enumeration Surface, // Basic process enumeration
Standard, // Process + memory analysis Standard, // Process + memory analysis
Deep, // Full analysis including threads Deep, // Full analysis including threads
Comprehensive, // All detection modules enabled Comprehensive, // All detection modules enabled
} }
@@ -367,6 +367,12 @@ pub struct ValidationDetails {
pub false_negative_rate: f32, pub false_negative_rate: f32,
} }
impl Default for TestFramework {
fn default() -> Self {
Self::new()
}
}
impl TestFramework { impl TestFramework {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -404,24 +410,20 @@ impl TestFramework {
thread_count: 1, thread_count: 1,
suspicious_indicators: Vec::new(), suspicious_indicators: Vec::new(),
}, },
memory_data: vec![ memory_data: vec![MemoryTestData {
MemoryTestData { base_address: 0x400000,
base_address: 0x400000, size: 0x10000,
size: 0x10000, protection: MemoryProtection::ReadExecute,
protection: MemoryProtection::ReadExecute, contains_shellcode: false,
contains_shellcode: false, shellcode_pattern: None,
shellcode_pattern: None, }],
} thread_data: vec![ThreadTestData {
], tid: 5678,
thread_data: vec![ entry_point: 0x401000,
ThreadTestData { stack_base: 0x500000,
tid: 5678, stack_size: 0x10000,
entry_point: 0x401000, is_suspicious: false,
stack_base: 0x500000, }],
stack_size: 0x10000,
is_suspicious: false,
}
],
injection_type: None, injection_type: None,
}), }),
expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Clean), expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Clean),
@@ -444,29 +446,29 @@ impl TestFramework {
"Suspicious API calls".to_string(), "Suspicious API calls".to_string(),
], ],
}, },
memory_data: vec![ memory_data: vec![MemoryTestData {
MemoryTestData { base_address: 0x200000,
base_address: 0x200000, size: 0x1000,
size: 0x1000, protection: MemoryProtection::ReadWriteExecute,
protection: MemoryProtection::ReadWriteExecute, contains_shellcode: true,
contains_shellcode: true, shellcode_pattern: Some(vec![0x90, 0x90, 0xEB, 0xFE]), // NOP NOP JMP -2
shellcode_pattern: Some(vec![0x90, 0x90, 0xEB, 0xFE]), // NOP NOP JMP -2 }],
} thread_data: vec![ThreadTestData {
], tid: 1111,
thread_data: vec![ entry_point: 0x200000,
ThreadTestData { stack_base: 0x600000,
tid: 1111, stack_size: 0x10000,
entry_point: 0x200000, is_suspicious: true,
stack_base: 0x600000, }],
stack_size: 0x10000,
is_suspicious: true,
}
],
injection_type: Some(InjectionTestType::ShellcodeInjection), injection_type: Some(InjectionTestType::ShellcodeInjection),
}), }),
expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Malicious), expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Malicious),
timeout: Duration::from_secs(10), timeout: Duration::from_secs(10),
tags: vec!["unit".to_string(), "detection".to_string(), "malware".to_string()], tags: vec![
"unit".to_string(),
"detection".to_string(),
"malware".to_string(),
],
}); });
let test_suite = TestSuite { let test_suite = TestSuite {
@@ -477,7 +479,8 @@ impl TestFramework {
teardown_function: None, teardown_function: None,
}; };
self.test_suites.insert("detection_engine".to_string(), test_suite); self.test_suites
.insert("detection_engine".to_string(), test_suite);
} }
/// Create shellcode detection tests /// Create shellcode detection tests
@@ -496,20 +499,18 @@ impl TestFramework {
thread_count: 1, thread_count: 1,
suspicious_indicators: Vec::new(), suspicious_indicators: Vec::new(),
}, },
memory_data: vec![ memory_data: vec![MemoryTestData {
MemoryTestData { base_address: 0x300000,
base_address: 0x300000, size: 0x1000,
size: 0x1000, protection: MemoryProtection::ReadWriteExecute,
protection: MemoryProtection::ReadWriteExecute, contains_shellcode: true,
contains_shellcode: true, shellcode_pattern: Some(vec![
shellcode_pattern: Some(vec![ 0x31, 0xC0, // XOR EAX, EAX
0x31, 0xC0, // XOR EAX, EAX 0x50, // PUSH EAX
0x50, // PUSH EAX 0x68, 0x2F, 0x2F, 0x73, 0x68, // PUSH //sh
0x68, 0x2F, 0x2F, 0x73, 0x68, // PUSH //sh 0x68, 0x2F, 0x62, 0x69, 0x6E, // PUSH /bin
0x68, 0x2F, 0x62, 0x69, 0x6E, // PUSH /bin ]),
]), }],
}
],
thread_data: Vec::new(), thread_data: Vec::new(),
injection_type: Some(InjectionTestType::ShellcodeInjection), injection_type: Some(InjectionTestType::ShellcodeInjection),
}), }),
@@ -526,7 +527,8 @@ impl TestFramework {
teardown_function: None, teardown_function: None,
}; };
self.test_suites.insert("shellcode_detection".to_string(), test_suite); self.test_suites
.insert("shellcode_detection".to_string(), test_suite);
} }
/// Create process hollowing detection tests /// Create process hollowing detection tests
@@ -547,15 +549,13 @@ impl TestFramework {
"Unexpected memory layout".to_string(), "Unexpected memory layout".to_string(),
], ],
}, },
memory_data: vec![ memory_data: vec![MemoryTestData {
MemoryTestData { base_address: 0x400000,
base_address: 0x400000, size: 0x20000,
size: 0x20000, protection: MemoryProtection::ReadWriteExecute,
protection: MemoryProtection::ReadWriteExecute, contains_shellcode: false,
contains_shellcode: false, shellcode_pattern: None,
shellcode_pattern: None, }],
}
],
thread_data: Vec::new(), thread_data: Vec::new(),
injection_type: Some(InjectionTestType::ProcessHollowing), injection_type: Some(InjectionTestType::ProcessHollowing),
}), }),
@@ -572,7 +572,8 @@ impl TestFramework {
teardown_function: None, teardown_function: None,
}; };
self.test_suites.insert("process_hollowing".to_string(), test_suite); self.test_suites
.insert("process_hollowing".to_string(), test_suite);
} }
/// Create evasion detection tests /// Create evasion detection tests
@@ -610,7 +611,8 @@ impl TestFramework {
teardown_function: None, teardown_function: None,
}; };
self.test_suites.insert("evasion_detection".to_string(), test_suite); self.test_suites
.insert("evasion_detection".to_string(), test_suite);
} }
/// Create threat intelligence tests /// Create threat intelligence tests
@@ -626,12 +628,10 @@ impl TestFramework {
benchmarks.push(Benchmark { benchmarks.push(Benchmark {
name: "single_process_analysis".to_string(), name: "single_process_analysis".to_string(),
description: "Benchmark single process analysis performance".to_string(), description: "Benchmark single process analysis performance".to_string(),
benchmark_function: BenchmarkFunction::ProcessAnalysis( benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark {
ProcessAnalysisBenchmark { process_count: 1,
process_count: 1, complexity_level: ComplexityLevel::Moderate,
complexity_level: ComplexityLevel::Moderate, }),
}
),
warm_up_iterations: 10, warm_up_iterations: 10,
measurement_iterations: 100, measurement_iterations: 100,
target_metrics: vec![ target_metrics: vec![
@@ -644,12 +644,10 @@ impl TestFramework {
benchmarks.push(Benchmark { benchmarks.push(Benchmark {
name: "bulk_process_analysis".to_string(), name: "bulk_process_analysis".to_string(),
description: "Benchmark bulk process analysis performance".to_string(), description: "Benchmark bulk process analysis performance".to_string(),
benchmark_function: BenchmarkFunction::ProcessAnalysis( benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark {
ProcessAnalysisBenchmark { process_count: 100,
process_count: 100, complexity_level: ComplexityLevel::Simple,
complexity_level: ComplexityLevel::Simple, }),
}
),
warm_up_iterations: 5, warm_up_iterations: 5,
measurement_iterations: 20, measurement_iterations: 20,
target_metrics: vec![ target_metrics: vec![
@@ -666,7 +664,8 @@ impl TestFramework {
baseline_measurements: HashMap::new(), baseline_measurements: HashMap::new(),
}; };
self.benchmark_suites.insert("performance".to_string(), benchmark_suite); self.benchmark_suites
.insert("performance".to_string(), benchmark_suite);
} }
/// Create integration tests /// Create integration tests
@@ -714,14 +713,17 @@ impl TestFramework {
teardown_function: None, teardown_function: None,
}; };
self.test_suites.insert("integration".to_string(), test_suite); self.test_suites
.insert("integration".to_string(), test_suite);
} }
/// Run all test suites /// Run all test suites
pub fn run_all_tests(&mut self) -> TestRunReport { pub fn run_all_tests(&mut self) -> TestRunReport {
let mut report = TestRunReport::new(); let mut report = TestRunReport::new();
let suite_names_and_tests: Vec<(String, TestSuite)> = self.test_suites.iter() let suite_names_and_tests: Vec<(String, TestSuite)> = self
.test_suites
.iter()
.map(|(name, suite)| (name.clone(), suite.clone())) .map(|(name, suite)| (name.clone(), suite.clone()))
.collect(); .collect();
@@ -764,15 +766,11 @@ impl TestFramework {
TestFunction::DetectionTest(params) => { TestFunction::DetectionTest(params) => {
self.run_detection_test(params, &test_case.expected_result) self.run_detection_test(params, &test_case.expected_result)
} }
TestFunction::PerformanceTest(params) => { TestFunction::PerformanceTest(params) => self.run_performance_test(params),
self.run_performance_test(params)
}
TestFunction::IntegrationTest(params) => { TestFunction::IntegrationTest(params) => {
self.run_integration_test(params, &test_case.expected_result) self.run_integration_test(params, &test_case.expected_result)
} }
TestFunction::StressTest(params) => { TestFunction::StressTest(params) => self.run_stress_test(params),
self.run_stress_test(params)
}
}; };
let execution_time = start_time.elapsed(); let execution_time = start_time.elapsed();
@@ -793,7 +791,11 @@ impl TestFramework {
} }
/// Run detection test /// Run detection test
fn run_detection_test(&self, params: &DetectionTestParams, expected: &ExpectedResult) -> TestStatus { fn run_detection_test(
&self,
params: &DetectionTestParams,
expected: &ExpectedResult,
) -> TestStatus {
// Create test detection engine // Create test detection engine
let mut engine = match DetectionEngine::new() { let mut engine = match DetectionEngine::new() {
Ok(engine) => engine, Ok(engine) => engine,
@@ -809,24 +811,28 @@ impl TestFramework {
thread_count: params.process_data.thread_count, thread_count: params.process_data.thread_count,
}; };
let memory_regions: Vec<MemoryRegion> = params.memory_data.iter().map(|mem| { let memory_regions: Vec<MemoryRegion> = params
MemoryRegion { .memory_data
.iter()
.map(|mem| MemoryRegion {
base_address: mem.base_address, base_address: mem.base_address,
size: mem.size, size: mem.size,
protection: mem.protection.clone(), protection: mem.protection,
region_type: "PRIVATE".to_string(), region_type: "PRIVATE".to_string(),
} })
}).collect(); .collect();
let threads: Vec<ThreadInfo> = params.thread_data.iter().map(|thread| { let threads: Vec<ThreadInfo> = params
ThreadInfo { .thread_data
.iter()
.map(|thread| ThreadInfo {
tid: thread.tid, tid: thread.tid,
owner_pid: process_info.pid, owner_pid: process_info.pid,
start_address: thread.entry_point, start_address: thread.entry_point,
creation_time: 0, creation_time: 0,
state: crate::thread::ThreadState::Running, state: crate::thread::ThreadState::Running,
} })
}).collect(); .collect();
// Run detection // Run detection
let result = engine.analyze_process(&process_info, &memory_regions, Some(&threads)); let result = engine.analyze_process(&process_info, &memory_regions, Some(&threads));
@@ -878,7 +884,11 @@ impl TestFramework {
} }
/// Run integration test /// Run integration test
fn run_integration_test(&self, _params: &IntegrationTestParams, _expected: &ExpectedResult) -> TestStatus { fn run_integration_test(
&self,
_params: &IntegrationTestParams,
_expected: &ExpectedResult,
) -> TestStatus {
// Implementation would test component interactions // Implementation would test component interactions
TestStatus::Passed TestStatus::Passed
} }
@@ -901,6 +911,12 @@ pub struct TestRunReport {
pub suite_results: HashMap<String, Vec<TestResult>>, pub suite_results: HashMap<String, Vec<TestResult>>,
} }
impl Default for TestRunReport {
fn default() -> Self {
Self::new()
}
}
impl TestRunReport { impl TestRunReport {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -937,6 +953,12 @@ impl TestRunReport {
} }
} }
impl Default for TestDataGenerator {
fn default() -> Self {
Self::new()
}
}
impl TestDataGenerator { impl TestDataGenerator {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -947,7 +969,7 @@ impl TestDataGenerator {
} }
/// Generate synthetic test processes /// Generate synthetic test processes
pub fn generate_test_processes(&self, count: usize) -> Vec<ProcessTestData> { pub fn generate_test_processes(&self, _count: usize) -> Vec<ProcessTestData> {
// Implementation would generate realistic test process data // Implementation would generate realistic test process data
Vec::new() Vec::new()
} }
@@ -962,6 +984,12 @@ impl TestDataGenerator {
} }
} }
impl Default for PerformanceProfiler {
fn default() -> Self {
Self::new()
}
}
impl PerformanceProfiler { impl PerformanceProfiler {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@@ -983,7 +1011,9 @@ impl PerformanceProfiler {
/// Stop profiling and collect results /// Stop profiling and collect results
pub fn stop_profiling(&mut self, session_id: &str) -> Option<Vec<Measurement>> { pub fn stop_profiling(&mut self, session_id: &str) -> Option<Vec<Measurement>> {
self.active_profiles.remove(session_id).map(|session| session.measurements) self.active_profiles
.remove(session_id)
.map(|session| session.measurements)
} }
/// Record a measurement /// Record a measurement

View File

@@ -60,7 +60,7 @@ mod platform {
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use windows::Win32::Foundation::CloseHandle; use windows::Win32::Foundation::CloseHandle;
use windows::Win32::System::Diagnostics::ToolHelp::{ use windows::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Thread32First, Thread32Next, THREADENTRY32, TH32CS_SNAPTHREAD, CreateToolhelp32Snapshot, Thread32First, Thread32Next, TH32CS_SNAPTHREAD, THREADENTRY32,
}; };
use windows::Win32::System::Threading::{ use windows::Win32::System::Threading::{
OpenThread, THREAD_QUERY_INFORMATION, THREAD_QUERY_LIMITED_INFORMATION, OpenThread, THREAD_QUERY_INFORMATION, THREAD_QUERY_LIMITED_INFORMATION,
@@ -216,8 +216,7 @@ mod platform {
pub fn enumerate_threads(pid: u32) -> Result<Vec<ThreadInfo>> { pub fn enumerate_threads(pid: u32) -> Result<Vec<ThreadInfo>> {
let task_dir = format!("/proc/{}/task", pid); let task_dir = format!("/proc/{}/task", pid);
let entries = let entries = fs::read_dir(&task_dir).context(format!("Failed to read {}", task_dir))?;
fs::read_dir(&task_dir).context(format!("Failed to read {}", task_dir))?;
let mut threads = Vec::new(); let mut threads = Vec::new();
@@ -341,11 +340,7 @@ mod platform {
} }
extern "C" { extern "C" {
fn task_for_pid( fn task_for_pid(target_tport: mach_port_t, pid: i32, task: *mut mach_port_t) -> i32;
target_tport: mach_port_t,
pid: i32,
task: *mut mach_port_t,
) -> i32;
fn mach_task_self() -> mach_port_t; fn mach_task_self() -> mach_port_t;
fn task_threads( fn task_threads(
target_task: mach_port_t, target_task: mach_port_t,
@@ -359,11 +354,7 @@ mod platform {
thread_info_out_cnt: *mut u32, thread_info_out_cnt: *mut u32,
) -> i32; ) -> i32;
fn mach_port_deallocate(task: mach_port_t, name: mach_port_t) -> i32; fn mach_port_deallocate(task: mach_port_t, name: mach_port_t) -> i32;
fn vm_deallocate( fn vm_deallocate(target_task: mach_port_t, address: usize, size: usize) -> i32;
target_task: mach_port_t,
address: usize,
size: usize,
) -> i32;
} }
let mut threads = Vec::new(); let mut threads = Vec::new();
@@ -420,11 +411,9 @@ mod platform {
// Calculate creation time from user_time + system_time (accumulated time) // Calculate creation time from user_time + system_time (accumulated time)
let creation_time = if kr == 0 { let creation_time = if kr == 0 {
let total_microseconds = (info.user_time.seconds as u64 * 1_000_000 (info.user_time.seconds as u64 * 1_000_000 + info.user_time.microseconds as u64)
+ info.user_time.microseconds as u64)
+ (info.system_time.seconds as u64 * 1_000_000 + (info.system_time.seconds as u64 * 1_000_000
+ info.system_time.microseconds as u64); + info.system_time.microseconds as u64)
total_microseconds
} else { } else {
0 0
}; };

View File

@@ -1,10 +1,11 @@
use crate::{DetectionResult, ProcessInfo, ThreatLevel};
use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, Duration}; use std::time::{Duration, SystemTime};
use serde::{Serialize, Deserialize};
use crate::{DetectionResult, ThreatLevel, ProcessInfo};
/// Threat Intelligence Integration Module /// Threat Intelligence Integration Module
/// Provides real-time threat context and IOC matching /// Provides real-time threat context and IOC matching
#[derive(Debug)]
pub struct ThreatIntelligence { pub struct ThreatIntelligence {
ioc_database: IocDatabase, ioc_database: IocDatabase,
threat_feeds: Vec<ThreatFeed>, threat_feeds: Vec<ThreatFeed>,
@@ -81,6 +82,7 @@ pub struct Campaign {
pub iocs: Vec<String>, pub iocs: Vec<String>,
} }
#[derive(Debug)]
pub struct IocDatabase { pub struct IocDatabase {
indicators: HashMap<String, IndicatorOfCompromise>, indicators: HashMap<String, IndicatorOfCompromise>,
hash_index: HashMap<String, Vec<String>>, hash_index: HashMap<String, Vec<String>>,
@@ -127,6 +129,7 @@ pub struct FrequencyRequirement {
pub time_window: Duration, pub time_window: Duration,
} }
#[derive(Debug)]
pub struct ThreatFeed { pub struct ThreatFeed {
pub name: String, pub name: String,
pub url: String, pub url: String,
@@ -153,6 +156,7 @@ pub struct FeedCredential {
pub password: Option<String>, pub password: Option<String>,
} }
#[derive(Debug)]
pub struct AttributionEngine { pub struct AttributionEngine {
threat_actors: HashMap<String, ThreatActor>, threat_actors: HashMap<String, ThreatActor>,
campaigns: HashMap<String, Campaign>, campaigns: HashMap<String, Campaign>,
@@ -171,18 +175,32 @@ pub struct AttributionRule {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AttributionCondition { pub enum AttributionCondition {
IocMatch { ioc_types: Vec<IocType>, min_matches: u32 }, IocMatch {
TechniquePattern { techniques: Vec<String>, correlation: f32 }, ioc_types: Vec<IocType>,
TemporalPattern { time_windows: Vec<Duration>, frequency: u32 }, min_matches: u32,
GeographicalIndicator { regions: Vec<String>, confidence: f32 }, },
TechniquePattern {
techniques: Vec<String>,
correlation: f32,
},
TemporalPattern {
time_windows: Vec<Duration>,
frequency: u32,
},
GeographicalIndicator {
regions: Vec<String>,
confidence: f32,
},
} }
#[derive(Debug)]
pub struct SimilarityCalculator { pub struct SimilarityCalculator {
technique_weights: HashMap<String, f32>, technique_weights: HashMap<String, f32>,
temporal_weights: HashMap<String, f32>, temporal_weights: HashMap<String, f32>,
behavioral_weights: HashMap<String, f32>, behavioral_weights: HashMap<String, f32>,
} }
#[derive(Debug)]
pub struct ReputationCache { pub struct ReputationCache {
process_reputations: HashMap<String, ProcessReputation>, process_reputations: HashMap<String, ProcessReputation>,
ip_reputations: HashMap<String, IpReputation>, ip_reputations: HashMap<String, IpReputation>,
@@ -321,7 +339,10 @@ impl ThreatIntelligence {
let mut risk_score = 0.0f32; let mut risk_score = 0.0f32;
// Check process name against IOCs // Check process name against IOCs
if let Some(iocs) = self.ioc_database.lookup_process_name(&detection.process.name) { if let Some(iocs) = self
.ioc_database
.lookup_process_name(&detection.process.name)
{
matched_iocs.extend(iocs); matched_iocs.extend(iocs);
} }
@@ -349,8 +370,9 @@ impl ThreatIntelligence {
} }
// Perform attribution analysis // Perform attribution analysis
let (threat_actor, campaign, attribution_confidence) = let (threat_actor, campaign, attribution_confidence) = self
self.attribution_engine.analyze_attribution(&matched_iocs, &detection.indicators); .attribution_engine
.analyze_attribution(&matched_iocs, &detection.indicators);
// Generate recommended actions // Generate recommended actions
let recommended_actions = self.generate_recommendations(&matched_iocs, risk_score); let recommended_actions = self.generate_recommendations(&matched_iocs, risk_score);
@@ -375,8 +397,11 @@ impl ThreatIntelligence {
let mut updates = Vec::new(); let mut updates = Vec::new();
for (idx, feed) in self.threat_feeds.iter().enumerate() { for (idx, feed) in self.threat_feeds.iter().enumerate() {
if SystemTime::now().duration_since(feed.last_update).unwrap_or_default() if SystemTime::now()
>= feed.update_interval { .duration_since(feed.last_update)
.unwrap_or_default()
>= feed.update_interval
{
// Fetch data inline to avoid borrow issues // Fetch data inline to avoid borrow issues
let iocs = Vec::new(); // Stub implementation let iocs = Vec::new(); // Stub implementation
updates.push((idx, iocs)); updates.push((idx, iocs));
@@ -391,7 +416,10 @@ impl ThreatIntelligence {
} }
/// Fetch data from a threat feed /// Fetch data from a threat feed
async fn fetch_feed_data(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> { async fn fetch_feed_data(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Implementation would depend on feed type // Implementation would depend on feed type
match feed.feed_type { match feed.feed_type {
FeedType::JSON => self.fetch_json_feed(feed).await, FeedType::JSON => self.fetch_json_feed(feed).await,
@@ -401,19 +429,28 @@ impl ThreatIntelligence {
} }
} }
async fn fetch_json_feed(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> { async fn fetch_json_feed(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Placeholder implementation // Placeholder implementation
// In a real implementation, this would fetch from the feed URL // In a real implementation, this would fetch from the feed URL
Ok(Vec::new()) Ok(Vec::new())
} }
async fn fetch_stix_feed(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> { async fn fetch_stix_feed(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Placeholder implementation // Placeholder implementation
// In a real implementation, this would parse STIX/TAXII data // In a real implementation, this would parse STIX/TAXII data
Ok(Vec::new()) Ok(Vec::new())
} }
async fn fetch_csv_feed(&self, feed: &ThreatFeed) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> { async fn fetch_csv_feed(
&self,
feed: &ThreatFeed,
) -> Result<Vec<IndicatorOfCompromise>, Box<dyn std::error::Error>> {
// Placeholder implementation // Placeholder implementation
// In a real implementation, this would parse CSV threat data // In a real implementation, this would parse CSV threat data
Ok(Vec::new()) Ok(Vec::new())
@@ -431,7 +468,10 @@ impl ThreatIntelligence {
confidence: 0.6, confidence: 0.6,
created_date: SystemTime::now(), created_date: SystemTime::now(),
expiry_date: None, expiry_date: None,
tags: vec!["process-injection".to_string(), "living-off-the-land".to_string()], tags: vec![
"process-injection".to_string(),
"living-off-the-land".to_string(),
],
mitre_techniques: vec!["T1055".to_string()], mitre_techniques: vec!["T1055".to_string()],
}, },
IndicatorOfCompromise { IndicatorOfCompromise {
@@ -467,7 +507,11 @@ impl ThreatIntelligence {
Ok(()) Ok(())
} }
fn generate_recommendations(&self, iocs: &[IndicatorOfCompromise], risk_score: f32) -> Vec<String> { fn generate_recommendations(
&self,
iocs: &[IndicatorOfCompromise],
risk_score: f32,
) -> Vec<String> {
let mut recommendations = Vec::new(); let mut recommendations = Vec::new();
if risk_score > 0.8 { if risk_score > 0.8 {
@@ -487,9 +531,15 @@ impl ThreatIntelligence {
for ioc in iocs { for ioc in iocs {
for technique in &ioc.mitre_techniques { for technique in &ioc.mitre_techniques {
match technique.as_str() { match technique.as_str() {
"T1055" => recommendations.push("Deploy process injection countermeasures".to_string()), "T1055" => {
"T1055.001" => recommendations.push("Monitor DLL loading activities".to_string()), recommendations.push("Deploy process injection countermeasures".to_string())
"T1055.002" => recommendations.push("Implement PE injection detection".to_string()), }
"T1055.001" => {
recommendations.push("Monitor DLL loading activities".to_string())
}
"T1055.002" => {
recommendations.push("Implement PE injection detection".to_string())
}
_ => {} _ => {}
} }
} }
@@ -518,12 +568,14 @@ impl IocDatabase {
// Update indexes for fast lookup // Update indexes for fast lookup
match ioc.ioc_type { match ioc.ioc_type {
IocType::FileHash => { IocType::FileHash => {
self.hash_index.entry(ioc.value.clone()) self.hash_index
.entry(ioc.value.clone())
.or_insert_with(Vec::new) .or_insert_with(Vec::new)
.push(ioc.id.clone()); .push(ioc.id.clone());
} }
IocType::MemorySignature | IocType::BehaviorPattern => { IocType::MemorySignature | IocType::BehaviorPattern => {
self.pattern_index.entry(ioc.value.clone()) self.pattern_index
.entry(ioc.value.clone())
.or_insert_with(Vec::new) .or_insert_with(Vec::new)
.push(ioc.id.clone()); .push(ioc.id.clone());
} }
@@ -532,23 +584,33 @@ impl IocDatabase {
} }
pub fn lookup_process_name(&self, name: &str) -> Option<Vec<IndicatorOfCompromise>> { pub fn lookup_process_name(&self, name: &str) -> Option<Vec<IndicatorOfCompromise>> {
let matches: Vec<_> = self.indicators let matches: Vec<_> = self
.indicators
.values() .values()
.filter(|ioc| ioc.ioc_type == IocType::ProcessName && ioc.value == name) .filter(|ioc| ioc.ioc_type == IocType::ProcessName && ioc.value == name)
.cloned() .cloned()
.collect(); .collect();
if matches.is_empty() { None } else { Some(matches) } if matches.is_empty() {
None
} else {
Some(matches)
}
} }
pub fn lookup_process_path(&self, path: &str) -> Option<Vec<IndicatorOfCompromise>> { pub fn lookup_process_path(&self, path: &str) -> Option<Vec<IndicatorOfCompromise>> {
let matches: Vec<_> = self.indicators let matches: Vec<_> = self
.indicators
.values() .values()
.filter(|ioc| ioc.ioc_type == IocType::ProcessPath && path.contains(&ioc.value)) .filter(|ioc| ioc.ioc_type == IocType::ProcessPath && path.contains(&ioc.value))
.cloned() .cloned()
.collect(); .collect();
if matches.is_empty() { None } else { Some(matches) } if matches.is_empty() {
None
} else {
Some(matches)
}
} }
pub fn lookup_memory_signature(&self, signature: &str) -> Option<Vec<IndicatorOfCompromise>> { pub fn lookup_memory_signature(&self, signature: &str) -> Option<Vec<IndicatorOfCompromise>> {
@@ -558,7 +620,11 @@ impl IocDatabase {
.filter_map(|id| self.indicators.get(id)) .filter_map(|id| self.indicators.get(id))
.cloned() .cloned()
.collect(); .collect();
if matches.is_empty() { None } else { Some(matches) } if matches.is_empty() {
None
} else {
Some(matches)
}
} else { } else {
None None
} }
@@ -581,9 +647,11 @@ impl AttributionEngine {
} }
} }
pub fn analyze_attribution(&self, iocs: &[IndicatorOfCompromise], indicators: &[String]) pub fn analyze_attribution(
-> (Option<ThreatActor>, Option<Campaign>, f32) { &self,
iocs: &[IndicatorOfCompromise],
indicators: &[String],
) -> (Option<ThreatActor>, Option<Campaign>, f32) {
let mut best_actor: Option<ThreatActor> = None; let mut best_actor: Option<ThreatActor> = None;
let mut best_campaign: Option<Campaign> = None; let mut best_campaign: Option<Campaign> = None;
let mut best_confidence = 0.0f32; let mut best_confidence = 0.0f32;
@@ -608,16 +676,23 @@ impl AttributionEngine {
(best_actor, best_campaign, best_confidence) (best_actor, best_campaign, best_confidence)
} }
fn evaluate_attribution_rule(&self, rule: &AttributionRule, fn evaluate_attribution_rule(
iocs: &[IndicatorOfCompromise], &self,
indicators: &[String]) -> f32 { rule: &AttributionRule,
iocs: &[IndicatorOfCompromise],
indicators: &[String],
) -> f32 {
let mut total_confidence = 0.0f32; let mut total_confidence = 0.0f32;
let mut condition_count = 0; let mut condition_count = 0;
for condition in &rule.conditions { for condition in &rule.conditions {
match condition { match condition {
AttributionCondition::IocMatch { ioc_types, min_matches } => { AttributionCondition::IocMatch {
let matches = iocs.iter() ioc_types,
min_matches,
} => {
let matches = iocs
.iter()
.filter(|ioc| ioc_types.contains(&ioc.ioc_type)) .filter(|ioc| ioc_types.contains(&ioc.ioc_type))
.count() as u32; .count() as u32;
@@ -625,8 +700,12 @@ impl AttributionEngine {
total_confidence += rule.confidence_weight; total_confidence += rule.confidence_weight;
} }
} }
AttributionCondition::TechniquePattern { techniques, correlation } => { AttributionCondition::TechniquePattern {
let technique_matches = iocs.iter() techniques,
correlation,
} => {
let technique_matches = iocs
.iter()
.flat_map(|ioc| &ioc.mitre_techniques) .flat_map(|ioc| &ioc.mitre_techniques)
.filter(|tech| techniques.contains(tech)) .filter(|tech| techniques.contains(tech))
.count(); .count();

View File

@@ -1,4 +1,4 @@
use crate::{ProcessInfo, MemoryRegion, GhostError}; use crate::{GhostError, MemoryRegion, ProcessInfo};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::SystemTime; use std::time::SystemTime;
@@ -94,15 +94,13 @@ impl DynamicYaraEngine {
} }
// Simulate rule download // Simulate rule download
let new_rules = vec![ let new_rules = vec![YaraRule {
YaraRule { name: format!("generic_malware_{}", updated_count + 1),
name: format!("generic_malware_{}", updated_count + 1), content: "rule generic_malware { condition: true }".to_string(),
content: "rule generic_malware { condition: true }".to_string(), source: source.name.clone(),
source: source.name.clone(), threat_level: ThreatLevel::Medium,
threat_level: ThreatLevel::Medium, last_updated: SystemTime::now(),
last_updated: SystemTime::now(), }];
},
];
self.rules.extend(new_rules); self.rules.extend(new_rules);
source.rule_count = self.rules.len(); source.rule_count = self.rules.len();
@@ -138,9 +136,7 @@ impl DynamicYaraEngine {
} }
} }
let scan_time_ms = start_time.elapsed() let scan_time_ms = start_time.elapsed().unwrap_or_default().as_millis() as u64;
.unwrap_or_default()
.as_millis() as u64;
Ok(YaraScanResult { Ok(YaraScanResult {
matches, matches,