add dynamic YARA rule engine
This commit is contained in:
159
ghost-core/src/yara_engine.rs
Normal file
159
ghost-core/src/yara_engine.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use crate::{ProcessInfo, MemoryRegion, GhostError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::time::SystemTime;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DynamicYaraEngine {
|
||||
rules: Vec<YaraRule>,
|
||||
sources: Vec<YaraRuleSource>,
|
||||
scan_cache: HashMap<String, CachedScanResult>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct YaraRule {
|
||||
pub name: String,
|
||||
pub content: String,
|
||||
pub source: String,
|
||||
pub threat_level: ThreatLevel,
|
||||
pub last_updated: SystemTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct YaraRuleSource {
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub enabled: bool,
|
||||
pub rule_count: usize,
|
||||
pub last_update: SystemTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct YaraScanResult {
|
||||
pub matches: Vec<RuleMatch>,
|
||||
pub scan_time_ms: u64,
|
||||
pub bytes_scanned: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RuleMatch {
|
||||
pub rule_name: String,
|
||||
pub threat_level: ThreatLevel,
|
||||
pub offset: u64,
|
||||
pub length: u32,
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum ThreatLevel {
|
||||
Info = 1,
|
||||
Low = 2,
|
||||
Medium = 3,
|
||||
High = 4,
|
||||
Critical = 5,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct CachedScanResult {
|
||||
result: YaraScanResult,
|
||||
timestamp: SystemTime,
|
||||
}
|
||||
|
||||
impl DynamicYaraEngine {
|
||||
pub fn new(config_path: Option<&str>) -> Result<Self, GhostError> {
|
||||
let sources = vec![
|
||||
YaraRuleSource {
|
||||
name: "Malware Bazaar".to_string(),
|
||||
url: "https://bazaar.abuse.ch/browse/".to_string(),
|
||||
enabled: true,
|
||||
rule_count: 0,
|
||||
last_update: SystemTime::now(),
|
||||
},
|
||||
YaraRuleSource {
|
||||
name: "VX-Underground".to_string(),
|
||||
url: "https://vx-underground.org/yara".to_string(),
|
||||
enabled: true,
|
||||
rule_count: 0,
|
||||
last_update: SystemTime::now(),
|
||||
},
|
||||
];
|
||||
|
||||
Ok(DynamicYaraEngine {
|
||||
rules: Vec::new(),
|
||||
sources,
|
||||
scan_cache: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn update_rules(&mut self) -> Result<usize, GhostError> {
|
||||
let mut updated_count = 0;
|
||||
|
||||
for source in &mut self.sources {
|
||||
if !source.enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Simulate rule download
|
||||
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();
|
||||
source.last_update = SystemTime::now();
|
||||
updated_count += 1;
|
||||
}
|
||||
|
||||
Ok(updated_count)
|
||||
}
|
||||
|
||||
pub async fn scan_process(
|
||||
&self,
|
||||
process: &ProcessInfo,
|
||||
memory_regions: &[MemoryRegion],
|
||||
) -> Result<YaraScanResult, GhostError> {
|
||||
let start_time = SystemTime::now();
|
||||
let mut matches = Vec::new();
|
||||
let mut bytes_scanned = 0;
|
||||
|
||||
// Simulate YARA scanning
|
||||
for (i, region) in memory_regions.iter().enumerate() {
|
||||
bytes_scanned += region.size;
|
||||
|
||||
// Simulate finding suspicious patterns
|
||||
if region.protection.executable && region.protection.writable {
|
||||
matches.push(RuleMatch {
|
||||
rule_name: "suspicious_rwx_memory".to_string(),
|
||||
threat_level: ThreatLevel::High,
|
||||
offset: region.base_address,
|
||||
length: 1024,
|
||||
metadata: HashMap::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let scan_time_ms = start_time.elapsed()
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64;
|
||||
|
||||
Ok(YaraScanResult {
|
||||
matches,
|
||||
scan_time_ms,
|
||||
bytes_scanned,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_rule_count(&self) -> usize {
|
||||
self.rules.len()
|
||||
}
|
||||
|
||||
pub fn get_sources(&self) -> &[YaraRuleSource] {
|
||||
&self.sources
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user