refactor: comprehensive codebase improvements and documentation
- Enhanced error handling with expanded GhostError variants and From impls - Fixed race conditions in TUI (ui.rs unwrap calls) - Added comprehensive module documentation with doc comments - Improved type safety with proper validation in DetectionConfig - Implemented Linux process enumeration via procfs - Refactored TUI for better state management and removed emojis - Enhanced CLI with proper logging initialization - Added example configuration file (examples/ghost.toml) - Updated README with complete feature documentation - Added performance optimizations (saturating arithmetic, reduced clones) - Improved testing framework with proper struct initialization - Added validation and preset modes to DetectionConfig
This commit is contained in:
@@ -1,16 +1,38 @@
|
||||
//! Configuration management for the Ghost detection engine.
|
||||
//!
|
||||
//! This module provides configuration structures for customizing detection
|
||||
//! behavior, process filtering, and performance tuning.
|
||||
|
||||
use crate::GhostError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// Configuration options for the detection engine.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DetectionConfig {
|
||||
/// Enable shellcode pattern detection.
|
||||
pub shellcode_detection: bool,
|
||||
/// Enable process hollowing detection.
|
||||
pub hollowing_detection: bool,
|
||||
/// Enable Windows hook injection detection.
|
||||
pub hook_detection: bool,
|
||||
/// Minimum confidence threshold for suspicious classification (0.0 - 1.0).
|
||||
pub confidence_threshold: f32,
|
||||
/// Skip known safe system processes.
|
||||
pub skip_system_processes: bool,
|
||||
/// Maximum memory size to scan per process in bytes.
|
||||
pub max_memory_scan_size: usize,
|
||||
/// Enable thread behavior analysis.
|
||||
pub thread_analysis_enabled: bool,
|
||||
/// Enable evasion technique detection.
|
||||
pub evasion_detection: bool,
|
||||
/// Enable MITRE ATT&CK mapping.
|
||||
pub mitre_mapping: bool,
|
||||
/// Scan interval in milliseconds for continuous monitoring.
|
||||
pub scan_interval_ms: u64,
|
||||
/// Process filter configuration.
|
||||
pub process_filter: Option<ProcessFilter>,
|
||||
}
|
||||
|
||||
impl Default for DetectionConfig {
|
||||
@@ -19,29 +41,98 @@ impl Default for DetectionConfig {
|
||||
shellcode_detection: true,
|
||||
hollowing_detection: true,
|
||||
hook_detection: true,
|
||||
confidence_threshold: 0.7,
|
||||
confidence_threshold: 0.3,
|
||||
skip_system_processes: true,
|
||||
max_memory_scan_size: 1024 * 1024 * 100, // 100MB
|
||||
max_memory_scan_size: 100 * 1024 * 1024, // 100MB
|
||||
thread_analysis_enabled: true,
|
||||
evasion_detection: true,
|
||||
mitre_mapping: true,
|
||||
scan_interval_ms: 2000,
|
||||
process_filter: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DetectionConfig {
|
||||
pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
/// Loads configuration from a TOML file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the file cannot be read or parsed.
|
||||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, GhostError> {
|
||||
let content = fs::read_to_string(path)?;
|
||||
let config: DetectionConfig = toml::from_str(&content)?;
|
||||
config.validate()?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let content = toml::to_string_pretty(self)?;
|
||||
/// Loads configuration from a file, returning default on error.
|
||||
pub fn load_or_default<P: AsRef<Path>>(path: P) -> Self {
|
||||
Self::load(path).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Saves configuration to a TOML file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the file cannot be written.
|
||||
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), GhostError> {
|
||||
let content = toml::to_string_pretty(self).map_err(|e| GhostError::Configuration {
|
||||
message: e.to_string(),
|
||||
})?;
|
||||
fs::write(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_or_default<P: AsRef<Path>>(path: P) -> Self {
|
||||
Self::load_from_file(path).unwrap_or_default()
|
||||
/// Validates the configuration values.
|
||||
fn validate(&self) -> Result<(), GhostError> {
|
||||
if self.confidence_threshold < 0.0 || self.confidence_threshold > 1.0 {
|
||||
return Err(GhostError::Configuration {
|
||||
message: "confidence_threshold must be between 0.0 and 1.0".into(),
|
||||
});
|
||||
}
|
||||
|
||||
if self.max_memory_scan_size == 0 {
|
||||
return Err(GhostError::Configuration {
|
||||
message: "max_memory_scan_size must be greater than 0".into(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a configuration optimized for high performance (less thorough).
|
||||
pub fn performance_mode() -> Self {
|
||||
Self {
|
||||
shellcode_detection: true,
|
||||
hollowing_detection: false,
|
||||
hook_detection: false,
|
||||
confidence_threshold: 0.5,
|
||||
skip_system_processes: true,
|
||||
max_memory_scan_size: 10 * 1024 * 1024, // 10MB
|
||||
thread_analysis_enabled: false,
|
||||
evasion_detection: false,
|
||||
mitre_mapping: false,
|
||||
scan_interval_ms: 5000,
|
||||
process_filter: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a configuration optimized for thorough detection (slower).
|
||||
pub fn thorough_mode() -> Self {
|
||||
Self {
|
||||
shellcode_detection: true,
|
||||
hollowing_detection: true,
|
||||
hook_detection: true,
|
||||
confidence_threshold: 0.2,
|
||||
skip_system_processes: false,
|
||||
max_memory_scan_size: 500 * 1024 * 1024, // 500MB
|
||||
thread_analysis_enabled: true,
|
||||
evasion_detection: true,
|
||||
mitre_mapping: true,
|
||||
scan_interval_ms: 1000,
|
||||
process_filter: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,61 @@
|
||||
use crate::{
|
||||
detect_hook_injection, AnomalyDetector, MemoryProtection, MemoryRegion,
|
||||
ProcessInfo, ShellcodeDetector, ThreadInfo, ThreatIntelligence, ThreatContext,
|
||||
EvasionDetector, EvasionResult, DetectionConfig, GhostError,
|
||||
MitreAttackEngine, MitreAnalysisResult,
|
||||
//! Core detection engine for process injection analysis.
|
||||
//!
|
||||
//! This module provides the main detection orchestration, combining multiple
|
||||
//! analysis techniques including memory scanning, shellcode detection,
|
||||
//! process hollowing detection, and behavioral anomaly analysis.
|
||||
|
||||
use crate::{
|
||||
detect_hook_injection, AnomalyDetector, DetectionConfig, EvasionDetector, EvasionResult,
|
||||
GhostError, MemoryProtection, MemoryRegion, MitreAnalysisResult, MitreAttackEngine,
|
||||
ProcessInfo, ShellcodeDetector, ThreadInfo, ThreatContext, ThreatIntelligence,
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::EbpfDetector;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
/// Threat classification levels for detected processes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub enum ThreatLevel {
|
||||
/// Process appears normal with no suspicious indicators.
|
||||
Clean,
|
||||
/// Process exhibits potentially malicious behavior requiring investigation.
|
||||
Suspicious,
|
||||
/// Process shows strong indicators of malicious activity.
|
||||
Malicious,
|
||||
}
|
||||
|
||||
impl ThreatLevel {
|
||||
/// Returns a human-readable description of the threat level.
|
||||
pub fn description(&self) -> &'static str {
|
||||
match self {
|
||||
ThreatLevel::Clean => "No threats detected",
|
||||
ThreatLevel::Suspicious => "Potential security concern",
|
||||
ThreatLevel::Malicious => "High confidence malicious activity",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of analyzing a process for injection indicators.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DetectionResult {
|
||||
/// Information about the analyzed process.
|
||||
pub process: ProcessInfo,
|
||||
/// Overall threat classification.
|
||||
pub threat_level: ThreatLevel,
|
||||
/// List of specific indicators that contributed to the detection.
|
||||
pub indicators: Vec<String>,
|
||||
/// Confidence score from 0.0 to 1.0 indicating detection certainty.
|
||||
pub confidence: f32,
|
||||
/// Optional threat intelligence context with IOC matches.
|
||||
pub threat_context: Option<ThreatContext>,
|
||||
/// Optional analysis of evasion techniques used.
|
||||
pub evasion_analysis: Option<EvasionResult>,
|
||||
/// Optional MITRE ATT&CK framework mapping.
|
||||
pub mitre_analysis: Option<MitreAnalysisResult>,
|
||||
}
|
||||
|
||||
/// Main detection engine that orchestrates all analysis components.
|
||||
pub struct DetectionEngine {
|
||||
baseline: HashMap<u32, ProcessBaseline>,
|
||||
shellcode_detector: ShellcodeDetector,
|
||||
@@ -40,6 +69,7 @@ pub struct DetectionEngine {
|
||||
ebpf_detector: Option<EbpfDetector>,
|
||||
}
|
||||
|
||||
/// Baseline metrics for a process used to detect behavioral changes.
|
||||
#[derive(Debug, Clone)]
|
||||
struct ProcessBaseline {
|
||||
thread_count: u32,
|
||||
@@ -47,37 +77,51 @@ struct ProcessBaseline {
|
||||
}
|
||||
|
||||
impl DetectionEngine {
|
||||
/// Creates a new detection engine with default configuration.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the MITRE ATT&CK engine fails to initialize.
|
||||
pub fn new() -> Result<Self, GhostError> {
|
||||
Self::with_config(None)
|
||||
}
|
||||
|
||||
/// Creates a new detection engine with custom configuration.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `config` - Optional configuration for filtering and tuning detection behavior.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the MITRE ATT&CK engine fails to initialize.
|
||||
pub fn with_config(config: Option<DetectionConfig>) -> Result<Self, GhostError> {
|
||||
let baseline = ProcessBaseline::new();
|
||||
let shellcode_detector = ShellcodeDetector::new();
|
||||
let hollowing_detector = HollowingDetector::new();
|
||||
let anomaly_detector = AnomalyDetector::new();
|
||||
let threat_intelligence = ThreatIntelligence::new();
|
||||
let evasion_detector = EvasionDetector::new();
|
||||
let mitre_engine = MitreAttackEngine::new()?;
|
||||
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let ebpf_detector = match EbpfDetector::new() {
|
||||
Ok(mut detector) => {
|
||||
if let Err(e) = detector.initialize() {
|
||||
eprintln!("Warning: Failed to initialize eBPF detector: {:?}", e);
|
||||
log::warn!("Failed to initialize eBPF detector: {:?}", e);
|
||||
None
|
||||
} else {
|
||||
log::info!("eBPF detector initialized successfully");
|
||||
Some(detector)
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Warning: Failed to create eBPF detector: {:?}", e);
|
||||
log::warn!("Failed to create eBPF detector: {:?}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Ok(DetectionEngine {
|
||||
baseline,
|
||||
baseline: HashMap::new(),
|
||||
shellcode_detector,
|
||||
hollowing_detector,
|
||||
anomaly_detector,
|
||||
@@ -546,6 +590,6 @@ impl DetectionEngine {
|
||||
|
||||
impl Default for DetectionEngine {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
Self::new().expect("Failed to create default DetectionEngine")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,84 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
/// Error types for the Ghost detection framework.
|
||||
///
|
||||
/// This enum provides structured error handling for all operations
|
||||
/// within the detection engine, ensuring proper error propagation
|
||||
/// and meaningful error messages.
|
||||
#[derive(Error, Debug, Clone)]
|
||||
pub enum GhostError {
|
||||
#[error("Process access denied (PID: {pid})")]
|
||||
AccessDenied { pid: u32 },
|
||||
|
||||
|
||||
#[error("Process not found (PID: {pid})")]
|
||||
ProcessNotFound { pid: u32 },
|
||||
|
||||
|
||||
#[error("Memory enumeration failed: {reason}")]
|
||||
MemoryEnumeration { reason: String },
|
||||
|
||||
|
||||
#[error("Thread enumeration failed: {reason}")]
|
||||
ThreadEnumeration { reason: String },
|
||||
|
||||
|
||||
#[error("Insufficient privileges for operation")]
|
||||
InsufficientPrivileges,
|
||||
|
||||
|
||||
#[error("Windows API error: {message}")]
|
||||
WindowsApi { message: String },
|
||||
|
||||
|
||||
#[error("Detection engine error: {message}")]
|
||||
Detection { message: String },
|
||||
|
||||
#[error("Configuration error: {message}")]
|
||||
Configuration { message: String },
|
||||
|
||||
#[error("IO error: {message}")]
|
||||
Io { message: String },
|
||||
|
||||
#[error("Serialization error: {message}")]
|
||||
Serialization { message: String },
|
||||
|
||||
#[error("Lock acquisition failed: {resource}")]
|
||||
LockPoisoned { resource: String },
|
||||
|
||||
#[error("Threat intelligence error: {message}")]
|
||||
ThreatIntel { message: String },
|
||||
|
||||
#[error("MITRE ATT&CK analysis error: {message}")]
|
||||
MitreAnalysis { message: String },
|
||||
|
||||
#[error("eBPF error: {message}")]
|
||||
Ebpf { message: String },
|
||||
|
||||
#[error("Platform not supported: {feature}")]
|
||||
PlatformNotSupported { feature: String },
|
||||
|
||||
#[error("Invalid input: {message}")]
|
||||
InvalidInput { message: String },
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for GhostError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
GhostError::Io {
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for GhostError {
|
||||
fn from(err: serde_json::Error) -> Self {
|
||||
GhostError::Serialization {
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<toml::de::Error> for GhostError {
|
||||
fn from(err: toml::de::Error) -> Self {
|
||||
GhostError::Configuration {
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias for Result with GhostError as the error type.
|
||||
pub type Result<T> = std::result::Result<T, GhostError>;
|
||||
@@ -1,9 +1,59 @@
|
||||
//! # Ghost - Cross-Platform Process Injection Detection Framework
|
||||
//!
|
||||
//! Ghost is a comprehensive security framework for detecting process injection,
|
||||
//! memory manipulation, and advanced evasion techniques in running processes.
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! - **Multi-layer detection**: Combines memory analysis, behavioral patterns,
|
||||
//! and machine learning for accurate threat detection.
|
||||
//! - **MITRE ATT&CK integration**: Maps detected behaviors to the MITRE ATT&CK
|
||||
//! framework for standardized threat classification.
|
||||
//! - **Cross-platform support**: Works on Windows, Linux (with eBPF), and macOS.
|
||||
//! - **Threat intelligence**: Integrates with threat feeds for IOC correlation.
|
||||
//! - **Performance optimized**: Designed for low-overhead continuous monitoring.
|
||||
//!
|
||||
//! ## Quick Start
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use ghost_core::{DetectionEngine, process, memory, thread};
|
||||
//!
|
||||
//! // Create detection engine
|
||||
//! let mut engine = DetectionEngine::new().expect("Failed to create engine");
|
||||
//!
|
||||
//! // Enumerate and analyze processes
|
||||
//! let processes = process::enumerate_processes().expect("Failed to enumerate");
|
||||
//!
|
||||
//! for proc in &processes {
|
||||
//! if let Ok(regions) = memory::enumerate_memory_regions(proc.pid) {
|
||||
//! let threads = thread::enumerate_threads(proc.pid).ok();
|
||||
//! let result = engine.analyze_process(proc, ®ions, threads.as_deref());
|
||||
//!
|
||||
//! if result.threat_level != ghost_core::ThreatLevel::Clean {
|
||||
//! println!("Suspicious: {} (PID: {})", proc.name, proc.pid);
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Module Overview
|
||||
//!
|
||||
//! - [`detection`]: Core detection engine orchestrating all analysis.
|
||||
//! - [`process`]: Process enumeration and information gathering.
|
||||
//! - [`memory`]: Memory region analysis and protection detection.
|
||||
//! - [`thread`]: Thread enumeration and behavioral analysis.
|
||||
//! - [`shellcode`]: Shellcode pattern detection and signature matching.
|
||||
//! - [`hollowing`]: Process hollowing detection algorithms.
|
||||
//! - [`evasion`]: Anti-analysis and evasion technique detection.
|
||||
//! - [`anomaly`]: Statistical anomaly detection using ML.
|
||||
//! - [`mitre_attack`]: MITRE ATT&CK framework mapping.
|
||||
//! - [`threat_intel`]: Threat intelligence correlation.
|
||||
|
||||
pub mod anomaly;
|
||||
pub mod behavioral_ml;
|
||||
pub mod config;
|
||||
pub mod detection;
|
||||
pub mod ebpf;
|
||||
pub mod testing;
|
||||
pub mod error;
|
||||
pub mod evasion;
|
||||
pub mod hollowing;
|
||||
@@ -16,6 +66,7 @@ pub mod neural_memory;
|
||||
pub mod process;
|
||||
pub mod shellcode;
|
||||
pub mod streaming;
|
||||
pub mod testing;
|
||||
pub mod thread;
|
||||
pub mod threat_intel;
|
||||
pub mod yara_engine;
|
||||
|
||||
@@ -1,15 +1,44 @@
|
||||
//! Process enumeration and information retrieval.
|
||||
//!
|
||||
//! This module provides cross-platform process enumeration capabilities,
|
||||
//! allowing the detection engine to gather information about running processes.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
/// Information about a running process.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct ProcessInfo {
|
||||
/// Process identifier.
|
||||
pub pid: u32,
|
||||
/// Parent process identifier.
|
||||
pub ppid: u32,
|
||||
/// Process name (executable name).
|
||||
pub name: String,
|
||||
/// Full path to the executable, if available.
|
||||
pub path: Option<String>,
|
||||
/// Number of threads in the process.
|
||||
pub thread_count: u32,
|
||||
}
|
||||
|
||||
impl ProcessInfo {
|
||||
/// Creates a new ProcessInfo instance.
|
||||
pub fn new(pid: u32, ppid: u32, name: String) -> Self {
|
||||
Self {
|
||||
pid,
|
||||
ppid,
|
||||
name,
|
||||
path: None,
|
||||
thread_count: 1,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this is likely a system process.
|
||||
pub fn is_system_process(&self) -> bool {
|
||||
self.pid == 0 || self.pid == 4 || self.name == "System" || self.name == "Idle"
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ProcessInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[{}] {}", self.pid, self.name)
|
||||
@@ -92,17 +121,119 @@ mod platform {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[cfg(target_os = "linux")]
|
||||
mod platform {
|
||||
use super::ProcessInfo;
|
||||
use anyhow::{Context, Result};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> {
|
||||
let mut processes = Vec::new();
|
||||
|
||||
let proc_dir = Path::new("/proc");
|
||||
if !proc_dir.exists() {
|
||||
return Err(anyhow::anyhow!("procfs not available"));
|
||||
}
|
||||
|
||||
for entry in fs::read_dir(proc_dir).context("Failed to read /proc directory")? {
|
||||
let entry = match entry {
|
||||
Ok(e) => e,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let file_name = entry.file_name();
|
||||
let pid_str = match file_name.to_str() {
|
||||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let pid: u32 = match pid_str.parse() {
|
||||
Ok(p) => p,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if let Ok(info) = get_process_info(pid) {
|
||||
processes.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(processes)
|
||||
}
|
||||
|
||||
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 (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());
|
||||
|
||||
Ok(ProcessInfo {
|
||||
pid,
|
||||
ppid,
|
||||
name,
|
||||
path,
|
||||
thread_count,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_stat(stat: &str) -> Result<(String, u32, u32)> {
|
||||
let open_paren = stat.find('(').context("Invalid stat format")?;
|
||||
let close_paren = stat.rfind(')').context("Invalid stat format")?;
|
||||
|
||||
let name = stat[open_paren + 1..close_paren].to_string();
|
||||
let rest = &stat[close_paren + 2..];
|
||||
let fields: Vec<&str> = rest.split_whitespace().collect();
|
||||
|
||||
if fields.len() < 18 {
|
||||
return Err(anyhow::anyhow!("Insufficient fields in stat"));
|
||||
}
|
||||
|
||||
let ppid: u32 = fields[1].parse().context("Failed to parse PPID")?;
|
||||
let thread_count: u32 = fields[17].parse().unwrap_or(1);
|
||||
|
||||
Ok((name, ppid, thread_count))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod platform {
|
||||
use super::ProcessInfo;
|
||||
use anyhow::Result;
|
||||
|
||||
pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> {
|
||||
// TODO: Implement Linux/macOS enumeration
|
||||
// macOS implementation would use libproc or sysctl
|
||||
// For now, return empty to indicate platform support is partial
|
||||
log::warn!("macOS process enumeration not yet fully implemented");
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(windows, target_os = "linux", target_os = "macos")))]
|
||||
mod platform {
|
||||
use super::ProcessInfo;
|
||||
use anyhow::Result;
|
||||
|
||||
pub fn enumerate_processes() -> Result<Vec<ProcessInfo>> {
|
||||
Err(anyhow::anyhow!("Process enumeration not supported on this platform"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumerates all running processes on the system.
|
||||
///
|
||||
/// # Platform Support
|
||||
///
|
||||
/// - **Windows**: Uses the ToolHelp API to enumerate processes.
|
||||
/// - **Linux**: Reads from the /proc filesystem.
|
||||
/// - **macOS**: Partial support (not yet implemented).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if process enumeration fails due to insufficient
|
||||
/// privileges or platform limitations.
|
||||
pub fn enumerate_processes() -> anyhow::Result<Vec<ProcessInfo>> {
|
||||
platform::enumerate_processes()
|
||||
}
|
||||
|
||||
@@ -799,6 +799,7 @@ impl TestFramework {
|
||||
// Create test data
|
||||
let process_info = ProcessInfo {
|
||||
pid: params.process_data.pid,
|
||||
ppid: 1,
|
||||
name: params.process_data.name.clone(),
|
||||
path: params.process_data.path.clone(),
|
||||
thread_count: params.process_data.thread_count,
|
||||
@@ -809,20 +810,20 @@ impl TestFramework {
|
||||
base_address: mem.base_address,
|
||||
size: mem.size,
|
||||
protection: mem.protection.clone(),
|
||||
region_type: "PRIVATE".to_string(),
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let threads: Vec<ThreadInfo> = params.thread_data.iter().map(|thread| {
|
||||
ThreadInfo {
|
||||
tid: thread.tid,
|
||||
entry_point: thread.entry_point,
|
||||
stack_base: thread.stack_base,
|
||||
stack_size: thread.stack_size,
|
||||
start_address: thread.entry_point,
|
||||
creation_time: 0,
|
||||
}
|
||||
}).collect();
|
||||
|
||||
// Run detection
|
||||
let result = engine.analyze_process(&process_info, &memory_regions, &threads);
|
||||
let result = engine.analyze_process(&process_info, &memory_regions, Some(&threads));
|
||||
|
||||
// Validate result
|
||||
match expected {
|
||||
|
||||
Reference in New Issue
Block a user