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