Fix all syntax errors and apply cargo fmt
This commit is contained in:
@@ -586,24 +586,32 @@ fn parse_pe_sections(data: &[u8]) -> Result<Vec<PESection>> {
|
|||||||
use crate::GhostError;
|
use crate::GhostError;
|
||||||
|
|
||||||
if data.len() < 0x40 {
|
if data.len() < 0x40 {
|
||||||
return Err(GhostError::InvalidInput { message: "Buffer too small".to_string() });
|
return Err(GhostError::InvalidInput {
|
||||||
|
message: "Buffer too small".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check DOS signature
|
// Check DOS signature
|
||||||
if &data[0..2] != b"MZ" {
|
if &data[0..2] != b"MZ" {
|
||||||
return Err(GhostError::InvalidInput { message: "Invalid DOS signature".to_string() });
|
return Err(GhostError::InvalidInput {
|
||||||
|
message: "Invalid DOS signature".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get PE offset
|
// Get PE offset
|
||||||
let pe_offset = u32::from_le_bytes([data[0x3c], data[0x3d], data[0x3e], data[0x3f]]) as usize;
|
let pe_offset = u32::from_le_bytes([data[0x3c], data[0x3d], data[0x3e], data[0x3f]]) as usize;
|
||||||
|
|
||||||
if pe_offset + 0x18 >= data.len() {
|
if pe_offset + 0x18 >= data.len() {
|
||||||
return Err(GhostError::InvalidInput { message: "Invalid PE offset".to_string() });
|
return Err(GhostError::InvalidInput {
|
||||||
|
message: "Invalid PE offset".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check PE signature
|
// Check PE signature
|
||||||
if &data[pe_offset..pe_offset + 4] != b"PE\0\0" {
|
if &data[pe_offset..pe_offset + 4] != b"PE\0\0" {
|
||||||
return Err(GhostError::InvalidInput { message: "Invalid PE signature".to_string() });
|
return Err(GhostError::InvalidInput {
|
||||||
|
message: "Invalid PE signature".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse COFF header
|
// Parse COFF header
|
||||||
|
|||||||
@@ -115,9 +115,12 @@ impl LiveThreatFeeds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_abuseipdb(&self, feed: &ThreatFeed) -> Result<Vec<CachedIOC>, GhostError> {
|
async fn fetch_abuseipdb(&self, feed: &ThreatFeed) -> Result<Vec<CachedIOC>, GhostError> {
|
||||||
let api_key = feed.api_key.as_ref().ok_or_else(|| {
|
let api_key = feed
|
||||||
GhostError::Configuration { message: "AbuseIPDB requires API key".to_string() }
|
.api_key
|
||||||
})?;
|
.as_ref()
|
||||||
|
.ok_or_else(|| GhostError::Configuration {
|
||||||
|
message: "AbuseIPDB requires API key".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let url = format!("{}/blacklist", feed.url);
|
let url = format!("{}/blacklist", feed.url);
|
||||||
@@ -129,18 +132,23 @@ impl LiveThreatFeeds {
|
|||||||
.query(&[("confidenceMinimum", "90")])
|
.query(&[("confidenceMinimum", "90")])
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| GhostError::ThreatIntel { message: format!("AbuseIPDB request failed: {}", e) })?;
|
.map_err(|e| GhostError::ThreatIntel {
|
||||||
|
message: format!("AbuseIPDB request failed: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(GhostError::ThreatIntel { message: format!(
|
return Err(GhostError::ThreatIntel {
|
||||||
"AbuseIPDB API returned status: {}",
|
message: format!("AbuseIPDB API returned status: {}", response.status()),
|
||||||
response.status()
|
});
|
||||||
) });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: serde_json::Value = response.json().await.map_err(|e| {
|
let data: serde_json::Value =
|
||||||
GhostError::Serialization { message: format!("Failed to parse AbuseIPDB response: {}", e) }
|
response
|
||||||
})?;
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| GhostError::Serialization {
|
||||||
|
message: format!("Failed to parse AbuseIPDB response: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut iocs = Vec::new();
|
let mut iocs = Vec::new();
|
||||||
|
|
||||||
@@ -187,20 +195,23 @@ impl LiveThreatFeeds {
|
|||||||
.json(&serde_json::json!({ "query": "get_recent", "selector": "100" }))
|
.json(&serde_json::json!({ "query": "get_recent", "selector": "100" }))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| GhostError::ThreatIntel {
|
||||||
GhostError::ThreatIntel { message: format!("MalwareBazaar request failed: {}", e) }
|
message: format!("MalwareBazaar request failed: {}", e),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(GhostError::ThreatIntel { message: format!(
|
return Err(GhostError::ThreatIntel {
|
||||||
"MalwareBazaar API returned status: {}",
|
message: format!("MalwareBazaar API returned status: {}", response.status()),
|
||||||
response.status()
|
});
|
||||||
) });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: serde_json::Value = response.json().await.map_err(|e| {
|
let data: serde_json::Value =
|
||||||
GhostError::Serialization { message: format!("Failed to parse MalwareBazaar response: {}", e) }
|
response
|
||||||
})?;
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| GhostError::Serialization {
|
||||||
|
message: format!("Failed to parse MalwareBazaar response: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut iocs = Vec::new();
|
let mut iocs = Vec::new();
|
||||||
|
|
||||||
@@ -236,9 +247,12 @@ impl LiveThreatFeeds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_alienvault(&self, feed: &ThreatFeed) -> Result<Vec<CachedIOC>, GhostError> {
|
async fn fetch_alienvault(&self, feed: &ThreatFeed) -> Result<Vec<CachedIOC>, GhostError> {
|
||||||
let api_key = feed.api_key.as_ref().ok_or_else(|| {
|
let api_key = feed
|
||||||
GhostError::Configuration { message: "AlienVault OTX requires API key".to_string() }
|
.api_key
|
||||||
})?;
|
.as_ref()
|
||||||
|
.ok_or_else(|| GhostError::Configuration {
|
||||||
|
message: "AlienVault OTX requires API key".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let url = format!("{}/pulses/subscribed", feed.url);
|
let url = format!("{}/pulses/subscribed", feed.url);
|
||||||
@@ -250,18 +264,23 @@ impl LiveThreatFeeds {
|
|||||||
.query(&[("limit", "50")])
|
.query(&[("limit", "50")])
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| GhostError::ThreatIntel { message: format!("AlienVault request failed: {}", e) })?;
|
.map_err(|e| GhostError::ThreatIntel {
|
||||||
|
message: format!("AlienVault request failed: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(GhostError::ThreatIntel { message: format!(
|
return Err(GhostError::ThreatIntel {
|
||||||
"AlienVault API returned status: {}",
|
message: format!("AlienVault API returned status: {}", response.status()),
|
||||||
response.status()
|
});
|
||||||
) });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: serde_json::Value = response.json().await.map_err(|e| {
|
let data: serde_json::Value =
|
||||||
GhostError::Serialization { message: format!("Failed to parse AlienVault response: {}", e) }
|
response
|
||||||
})?;
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| GhostError::Serialization {
|
||||||
|
message: format!("Failed to parse AlienVault response: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut iocs = Vec::new();
|
let mut iocs = Vec::new();
|
||||||
|
|
||||||
|
|||||||
@@ -434,7 +434,9 @@ pub fn parse_iat_from_memory(
|
|||||||
_base_address: usize,
|
_base_address: usize,
|
||||||
_memory_reader: impl Fn(u32, usize, usize) -> Result<Vec<u8>>,
|
_memory_reader: impl Fn(u32, usize, usize) -> Result<Vec<u8>>,
|
||||||
) -> Result<Vec<ImportEntry>> {
|
) -> Result<Vec<ImportEntry>> {
|
||||||
Err(GhostError::PlatformNotSupported { feature: "IAT parsing not implemented for this platform".to_string() })
|
Err(GhostError::PlatformNotSupported {
|
||||||
|
feature: "IAT parsing not implemented for this platform".to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@@ -444,5 +446,7 @@ pub fn detect_iat_hooks(
|
|||||||
_disk_path: &str,
|
_disk_path: &str,
|
||||||
_memory_reader: impl Fn(u32, usize, usize) -> Result<Vec<u8>>,
|
_memory_reader: impl Fn(u32, usize, usize) -> Result<Vec<u8>>,
|
||||||
) -> Result<IATHookResult> {
|
) -> Result<IATHookResult> {
|
||||||
Err(GhostError::PlatformNotSupported { feature: "IAT hook detection not implemented for this platform".to_string() })
|
Err(GhostError::PlatformNotSupported {
|
||||||
|
feature: "IAT hook detection not implemented for this platform".to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,9 +118,12 @@ impl DynamicYaraEngine {
|
|||||||
|
|
||||||
/// Compile all YARA rules from the rules directory
|
/// Compile all YARA rules from the rules directory
|
||||||
pub fn compile_rules(&mut self) -> Result<usize, GhostError> {
|
pub fn compile_rules(&mut self) -> Result<usize, GhostError> {
|
||||||
let rules_dir = self.rules_path.as_ref().ok_or_else(|| {
|
let rules_dir = self
|
||||||
GhostError::Configuration { message: "No rules directory configured".to_string() }
|
.rules_path
|
||||||
})?;
|
.as_ref()
|
||||||
|
.ok_or_else(|| GhostError::Configuration {
|
||||||
|
message: "No rules directory configured".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
if !rules_dir.exists() {
|
if !rules_dir.exists() {
|
||||||
return Err(GhostError::ConfigurationError(format!(
|
return Err(GhostError::ConfigurationError(format!(
|
||||||
@@ -129,8 +132,9 @@ impl DynamicYaraEngine {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut compiler = Compiler::new()
|
let mut compiler = Compiler::new().map_err(|e| GhostError::Configuration {
|
||||||
.map_err(|e| GhostError::Configuration { message: format!("YARA compiler error: {}", e) })?;
|
message: format!("YARA compiler error: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut rule_count = 0;
|
let mut rule_count = 0;
|
||||||
self.rule_metadata.clear();
|
self.rule_metadata.clear();
|
||||||
@@ -176,9 +180,14 @@ impl DynamicYaraEngine {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compiled_rules = Some(compiler.compile_rules().map_err(|e| {
|
self.compiled_rules =
|
||||||
GhostError::Configuration { message: format!("Rule compilation failed: {}", e })
|
Some(
|
||||||
})?);
|
compiler
|
||||||
|
.compile_rules()
|
||||||
|
.map_err(|e| GhostError::Configuration {
|
||||||
|
message: format!("Rule compilation failed: {}", e),
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
|
||||||
log::info!("Successfully compiled {} YARA rules", rule_count);
|
log::info!("Successfully compiled {} YARA rules", rule_count);
|
||||||
Ok(rule_count)
|
Ok(rule_count)
|
||||||
@@ -192,8 +201,8 @@ impl DynamicYaraEngine {
|
|||||||
return Ok(rule_files);
|
return Ok(rule_files);
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries = fs::read_dir(dir).map_err(|e| {
|
let entries = fs::read_dir(dir).map_err(|e| GhostError::Configuration {
|
||||||
GhostError::Configuration { message: format!("Failed to read rules directory: {}", e })
|
message: format!("Failed to read rules directory: {}", e),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for entry in entries.flatten() {
|
for entry in entries.flatten() {
|
||||||
@@ -225,7 +234,9 @@ impl DynamicYaraEngine {
|
|||||||
let rules = self
|
let rules = self
|
||||||
.compiled_rules
|
.compiled_rules
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| GhostError::Configuration { message: "YARA rules not compiled".to_string( }))?;
|
.ok_or_else(|| GhostError::Configuration {
|
||||||
|
message: "YARA rules not compiled".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut all_matches = Vec::new();
|
let mut all_matches = Vec::new();
|
||||||
let mut bytes_scanned = 0u64;
|
let mut bytes_scanned = 0u64;
|
||||||
@@ -287,12 +298,13 @@ impl DynamicYaraEngine {
|
|||||||
data: &[u8],
|
data: &[u8],
|
||||||
base_address: usize,
|
base_address: usize,
|
||||||
) -> Result<Vec<RuleMatch>, GhostError> {
|
) -> Result<Vec<RuleMatch>, GhostError> {
|
||||||
let mut scanner = Scanner::new(rules)
|
let mut scanner = Scanner::new(rules).map_err(|e| GhostError::Detection {
|
||||||
.map_err(|e| GhostError::Detection { message: format!("Scanner creation failed: {}", e }))?;
|
message: format!("Scanner creation failed: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
let scan_results = scanner
|
let scan_results = scanner.scan_mem(data).map_err(|e| GhostError::Detection {
|
||||||
.scan_mem(data)
|
message: format!("Scan failed: {}", e),
|
||||||
.map_err(|e| GhostError::Detection { message: format!("Scan failed: {}", e }))?;
|
})?;
|
||||||
|
|
||||||
let mut matches = Vec::new();
|
let mut matches = Vec::new();
|
||||||
|
|
||||||
@@ -349,8 +361,11 @@ impl DynamicYaraEngine {
|
|||||||
use windows::Win32::System::Threading::{OpenProcess, PROCESS_VM_READ};
|
use windows::Win32::System::Threading::{OpenProcess, PROCESS_VM_READ};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let handle = OpenProcess(PROCESS_VM_READ, false, pid)
|
let handle = OpenProcess(PROCESS_VM_READ, false, pid).map_err(|e| {
|
||||||
.map_err(|e| GhostError::MemoryEnumeration { reason: format!("OpenProcess failed: {}", e }))?;
|
GhostError::MemoryEnumeration {
|
||||||
|
reason: format!("OpenProcess failed: {}", e),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut buffer = vec![0u8; region.size];
|
let mut buffer = vec![0u8; region.size];
|
||||||
let mut bytes_read = 0;
|
let mut bytes_read = 0;
|
||||||
@@ -383,16 +398,20 @@ impl DynamicYaraEngine {
|
|||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
|
||||||
let mem_path = format!("/proc/{}/mem", pid);
|
let mem_path = format!("/proc/{}/mem", pid);
|
||||||
let mut file = File::open(&mem_path).map_err(|e| {
|
let mut file = File::open(&mem_path).map_err(|e| GhostError::MemoryEnumeration {
|
||||||
GhostError::MemoryEnumeration { reason: format!("Failed to open {}: {}", mem_path, e })
|
reason: format!("Failed to open {}: {}", mem_path, e),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
file.seek(SeekFrom::Start(region.base_address as u64))
|
file.seek(SeekFrom::Start(region.base_address as u64))
|
||||||
.map_err(|e| GhostError::MemoryEnumeration { reason: format!("Seek failed: {}", e }))?;
|
.map_err(|e| GhostError::MemoryEnumeration {
|
||||||
|
reason: format!("Seek failed: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut buffer = vec![0u8; region.size];
|
let mut buffer = vec![0u8; region.size];
|
||||||
file.read_exact(&mut buffer)
|
file.read_exact(&mut buffer)
|
||||||
.map_err(|e| GhostError::MemoryEnumeration { reason: format!("Read failed: {}", e }))?;
|
.map_err(|e| GhostError::MemoryEnumeration {
|
||||||
|
reason: format!("Read failed: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user