Skip to main content

advanced_filtering/
advanced_filtering.rs

1#!/usr/bin/env cargo
2//! Advanced filtering and filesystem boundary example
3//! 
4//! Run with: cargo run --example advanced_filtering
5
6use execheck::{
7    collect_executable_files, analyze_files, print_report, 
8    ScanOptions, FileFilter, OutputFormat
9};
10use std::path::PathBuf;
11
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    println!("=== ExeCheck Advanced Filtering Example ===\n");
14
15    // Example 1: Filter only Windows executables (.exe)
16    println!("1. Scanning for Windows executables (.exe files only):");
17    let exe_options = ScanOptions {
18        recursive: false,
19        issues_only: false,
20        strict: false,
21        file_filter: FileFilter::WindowsExecutables,
22        one_filesystem: false,
23    };
24    
25    if let Ok(exe_files) = collect_executable_files(&PathBuf::from("."), &exe_options) {
26        println!("   Found {} .exe files", exe_files.len());
27        for file in exe_files.iter().take(3) {
28            println!("   - {}", file.display());
29        }
30    } else {
31        println!("   No .exe files found or error occurred");
32    }
33
34    // Example 2: Filter only Windows DLLs (.dll)
35    println!("\n2. Scanning for Windows DLLs (.dll files only):");
36    let dll_options = ScanOptions {
37        recursive: false,
38        issues_only: false,
39        strict: false,
40        file_filter: FileFilter::WindowsDlls,
41        one_filesystem: false,
42    };
43    
44    if let Ok(dll_files) = collect_executable_files(&PathBuf::from("."), &dll_options) {
45        println!("   Found {} .dll files", dll_files.len());
46        for file in dll_files.iter().take(3) {
47            println!("   - {}", file.display());
48        }
49    } else {
50        println!("   No .dll files found or error occurred");
51    }
52
53    // Example 3: Custom extension filtering
54    println!("\n3. Custom extension filtering (exe, dll, so, dylib):");
55    let custom_extensions = vec![
56        "exe".to_string(),
57        "dll".to_string(), 
58        "so".to_string(),
59        "dylib".to_string(),
60    ];
61    
62    let custom_options = ScanOptions {
63        recursive: true,
64        issues_only: false,
65        strict: false,
66        file_filter: FileFilter::Extensions(custom_extensions),
67        one_filesystem: false,
68    };
69    
70    if let Ok(custom_files) = collect_executable_files(&PathBuf::from("."), &custom_options) {
71        println!("   Found {} files with custom extensions", custom_files.len());
72        for file in custom_files.iter().take(5) {
73            println!("   - {}", file.display());
74        }
75    } else {
76        println!("   No files with custom extensions found or error occurred");
77    }
78
79    // Example 4: Custom predicate filtering
80    println!("\n4. Custom predicate filtering (files containing 'lib' in name):");
81    let lib_filter = |path: &std::path::Path| {
82        path.file_name()
83            .and_then(|name| name.to_str())
84            .map_or(false, |name| name.to_lowercase().contains("lib"))
85    };
86    
87    let predicate_options = ScanOptions {
88        recursive: true,
89        issues_only: false,
90        strict: false,
91        file_filter: FileFilter::Custom(lib_filter),
92        one_filesystem: false,
93    };
94    
95    if let Ok(lib_files) = collect_executable_files(&PathBuf::from("/usr/lib"), &predicate_options) {
96        println!("   Found {} library files", lib_files.len());
97        for file in lib_files.iter().take(5) {
98            println!("   - {}", file.display());
99        }
100    } else {
101        println!("   Error scanning /usr/lib or no library files found");
102    }
103
104    // Example 5: Filesystem boundary demonstration (Unix only)
105    #[cfg(unix)]
106    {
107        println!("\n5. Filesystem boundary scanning (Unix only):");
108        let boundary_options = ScanOptions {
109            recursive: true,
110            issues_only: false,
111            strict: false,
112            file_filter: FileFilter::All,
113            one_filesystem: true, // Stay within single filesystem
114        };
115        
116        if let Ok(boundary_files) = collect_executable_files(&PathBuf::from("/"), &boundary_options) {
117            println!("   Found {} files within root filesystem", boundary_files.len());
118            println!("   (This prevents crossing into /proc, /sys, mounted drives, etc.)");
119        } else {
120            println!("   Error scanning root filesystem with boundary restrictions");
121        }
122    }
123    
124    #[cfg(not(unix))]
125    {
126        println!("\n5. Filesystem boundary scanning:");
127        println!("   (Not supported on this platform - Unix-like systems only)");
128    }
129
130    // Example 6: Practical use case - analyze only PE files in a directory
131    println!("\n6. Practical example - Analyze Windows executables and DLLs with JSON output:");
132    
133    let analysis_options = ScanOptions {
134        recursive: true,
135        issues_only: true, // Only show files with security issues
136        strict: false,
137        file_filter: FileFilter::WindowsExecutablesAndDlls,
138        one_filesystem: false,
139    };
140    
141    // Try to analyze current directory for demo purposes
142    if let Ok(files) = collect_executable_files(&PathBuf::from("."), &analysis_options) {
143        if !files.is_empty() {
144            let report = analyze_files(files, &analysis_options)?;
145            
146            if !report.files.is_empty() {
147                println!("   Analysis results (JSON format):");
148                print_report(&report, &OutputFormat::Json, None)?;
149            } else {
150                println!("   No security issues found in Windows executables/DLLs!");
151            }
152        } else {
153            println!("   No Windows executables or DLLs found in current directory");
154        }
155    }
156
157    println!("\n=== Advanced Filtering Example Complete ===");
158    Ok(())
159}