Add structured logging with debug flag

This commit is contained in:
Adir Shitrit
2025-11-08 12:35:41 +02:00
parent 3ae9cbc907
commit f72b530f6c

View File

@@ -1,6 +1,7 @@
use anyhow::Result; use anyhow::Result;
use clap::{Arg, Command}; use clap::{Arg, Command};
use ghost_core::{memory, process, thread, DetectionEngine, ThreatLevel}; use ghost_core::{memory, process, thread, DetectionEngine, ThreatLevel};
use log::{debug, error, info, warn};
use std::time::Instant; use std::time::Instant;
fn main() -> Result<()> { fn main() -> Result<()> {
@@ -40,22 +41,49 @@ fn main() -> Result<()> {
.short('o') .short('o')
.long("output") .long("output")
.value_name("FILE") .value_name("FILE")
.help("Write results to file instead of stdout") .help("Write output to file instead of stdout"),
)
.arg(
Arg::new("debug")
.short('d')
.long("debug")
.action(clap::ArgAction::SetTrue)
.help("Enable debug logging"),
) )
.get_matches(); .get_matches();
// Initialize logging based on debug flag
if matches.get_flag("debug") {
env_logger::Builder::from_default_env()
.filter_level(log::LevelFilter::Debug)
.init();
debug!("Debug logging enabled");
} else {
env_logger::Builder::from_default_env()
.filter_level(log::LevelFilter::Info)
.init();
}
let format = matches.get_one::<String>("format").unwrap(); let format = matches.get_one::<String>("format").unwrap();
let verbose = matches.get_flag("verbose"); let verbose = matches.get_flag("verbose");
let target_pid = matches.get_one::<String>("pid"); let target_pid = matches.get_one::<String>("pid");
let output_file = matches.get_one::<String>("output"); let output_file = matches.get_one::<String>("output");
info!("Starting Ghost process injection detection");
debug!("Configuration - Format: {}, Verbose: {}, Target PID: {:?}", format, verbose, target_pid);
println!("Ghost v0.1.0 - Process Injection Detection\n"); println!("Ghost v0.1.0 - Process Injection Detection\n");
let scan_start = Instant::now(); let scan_start = Instant::now();
let mut engine = DetectionEngine::new(); let mut engine = DetectionEngine::new();
let processes = if let Some(pid_str) = target_pid { let processes = if let Some(pid_str) = target_pid {
let pid: u32 = pid_str.parse().map_err(|_| anyhow::anyhow!("Invalid PID format: {}", pid_str))?; let pid: u32 = pid_str.parse().map_err(|e| {
error!("Invalid PID format '{}': {}", pid_str, e);
anyhow::anyhow!("Invalid PID format: {}", pid_str)
})?;
info!("Targeting specific process ID: {}", pid);
let all_processes = process::enumerate_processes()?; let all_processes = process::enumerate_processes()?;
let filtered: Vec<_> = all_processes let filtered: Vec<_> = all_processes
.into_iter() .into_iter()
@@ -63,11 +91,16 @@ fn main() -> Result<()> {
.collect(); .collect();
if filtered.is_empty() { if filtered.is_empty() {
warn!("No process found with PID {}", pid);
println!("Warning: No process found with PID {}", pid); println!("Warning: No process found with PID {}", pid);
} else {
debug!("Found target process: {}", filtered[0].name);
} }
filtered filtered
} else { } else {
process::enumerate_processes()? let all_processes = process::enumerate_processes()?;
info!("Enumerating all processes, found {} total", all_processes.len());
all_processes
}; };
println!("Scanning {} processes...\n", processes.len()); println!("Scanning {} processes...\n", processes.len());
@@ -79,23 +112,30 @@ fn main() -> Result<()> {
for proc in &processes { for proc in &processes {
// Skip known safe system processes for performance // Skip known safe system processes for performance
if proc.name == "csrss.exe" || proc.name == "wininit.exe" || proc.name == "winlogon.exe" { if proc.name == "csrss.exe" || proc.name == "wininit.exe" || proc.name == "winlogon.exe" {
debug!("Skipping safe system process: {}", proc.name);
continue; continue;
} }
scanned_count += 1; scanned_count += 1;
debug!("Scanning process: {} (PID: {})", proc.name, proc.pid);
match memory::enumerate_memory_regions(proc.pid) { match memory::enumerate_memory_regions(proc.pid) {
Ok(regions) => { Ok(regions) => {
debug!("Found {} memory regions for process {}", regions.len(), proc.name);
// Get thread information if available // Get thread information if available
let threads = thread::enumerate_threads(proc.pid).ok(); let threads = thread::enumerate_threads(proc.pid).ok();
let result = engine.analyze_process(proc, &regions, threads.as_deref()); let result = engine.analyze_process(proc, &regions, threads.as_deref());
if result.threat_level != ThreatLevel::Clean { if result.threat_level != ThreatLevel::Clean {
warn!("Suspicious activity detected in process {} (PID: {})", proc.name, proc.pid);
detections.push(result); detections.push(result);
} else {
debug!("Process {} (PID: {}) is clean", proc.name, proc.pid);
} }
} }
Err(_) => { Err(e) => {
error_count += 1; error_count += 1;
error!("Failed to scan process {} (PID: {}): {}", proc.name, proc.pid, e);
if verbose { if verbose {
println!("Warning: Could not scan process {} (PID: {})", proc.name, proc.pid); println!("Warning: Could not scan process {} (PID: {})", proc.name, proc.pid);
} }
@@ -104,9 +144,12 @@ fn main() -> Result<()> {
} }
if verbose && error_count > 0 { if verbose && error_count > 0 {
warn!("Scan completed with {} access errors", error_count);
println!("Scan completed with {} access errors", error_count); println!("Scan completed with {} access errors", error_count);
} }
info!("Scan completed: {} processes scanned, {} suspicious processes found", scanned_count, detections.len());
// Handle output // Handle output
let output_content = if detections.is_empty() { let output_content = if detections.is_empty() {
"No suspicious activity detected.".to_string() "No suspicious activity detected.".to_string()
@@ -140,10 +183,12 @@ fn main() -> Result<()> {
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
info!("Writing results to file: {}", output_path);
let mut file = File::create(output_path)?; let mut file = File::create(output_path)?;
file.write_all(output_content.as_bytes())?; file.write_all(output_content.as_bytes())?;
println!("Results written to {}", output_path); println!("Results written to {}", output_path);
} else { } else {
debug!("Writing results to stdout");
print!("{}", output_content); print!("{}", output_content);
} }