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)]
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)]
pub struct HollowingDetection {
@@ -15,12 +15,25 @@ pub struct HollowingDetection {
pub enum HollowingIndicator {
UnmappedMainImage,
SuspiciousImageBase,
MemoryLayoutAnomaly { expected_size: usize, actual_size: usize },
MemoryLayoutAnomaly {
expected_size: usize,
actual_size: usize,
},
MismatchedPEHeader,
InvalidPEHeader { validation: String },
CorruptedPEStructure { address: usize, reason: String },
UnusualEntryPoint { address: usize },
SuspiciousMemoryGaps { gap_count: usize, largest_gap: usize },
InvalidPEHeader {
validation: String,
},
CorruptedPEStructure {
address: usize,
reason: String,
},
UnusualEntryPoint {
address: usize,
},
SuspiciousMemoryGaps {
gap_count: usize,
largest_gap: usize,
},
}
impl std::fmt::Display for HollowingIndicator {
@@ -28,8 +41,15 @@ impl std::fmt::Display for HollowingIndicator {
match self {
Self::UnmappedMainImage => write!(f, "Main executable image appears unmapped"),
Self::SuspiciousImageBase => write!(f, "Image base address is suspicious"),
Self::MemoryLayoutAnomaly { expected_size, actual_size } => {
write!(f, "Memory layout anomaly: expected {:#x}, found {:#x}", expected_size, actual_size)
Self::MemoryLayoutAnomaly {
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::InvalidPEHeader { validation } => {
@@ -41,14 +61,22 @@ impl std::fmt::Display for HollowingIndicator {
Self::UnusualEntryPoint { address } => {
write!(f, "Entry point at unusual location: {:#x}", address)
}
Self::SuspiciousMemoryGaps { gap_count, largest_gap } => {
write!(f, "{} memory gaps detected, largest: {:#x} bytes", gap_count, largest_gap)
Self::SuspiciousMemoryGaps {
gap_count,
largest_gap,
} => {
write!(
f,
"{} memory gaps detected, largest: {:#x} bytes",
gap_count, largest_gap
)
}
}
}
}
/// Process hollowing detection engine
#[derive(Debug)]
pub struct HollowingDetector;
impl HollowingDetector {
@@ -147,7 +175,13 @@ impl HollowingDetector {
// Calculate total executable memory size
let total_executable: usize = regions
.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)
.sum();
@@ -241,7 +275,11 @@ impl HollowingDetector {
}
#[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
let image_regions: Vec<_> = regions
.iter()
@@ -251,8 +289,7 @@ impl HollowingDetector {
for region in image_regions {
match validate_pe_header(pid, region.base_address) {
Ok(validation) => {
match validation {
Ok(validation) => match validation {
PEHeaderValidation::Valid => continue,
PEHeaderValidation::InvalidDosSignature => {
return Some(HollowingIndicator::InvalidPEHeader {
@@ -287,8 +324,7 @@ impl HollowingDetector {
});
}
PEHeaderValidation::NotPE => continue,
}
}
},
Err(_) => {
// Could not read memory - might be suspicious but don't report
continue;
@@ -300,7 +336,11 @@ impl HollowingDetector {
}
#[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
None
}
@@ -317,8 +357,11 @@ impl HollowingDetector {
let executable_regions: Vec<_> = regions
.iter()
.filter(|r| {
matches!(r.protection, crate::MemoryProtection::ReadExecute | crate::MemoryProtection::ReadWriteExecute)
&& r.region_type == "PRIVATE"
matches!(
r.protection,
crate::MemoryProtection::ReadExecute
| crate::MemoryProtection::ReadWriteExecute
) && r.region_type == "PRIVATE"
})
.collect();

View File

@@ -4,9 +4,7 @@
//! used for process injection (T1055.003, T1055.012).
//! On Linux, it detects LD_PRELOAD and LD_LIBRARY_PATH based injection.
use crate::{GhostError, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Type of hook detected.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
@@ -78,18 +76,18 @@ mod platform {
use std::collections::HashMap;
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::System::Diagnostics::Debug::ReadProcessMemory;
use windows::Win32::System::LibraryLoader::{
GetModuleHandleW, GetProcAddress, LoadLibraryW,
};
use windows::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress, LoadLibraryW};
use windows::Win32::System::ProcessStatus::{
EnumProcessModulesEx, GetModuleBaseNameW, GetModuleInformation, LIST_MODULES_ALL,
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::{
WH_CALLWNDPROC, WH_CALLWNDPROCRET, WH_CBT, WH_DEBUG, WH_FOREGROUNDIDLE, WH_GETMESSAGE,
WH_JOURNALPLAYBACK, WH_JOURNALRECORD, WH_KEYBOARD, WH_KEYBOARD_LL, WH_MOUSE,
WH_MOUSE_LL, WH_MSGFILTER, WH_SHELL, WH_SYSMSGFILTER,
WH_JOURNALPLAYBACK, WH_JOURNALRECORD, WH_KEYBOARD, WH_KEYBOARD_LL, WH_MOUSE, WH_MOUSE_LL,
WH_MSGFILTER, WH_SHELL, WH_SYSMSGFILTER,
};
/// Critical APIs commonly hooked for injection.
@@ -151,7 +149,11 @@ mod platform {
let mut hooks = Vec::new();
unsafe {
let handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, target_pid)
let handle = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
false,
target_pid,
)
.map_err(|e| GhostError::Process {
message: format!("Failed to open process: {}", e),
})?;
@@ -407,10 +409,9 @@ mod platform {
/// Detect LD_PRELOAD environment variable in process.
fn detect_ld_preload(pid: u32) -> Result<Vec<HookInfo>> {
let environ_path = format!("/proc/{}/environ", pid);
let environ_content = fs::read_to_string(&environ_path).map_err(|e| {
GhostError::Process {
let environ_content =
fs::read_to_string(&environ_path).map_err(|e| GhostError::Process {
message: format!("Failed to read process environment: {}", e),
}
})?;
let mut hooks = Vec::new();
@@ -442,10 +443,9 @@ mod platform {
/// Detect LD_LIBRARY_PATH environment variable manipulation.
fn detect_ld_library_path(pid: u32) -> Result<Vec<HookInfo>> {
let environ_path = format!("/proc/{}/environ", pid);
let environ_content = fs::read_to_string(&environ_path).map_err(|e| {
GhostError::Process {
let environ_content =
fs::read_to_string(&environ_path).map_err(|e| GhostError::Process {
message: format!("Failed to read process environment: {}", e),
}
})?;
let mut hooks = Vec::new();
@@ -476,25 +476,18 @@ mod platform {
/// Check if a library path is suspicious.
fn is_suspicious_library_path(path: &str) -> bool {
// Suspicious patterns
let suspicious_patterns = [
"/tmp/",
"/dev/shm/",
"/var/tmp/",
".",
"..",
"/home/",
];
let suspicious_patterns = ["/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).
fn detect_ptrace_attachment(pid: u32) -> Result<bool> {
let status_path = format!("/proc/{}/status", pid);
let status_content = fs::read_to_string(&status_path).map_err(|e| {
GhostError::Process {
let status_content = fs::read_to_string(&status_path).map_err(|e| GhostError::Process {
message: format!("Failed to read process status: {}", e),
}
})?;
// Look for TracerPid field
@@ -519,10 +512,8 @@ mod platform {
/// Detect suspicious loaded libraries.
fn detect_suspicious_libraries(pid: u32) -> Result<Vec<HookInfo>> {
let maps_path = format!("/proc/{}/maps", pid);
let maps_content = fs::read_to_string(&maps_path).map_err(|e| {
GhostError::Process {
let maps_content = fs::read_to_string(&maps_path).map_err(|e| GhostError::Process {
message: format!("Failed to read process maps: {}", e),
}
})?;
let mut hooks = Vec::new();
@@ -563,29 +554,23 @@ mod platform {
/// Check if a library path is suspicious.
fn is_suspicious_library(path: &str) -> bool {
// Libraries in these locations are often used for injection
let suspicious_locations = [
"/tmp/",
"/dev/shm/",
"/var/tmp/",
"/home/",
];
let suspicious_locations = ["/tmp/", "/dev/shm/", "/var/tmp/", "/home/"];
// 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;
}
// Check for libraries with suspicious names
let suspicious_names = [
"inject",
"hook",
"cheat",
"hack",
"rootkit",
];
let suspicious_names = ["inject", "hook", "cheat", "hack", "rootkit"];
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 {
@@ -596,7 +581,7 @@ mod platform {
#[cfg(not(any(windows, target_os = "linux")))]
mod platform {
use super::HookDetectionResult;
use crate::{GhostError, Result};
use crate::Result;
pub fn detect_hook_injection(_target_pid: u32) -> Result<HookDetectionResult> {
// 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 behavioral_ml::{
AdvancedBehavioralML, BehavioralAnalysisResult, PredictedTechnique, BehavioralAnomaly,
ModelConsensus, TemporalAnalysis, RiskLevel
AdvancedBehavioralML, BehavioralAnalysisResult, BehavioralAnomaly, ModelConsensus,
PredictedTechnique, RiskLevel, TemporalAnalysis,
};
pub use config::{DetectionConfig, ProcessFilter};
pub use detection::{DetectionEngine, DetectionResult, ThreatLevel};
#[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 evasion::{
EvasionDetector, EvasionResult, EvasionTechnique, EvasionSeverity,
TimingAnalyzer, EnvironmentChecker, BehaviorAnalyzer, ObfuscationDetector
BehaviorAnalyzer, EnvironmentChecker, EvasionDetector, EvasionResult, EvasionSeverity,
EvasionTechnique, ObfuscationDetector, TimingAnalyzer,
};
pub use hollowing::{HollowingDetection, HollowingDetector, HollowingIndicator};
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 mitre_attack::{
MitreAttackEngine, MitreAnalysisResult, AttackTechnique, AttackTactic, ThreatActor,
DetectedTechnique, TacticCoverage, ThreatActorMatch, KillChainAnalysis, RiskAssessment
AttackTactic, AttackTechnique, DetectedTechnique, KillChainAnalysis, MitreAnalysisResult,
MitreAttackEngine, RiskAssessment, TacticCoverage, ThreatActor, ThreatActorMatch,
};
pub use ml_cloud::{CloudMLEngine, InferenceResult, MLModel, ThreatPrediction, ThreatSeverity};
pub use neural_memory::{
NeuralMemoryAnalyzer, NeuralAnalysisResult, DetectedPattern, DetectedEvasion,
PolymorphicIndicator, MemoryAnomaly, NeuralInsights, PatternType, EvasionCategory
DetectedEvasion, DetectedPattern, EvasionCategory, MemoryAnomaly, NeuralAnalysisResult,
NeuralInsights, NeuralMemoryAnalyzer, PatternType, PolymorphicIndicator,
};
pub use process::ProcessInfo;
pub use shellcode::{ShellcodeDetection, ShellcodeDetector};
pub use streaming::{
EventStreamingSystem, EventChannel, StreamingEvent, EventType, EventSeverity,
AlertManager, Alert, AlertRule, CorrelationEngine, NotificationSystem
Alert, AlertManager, AlertRule, CorrelationEngine, EventChannel, EventSeverity,
EventStreamingSystem, EventType, NotificationSystem, StreamingEvent,
};
pub use thread::ThreadInfo;
pub use threat_intel::{
ThreatIntelligence, ThreatContext, IndicatorOfCompromise,
ThreatActor as ThreatIntelActor, Campaign, IocType, SophisticationLevel
Campaign, IndicatorOfCompromise, IocType, SophisticationLevel, ThreatActor as ThreatIntelActor,
ThreatContext, ThreatIntelligence,
};
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 serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, Duration};
use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Serialize, Deserialize)]
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 std::collections::HashMap;
use std::time::{SystemTime, Duration};
use std::time::{Duration, SystemTime};
/// MITRE ATT&CK Framework Integration Engine
/// Provides comprehensive technique mapping, threat actor profiling, and tactical analysis
@@ -74,7 +74,7 @@ pub enum Platform {
Linux,
MacOS,
Android,
iOS,
IOS,
Cloud,
Network,
Container,
@@ -344,7 +344,7 @@ pub enum EvidenceType {
NetworkActivity,
FileSystem,
Registry,
API_Calls,
ApiCalls,
Timing,
}
@@ -370,102 +370,112 @@ impl MitreAttackEngine {
fn initialize_techniques(&mut self) -> Result<(), GhostError> {
// Process Injection (T1055)
self.techniques.insert("T1055".to_string(), AttackTechnique {
self.techniques.insert(
"T1055".to_string(),
AttackTechnique {
id: "T1055".to_string(),
name: "Process Injection".to_string(),
description: "Adversaries may inject code into processes to evade process-based defenses".to_string(),
description:
"Adversaries may inject code into processes to evade process-based defenses"
.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 {
data_sources: vec![DataSource {
name: "Process".to_string(),
data_component: "Process Access".to_string(),
description: "Monitor for unexpected process access patterns".to_string(),
},
],
detection_methods: vec![
DetectionMethod {
}],
detection_methods: vec![DetectionMethod {
method_type: DetectionType::BehavioralAnalysis,
description: "Monitor for unusual cross-process activity".to_string(),
effectiveness: 0.85,
false_positive_rate: 0.1,
},
],
mitigations: vec![
Mitigation {
}],
mitigations: vec![Mitigation {
id: "M1040".to_string(),
name: "Behavior Prevention on Endpoint".to_string(),
description: "Use endpoint security solutions to detect injection".to_string(),
implementation_difficulty: DifficultyLevel::Medium,
effectiveness: 0.8,
},
],
}],
sub_techniques: vec!["T1055.001".to_string(), "T1055.002".to_string()],
kill_chain_phases: vec![KillChainPhase::Installation, KillChainPhase::ActionsOnObjectives],
kill_chain_phases: vec![
KillChainPhase::Installation,
KillChainPhase::ActionsOnObjectives,
],
threat_actors: vec!["APT1".to_string(), "APT29".to_string()],
references: vec![
Reference {
references: vec![Reference {
source: "MITRE ATT&CK".to_string(),
url: "https://attack.mitre.org/techniques/T1055/".to_string(),
description: "Process Injection".to_string(),
}],
},
],
});
);
// Process Hollowing (T1055.012)
self.techniques.insert("T1055.012".to_string(), AttackTechnique {
self.techniques.insert(
"T1055.012".to_string(),
AttackTechnique {
id: "T1055.012".to_string(),
name: "Process Hollowing".to_string(),
description: "Adversaries may inject malicious code into suspended and hollowed processes".to_string(),
description:
"Adversaries may inject malicious code into suspended and hollowed processes"
.to_string(),
tactics: vec!["TA0004".to_string(), "TA0005".to_string()],
platforms: vec![Platform::Windows],
data_sources: vec![
DataSource {
data_sources: vec![DataSource {
name: "Process".to_string(),
data_component: "Process Creation".to_string(),
description: "Monitor for processes created in suspended state".to_string(),
},
],
detection_methods: vec![
DetectionMethod {
}],
detection_methods: vec![DetectionMethod {
method_type: DetectionType::EndpointDetection,
description: "Detect hollowing through memory analysis".to_string(),
effectiveness: 0.9,
false_positive_rate: 0.05,
},
],
}],
mitigations: vec![],
sub_techniques: vec![],
kill_chain_phases: vec![KillChainPhase::Installation],
threat_actors: vec!["APT29".to_string(), "Lazarus Group".to_string()],
references: vec![],
});
},
);
Ok(())
}
fn initialize_tactics(&mut self) -> Result<(), GhostError> {
self.tactics.insert("TA0004".to_string(), AttackTactic {
self.tactics.insert(
"TA0004".to_string(),
AttackTactic {
id: "TA0004".to_string(),
name: "Defense Evasion".to_string(),
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(
"TA0005".to_string(),
AttackTactic {
id: "TA0005".to_string(),
name: "Privilege Escalation".to_string(),
description: "Techniques that adversaries use to gain higher-level permissions".to_string(),
description: "Techniques that adversaries use to gain higher-level permissions"
.to_string(),
techniques: vec!["T1055".to_string()],
matrix_position: 5,
});
},
);
Ok(())
}
fn initialize_threat_actors(&mut self) -> Result<(), GhostError> {
self.threat_actors.insert("APT29".to_string(), ThreatActor {
self.threat_actors.insert(
"APT29".to_string(),
ThreatActor {
id: "G0016".to_string(),
name: "APT29".to_string(),
aliases: vec!["Cozy Bear".to_string(), "The Dukes".to_string()],
@@ -477,7 +487,8 @@ impl MitreAttackEngine {
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(())
}
@@ -501,7 +512,9 @@ impl MitreAttackEngine {
memory_regions: &[MemoryRegion],
threads: &[ThreadInfo],
) -> 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 threat_actor_matches = self.match_threat_actors(&detected_techniques)?;
let campaign_indicators = self.analyze_campaign_indicators(&detected_techniques)?;
@@ -529,8 +542,13 @@ impl MitreAttackEngine {
let mut detected = Vec::new();
// Check for Process Injection indicators
let rwx_regions = memory_regions.iter()
.filter(|r| r.protection.is_readable() && r.protection.is_writable() && r.protection.is_executable())
let rwx_regions = memory_regions
.iter()
.filter(|r| {
r.protection.is_readable()
&& r.protection.is_writable()
&& r.protection.is_executable()
})
.count();
if rwx_regions > 0 {
@@ -538,14 +556,12 @@ impl MitreAttackEngine {
detected.push(DetectedTechnique {
technique: technique.clone(),
confidence: 0.8,
evidence: vec![
Evidence {
evidence: vec![Evidence {
evidence_type: EvidenceType::MemoryPattern,
description: format!("Found {} RWX memory regions", rwx_regions),
confidence: 0.9,
source: "Memory Analysis".to_string(),
},
],
}],
sub_technique_id: None,
detection_timestamp: SystemTime::now(),
});
@@ -558,14 +574,13 @@ impl MitreAttackEngine {
detected.push(DetectedTechnique {
technique: technique.clone(),
confidence: 0.7,
evidence: vec![
Evidence {
evidence: vec![Evidence {
evidence_type: EvidenceType::ProcessBehavior,
description: "Suspicious memory layout consistent with hollowing".to_string(),
description: "Suspicious memory layout consistent with hollowing"
.to_string(),
confidence: 0.7,
source: "Process Analysis".to_string(),
},
],
}],
sub_technique_id: Some("T1055.012".to_string()),
detection_timestamp: SystemTime::now(),
});
@@ -575,11 +590,15 @@ impl MitreAttackEngine {
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();
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))
.count();
@@ -601,17 +620,22 @@ impl MitreAttackEngine {
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();
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))
.map(|dt| dt.technique.id.clone())
.collect();
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 {
threat_actor: actor.clone(),
@@ -625,11 +649,17 @@ impl MitreAttackEngine {
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
}
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();
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 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 {
0.0
};
@@ -676,17 +713,18 @@ impl MitreAttackEngine {
attack_likelihood: avg_confidence,
potential_impact: 0.8, // Simulated
urgency_level,
risk_factors: vec![
RiskFactor {
risk_factors: vec![RiskFactor {
factor_name: "Multiple Techniques Detected".to_string(),
risk_contribution: 0.6,
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();
for technique in detected_techniques {
@@ -719,6 +757,10 @@ impl MitreAttackEngine {
}
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 std::collections::HashMap;
use std::time::{SystemTime, Duration};
use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudMLEngine {
@@ -112,7 +112,10 @@ impl CloudMLEngine {
// Simulate ML inference
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
} else if memory_regions.len() > 50 {
ThreatSeverity::Medium
@@ -122,13 +125,11 @@ impl CloudMLEngine {
let prediction = ThreatPrediction {
threat_level,
technique_predictions: vec![
TechniquePrediction {
technique_predictions: vec![TechniquePrediction {
technique_id: "T1055".to_string(),
technique_name: "Process Injection".to_string(),
confidence: 0.85,
},
],
}],
anomaly_score: 0.75,
};
@@ -140,11 +141,14 @@ impl CloudMLEngine {
};
// Cache result
self.cache.insert(cache_key, CachedPrediction {
self.cache.insert(
cache_key,
CachedPrediction {
result: result.clone(),
timestamp: SystemTime::now(),
ttl: Duration::from_secs(300), // 5 minutes
});
},
);
Ok(result)
}

View File

@@ -1,7 +1,6 @@
use crate::{ProcessInfo, MemoryRegion, GhostError};
use crate::{GhostError, MemoryRegion, ProcessInfo};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, Duration};
#[derive(Debug)]
pub struct NeuralMemoryAnalyzer {
@@ -143,7 +142,7 @@ impl NeuralMemoryAnalyzer {
pub async fn analyze_memory_regions(
&mut self,
process: &ProcessInfo,
_process: &ProcessInfo,
memory_regions: &[MemoryRegion],
) -> Result<NeuralAnalysisResult, GhostError> {
// Extract features
@@ -178,15 +177,23 @@ impl NeuralMemoryAnalyzer {
features.push(memory_regions.len() as f32);
// Protection features
let rwx_count = memory_regions.iter()
.filter(|r| r.protection.is_readable() && r.protection.is_writable() && r.protection.is_executable())
let rwx_count = memory_regions
.iter()
.filter(|r| {
r.protection.is_readable()
&& r.protection.is_writable()
&& r.protection.is_executable()
})
.count() as f32;
features.push(rwx_count);
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();
for network in &self.neural_networks {
@@ -197,7 +204,11 @@ impl NeuralMemoryAnalyzer {
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
Ok(ModelPrediction {
@@ -213,7 +224,8 @@ impl NeuralMemoryAnalyzer {
return 0.0;
}
let weighted_sum: f32 = predictions.iter()
let weighted_sum: f32 = predictions
.iter()
.map(|p| p.prediction * 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,
TH32CS_SNAPPROCESS,
};
use windows::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION};
use windows::Win32::System::ProcessStatus::GetProcessImageFileNameW;
use windows::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION};
pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> {
let mut processes = Vec::new();
@@ -163,13 +163,14 @@ mod platform {
fn get_process_info(pid: u32) -> Result<ProcessInfo> {
let stat_path = format!("/proc/{}/stat", pid);
let stat_content =
fs::read_to_string(&stat_path).context("Failed to read process stat")?;
let stat_content = fs::read_to_string(&stat_path).context("Failed to read process stat")?;
let (name, ppid, thread_count) = parse_stat(&stat_content)?;
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 {
pid,
@@ -219,7 +220,9 @@ mod platform {
use anyhow::Result;
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)]
pub struct ShellcodeSignature {
pub pattern: Vec<u8>,
@@ -17,6 +15,7 @@ pub struct ShellcodeDetection {
}
/// Common shellcode patterns and signatures
#[derive(Debug)]
pub struct ShellcodeDetector {
signatures: Vec<ShellcodeSignature>,
}
@@ -298,8 +297,12 @@ impl ShellcodeDetector {
// Linux x64 execve pattern
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"
mask: vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
pattern: vec![
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",
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 {
return None;
}
@@ -479,10 +486,10 @@ impl ShellcodeDetector {
match data[i] {
0xEB => suspicious_instructions += 1, // Short 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
}
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
}
_ => {}

View File

@@ -1,9 +1,9 @@
use crate::{DetectionResult, EvasionResult, ProcessInfo, ThreatContext, ThreatLevel};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, Duration};
use std::time::{Duration, SystemTime};
use tokio::sync::{broadcast, mpsc};
use serde::{Serialize, Deserialize};
use crate::{DetectionResult, ThreatLevel, ProcessInfo, ThreatContext, EvasionResult};
/// Real-time Event Streaming and Alerting System
/// Provides configurable alerting, correlation, and notification capabilities
@@ -519,6 +519,12 @@ pub struct EventBuffer {
retention_period: Duration,
}
impl Default for EventStreamingSystem {
fn default() -> Self {
Self::new()
}
}
impl EventStreamingSystem {
pub fn new() -> Self {
Self {
@@ -526,12 +532,18 @@ impl EventStreamingSystem {
alert_manager: AlertManager::new(),
correlation_engine: CorrelationEngine::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
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 {
event_id: format!("det_{}", uuid::Uuid::new_v4()),
timestamp: SystemTime::now(),
@@ -556,11 +568,16 @@ impl EventStreamingSystem {
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
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 {
EventSeverity::Critical
} else if evasion.sophistication_score > 0.6 {
@@ -589,11 +606,16 @@ impl EventStreamingSystem {
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
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
{
let mut buffer = self.event_buffer.lock().unwrap();
@@ -614,7 +636,10 @@ impl EventStreamingSystem {
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);
// Create alert for correlated incident
@@ -653,6 +678,12 @@ impl EventStreamingSystem {
}
}
impl Default for EventPublisher {
fn default() -> Self {
Self::new()
}
}
impl EventPublisher {
pub fn new() -> 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) {
sender.send(event)?;
}
@@ -669,8 +704,7 @@ impl EventPublisher {
}
pub fn subscribe(&mut self, channel: EventChannel) -> broadcast::Receiver<StreamingEvent> {
let sender = self.channels.entry(channel.clone())
.or_insert_with(|| {
let sender = self.channels.entry(channel.clone()).or_insert_with(|| {
let (tx, _) = broadcast::channel(1000);
tx
});
@@ -681,6 +715,12 @@ impl EventPublisher {
}
}
impl Default for AlertManager {
fn default() -> Self {
Self::new()
}
}
impl AlertManager {
pub fn new() -> Self {
Self {
@@ -691,8 +731,13 @@ impl AlertManager {
}
}
pub async fn evaluate_alerts(&mut self, event: &StreamingEvent) -> Result<(), Box<dyn std::error::Error>> {
let triggered_rules: Vec<AlertRule> = self.alert_rules.iter()
pub async fn evaluate_alerts(
&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))
.cloned()
.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 {
alert_id: format!("alert_{}", uuid::Uuid::new_v4()),
rule_id: rule.rule_id.clone(),
@@ -769,13 +818,20 @@ impl AlertManager {
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);
Ok(())
}
}
impl Default for CorrelationEngine {
fn default() -> Self {
Self::new()
}
}
impl CorrelationEngine {
pub fn new() -> 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
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;
let incident_id = format!("incident_{}", self.incident_tracker.incident_counter);
@@ -810,7 +869,9 @@ impl CorrelationEngine {
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));
}
}
@@ -818,13 +879,23 @@ impl CorrelationEngine {
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
// In a real implementation, this would be much more sophisticated
Some(())
}
}
impl Default for NotificationSystem {
fn default() -> Self {
Self::new()
}
}
impl NotificationSystem {
pub fn new() -> Self {
let (tx, _) = mpsc::channel(1000);
@@ -836,20 +907,35 @@ impl NotificationSystem {
}
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));
}
pub fn add_slack_channel(&mut self, name: String, webhook_url: String, default_channel: String) {
let channel = SlackChannel { webhook_url, default_channel };
pub fn add_slack_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));
}
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 {
endpoint_url,
headers,
auth_token: None
auth_token: None,
};
self.channels.insert(name, Box::new(channel));
}
@@ -879,7 +965,8 @@ impl EventBuffer {
pub fn get_events_in_window(&self, window: Duration) -> Vec<&StreamingEvent> {
let cutoff_time = SystemTime::now() - window;
self.events.iter()
self.events
.iter()
.filter(|e| e.timestamp >= cutoff_time)
.collect()
}

View File

@@ -1,9 +1,9 @@
use crate::{
DetectionEngine, DetectionResult, MemoryProtection, MemoryRegion, ProcessInfo, ThreadInfo,
ThreatLevel,
};
use std::collections::HashMap;
use std::time::{Duration, Instant};
use crate::{
DetectionEngine, DetectionResult, ThreatLevel, ProcessInfo, MemoryRegion,
ThreadInfo, MemoryProtection, EvasionResult, ThreatContext
};
/// Comprehensive Testing Framework for Ghost Detection Engine
/// Provides unit tests, integration tests, and performance benchmarks
@@ -205,10 +205,10 @@ pub struct MemoryScanningBenchmark {
#[derive(Debug, Clone)]
pub enum ScanAlgorithm {
Linear,
Boyer_Moore,
Knuth_Morris_Pratt,
Aho_Corasick,
SIMD_Optimized,
BoyerMoore,
KnuthMorrisPratt,
AhoCorasick,
SimdOptimized,
}
#[derive(Debug, Clone)]
@@ -367,6 +367,12 @@ pub struct ValidationDetails {
pub false_negative_rate: f32,
}
impl Default for TestFramework {
fn default() -> Self {
Self::new()
}
}
impl TestFramework {
pub fn new() -> Self {
Self {
@@ -404,24 +410,20 @@ impl TestFramework {
thread_count: 1,
suspicious_indicators: Vec::new(),
},
memory_data: vec![
MemoryTestData {
memory_data: vec![MemoryTestData {
base_address: 0x400000,
size: 0x10000,
protection: MemoryProtection::ReadExecute,
contains_shellcode: false,
shellcode_pattern: None,
}
],
thread_data: vec![
ThreadTestData {
}],
thread_data: vec![ThreadTestData {
tid: 5678,
entry_point: 0x401000,
stack_base: 0x500000,
stack_size: 0x10000,
is_suspicious: false,
}
],
}],
injection_type: None,
}),
expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Clean),
@@ -444,29 +446,29 @@ impl TestFramework {
"Suspicious API calls".to_string(),
],
},
memory_data: vec![
MemoryTestData {
memory_data: vec![MemoryTestData {
base_address: 0x200000,
size: 0x1000,
protection: MemoryProtection::ReadWriteExecute,
contains_shellcode: true,
shellcode_pattern: Some(vec![0x90, 0x90, 0xEB, 0xFE]), // NOP NOP JMP -2
}
],
thread_data: vec![
ThreadTestData {
}],
thread_data: vec![ThreadTestData {
tid: 1111,
entry_point: 0x200000,
stack_base: 0x600000,
stack_size: 0x10000,
is_suspicious: true,
}
],
}],
injection_type: Some(InjectionTestType::ShellcodeInjection),
}),
expected_result: ExpectedResult::ThreatLevel(ThreatLevel::Malicious),
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 {
@@ -477,7 +479,8 @@ impl TestFramework {
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
@@ -496,8 +499,7 @@ impl TestFramework {
thread_count: 1,
suspicious_indicators: Vec::new(),
},
memory_data: vec![
MemoryTestData {
memory_data: vec![MemoryTestData {
base_address: 0x300000,
size: 0x1000,
protection: MemoryProtection::ReadWriteExecute,
@@ -508,8 +510,7 @@ impl TestFramework {
0x68, 0x2F, 0x2F, 0x73, 0x68, // PUSH //sh
0x68, 0x2F, 0x62, 0x69, 0x6E, // PUSH /bin
]),
}
],
}],
thread_data: Vec::new(),
injection_type: Some(InjectionTestType::ShellcodeInjection),
}),
@@ -526,7 +527,8 @@ impl TestFramework {
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
@@ -547,15 +549,13 @@ impl TestFramework {
"Unexpected memory layout".to_string(),
],
},
memory_data: vec![
MemoryTestData {
memory_data: vec![MemoryTestData {
base_address: 0x400000,
size: 0x20000,
protection: MemoryProtection::ReadWriteExecute,
contains_shellcode: false,
shellcode_pattern: None,
}
],
}],
thread_data: Vec::new(),
injection_type: Some(InjectionTestType::ProcessHollowing),
}),
@@ -572,7 +572,8 @@ impl TestFramework {
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
@@ -610,7 +611,8 @@ impl TestFramework {
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
@@ -626,12 +628,10 @@ impl TestFramework {
benchmarks.push(Benchmark {
name: "single_process_analysis".to_string(),
description: "Benchmark single process analysis performance".to_string(),
benchmark_function: BenchmarkFunction::ProcessAnalysis(
ProcessAnalysisBenchmark {
benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark {
process_count: 1,
complexity_level: ComplexityLevel::Moderate,
}
),
}),
warm_up_iterations: 10,
measurement_iterations: 100,
target_metrics: vec![
@@ -644,12 +644,10 @@ impl TestFramework {
benchmarks.push(Benchmark {
name: "bulk_process_analysis".to_string(),
description: "Benchmark bulk process analysis performance".to_string(),
benchmark_function: BenchmarkFunction::ProcessAnalysis(
ProcessAnalysisBenchmark {
benchmark_function: BenchmarkFunction::ProcessAnalysis(ProcessAnalysisBenchmark {
process_count: 100,
complexity_level: ComplexityLevel::Simple,
}
),
}),
warm_up_iterations: 5,
measurement_iterations: 20,
target_metrics: vec![
@@ -666,7 +664,8 @@ impl TestFramework {
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
@@ -714,14 +713,17 @@ impl TestFramework {
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
pub fn run_all_tests(&mut self) -> TestRunReport {
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()))
.collect();
@@ -764,15 +766,11 @@ impl TestFramework {
TestFunction::DetectionTest(params) => {
self.run_detection_test(params, &test_case.expected_result)
}
TestFunction::PerformanceTest(params) => {
self.run_performance_test(params)
}
TestFunction::PerformanceTest(params) => self.run_performance_test(params),
TestFunction::IntegrationTest(params) => {
self.run_integration_test(params, &test_case.expected_result)
}
TestFunction::StressTest(params) => {
self.run_stress_test(params)
}
TestFunction::StressTest(params) => self.run_stress_test(params),
};
let execution_time = start_time.elapsed();
@@ -793,7 +791,11 @@ impl TestFramework {
}
/// 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
let mut engine = match DetectionEngine::new() {
Ok(engine) => engine,
@@ -809,24 +811,28 @@ impl TestFramework {
thread_count: params.process_data.thread_count,
};
let memory_regions: Vec<MemoryRegion> = params.memory_data.iter().map(|mem| {
MemoryRegion {
let memory_regions: Vec<MemoryRegion> = params
.memory_data
.iter()
.map(|mem| MemoryRegion {
base_address: mem.base_address,
size: mem.size,
protection: mem.protection.clone(),
protection: mem.protection,
region_type: "PRIVATE".to_string(),
}
}).collect();
})
.collect();
let threads: Vec<ThreadInfo> = params.thread_data.iter().map(|thread| {
ThreadInfo {
let threads: Vec<ThreadInfo> = params
.thread_data
.iter()
.map(|thread| ThreadInfo {
tid: thread.tid,
owner_pid: process_info.pid,
start_address: thread.entry_point,
creation_time: 0,
state: crate::thread::ThreadState::Running,
}
}).collect();
})
.collect();
// Run detection
let result = engine.analyze_process(&process_info, &memory_regions, Some(&threads));
@@ -878,7 +884,11 @@ impl TestFramework {
}
/// 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
TestStatus::Passed
}
@@ -901,6 +911,12 @@ pub struct TestRunReport {
pub suite_results: HashMap<String, Vec<TestResult>>,
}
impl Default for TestRunReport {
fn default() -> Self {
Self::new()
}
}
impl TestRunReport {
pub fn new() -> Self {
Self {
@@ -937,6 +953,12 @@ impl TestRunReport {
}
}
impl Default for TestDataGenerator {
fn default() -> Self {
Self::new()
}
}
impl TestDataGenerator {
pub fn new() -> Self {
Self {
@@ -947,7 +969,7 @@ impl TestDataGenerator {
}
/// 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
Vec::new()
}
@@ -962,6 +984,12 @@ impl TestDataGenerator {
}
}
impl Default for PerformanceProfiler {
fn default() -> Self {
Self::new()
}
}
impl PerformanceProfiler {
pub fn new() -> Self {
Self {
@@ -983,7 +1011,9 @@ impl PerformanceProfiler {
/// Stop profiling and collect results
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

View File

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

View File

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

View File

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