pub fn print_report(
report: &SecurityReport,
format: &OutputFormat,
output_file: Option<&PathBuf>,
) -> Result<()>Examples found in repository?
examples/simple_analysis.rs (line 39)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 // Analyze a single executable file
11 let file_path = PathBuf::from("/bin/ls");
12
13 println!("Analyzing: {}", file_path.display());
14
15 match analyze_file(&file_path) {
16 Ok(result) => {
17 println!("\n=== Analysis Results ===");
18 println!("File: {}", result.file_path);
19 println!("Type: {}", result.file_type);
20 println!("Status: {}", result.overall_status);
21
22 println!("\n=== Security Checks ===");
23 for (check, value) in &result.checks {
24 println!(" {}: {}", check, value);
25 }
26
27 // Create a report and print it in human-readable format
28 println!("\n=== Formatted Report ===");
29 let report = SecurityReport {
30 files: vec![result],
31 summary: ReportSummary {
32 total_files: 1,
33 secure_files: 1,
34 insecure_files: 0,
35 unsupported_files: 0,
36 },
37 };
38
39 print_report(&report, &OutputFormat::Human, None)?;
40 }
41 Err(e) => {
42 eprintln!("Failed to analyze file: {}", e);
43 std::process::exit(1);
44 }
45 }
46
47 Ok(())
48}More examples
examples/json_output.rs (line 53)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 // Analyze multiple files
11 let files = vec![
12 PathBuf::from("/bin/ls"),
13 PathBuf::from("/bin/cat"),
14 PathBuf::from("/bin/echo"),
15 ];
16
17 let mut results = Vec::new();
18 let mut secure_count = 0;
19 let mut insecure_count = 0;
20 let mut unsupported_count = 0;
21
22 println!("Analyzing {} files...", files.len());
23
24 for file_path in files {
25 match analyze_file(&file_path) {
26 Ok(result) => {
27 match result.overall_status.as_str() {
28 "Secure" => secure_count += 1,
29 "Mostly Secure" | "Insecure" => insecure_count += 1,
30 _ => unsupported_count += 1,
31 }
32 results.push(result);
33 }
34 Err(e) => {
35 eprintln!("Warning: Failed to analyze {}: {}", file_path.display(), e);
36 unsupported_count += 1;
37 }
38 }
39 }
40
41 // Create report
42 let report = SecurityReport {
43 files: results,
44 summary: ReportSummary {
45 total_files: secure_count + insecure_count + unsupported_count,
46 secure_files: secure_count,
47 insecure_files: insecure_count,
48 unsupported_files: unsupported_count,
49 },
50 };
51
52 println!("\n=== JSON Output ===");
53 print_report(&report, &OutputFormat::Json, None)?;
54
55 Ok(())
56}examples/directory_scan.rs (line 33)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 // Configure scan options
11 let options = ScanOptions {
12 recursive: false, // Only scan top level
13 issues_only: true, // Only show files with security issues
14 strict: false, // Don't exit on issues
15 file_filter: FileFilter::All, // All executable types
16 one_filesystem: false, // Allow crossing filesystem boundaries
17 };
18
19 // Scan a directory (adjust path as needed)
20 let scan_path = PathBuf::from("/usr/bin");
21 println!("Scanning directory: {} (issues only)", scan_path.display());
22
23 match scan_directory(&scan_path, &options) {
24 Ok(report) => {
25 println!("\n=== Scan Summary ===");
26 println!("Total files analyzed: {}", report.summary.total_files);
27 println!("Secure files: {}", report.summary.secure_files);
28 println!("Files with issues: {}", report.summary.insecure_files);
29 println!("Unsupported files: {}", report.summary.unsupported_files);
30
31 if report.summary.insecure_files > 0 {
32 println!("\n=== Files with Security Issues ===");
33 print_report(&report, &OutputFormat::Human, None)?;
34 } else {
35 println!("\nAll analyzed files have good security posture! ✓");
36 }
37 }
38 Err(e) => {
39 eprintln!("Failed to scan directory: {}", e);
40 std::process::exit(1);
41 }
42 }
43
44 Ok(())
45}examples/fat_binary_analysis.rs (lines 71-79)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 println!("=== ExeCheck Fat Binary Analysis Example ===");
13 println!();
14
15 // Example fat binary paths (these may not exist on all systems)
16 let potential_fat_binaries = vec![
17 "/Applications/Xcode.app/Contents/MacOS/Xcode",
18 "/System/Applications/Calculator.app/Contents/MacOS/Calculator",
19 "/usr/bin/python3",
20 "/bin/bash",
21 ];
22
23 println!("Searching for fat binaries on the system...");
24 println!();
25
26 let mut found_examples = false;
27
28 for binary_path in potential_fat_binaries {
29 let path = PathBuf::from(binary_path);
30
31 if path.exists() {
32 println!("Analyzing: {}", binary_path);
33
34 match analyze_file(&path) {
35 Ok(result) => {
36 // Check if this is a fat binary
37 if result.file_type.contains("Fat") {
38 found_examples = true;
39
40 println!("✅ Found fat binary!");
41 println!(" File Type: {}", result.file_type);
42 println!(" Status: {}", result.overall_status);
43
44 if let Some(arch_count) = result.checks.get("architectures") {
45 println!(" Architectures: {}", arch_count);
46 }
47
48 // Show per-architecture security details
49 if let Some(total_archs) = result.checks.get("total_architectures") {
50 println!(" Total Architectures: {}", total_archs);
51 }
52 if let Some(secure_archs) = result.checks.get("secure_architectures") {
53 println!(" Secure Architectures: {}", secure_archs);
54 }
55 if let Some(arch_list) = result.checks.get("architectures") {
56 println!(" Architecture List: {}", arch_list);
57 }
58
59 // Show individual architecture security checks
60 println!(" Per-Architecture Security:");
61 for (key, value) in &result.checks {
62 if key.contains("_pie") || key.contains("_canary") || key.contains("_nx") {
63 println!(" {}: {}", key, value);
64 }
65 }
66
67 println!();
68
69 // Show detailed report in JSON format
70 println!("Detailed JSON Report:");
71 print_report(&execheck::SecurityReport {
72 files: vec![result],
73 summary: execheck::ReportSummary {
74 total_files: 1,
75 secure_files: 0,
76 insecure_files: 0,
77 unsupported_files: 1,
78 },
79 }, &OutputFormat::Json, None)?;
80
81 println!("\n{}\n", "=".repeat(60));
82 } else {
83 println!(" Not a fat binary ({})", result.file_type);
84 }
85 }
86 Err(e) => {
87 println!(" Error analyzing: {}", e);
88 }
89 }
90 } else {
91 println!("Skipping: {} (not found)", binary_path);
92 }
93 }
94
95 if !found_examples {
96 // Create a demonstration with mock data
97 println!("No fat binaries found on system. Showing example output:");
98 println!();
99
100 demonstrate_fat_binary_output()?;
101 }
102
103 println!("=== Fat Binary Analysis Notes ===");
104 println!();
105 println!("Current Status:");
106 println!("• ✅ Fat binary detection and architecture counting");
107 println!("• ✅ Per-architecture security analysis");
108 println!("• ✅ Architecture-specific security checks (e.g., 'x86_64_pie', 'arm64_canary')");
109 println!("• ✅ Combined security status (Secure/Mixed/Insecure)");
110 println!();
111 println!("Fat binaries now show detailed architecture-specific security analysis,");
112 println!("allowing you to see security features for each architecture independently.");
113
114 Ok(())
115}
116
117/// Demonstrate what fat binary output will look like when fully implemented
118fn demonstrate_fat_binary_output() -> Result<(), Box<dyn std::error::Error>> {
119 use std::collections::HashMap;
120
121 println!("Example Fat Binary Analysis (Mock Data):");
122 println!();
123
124 // Create a mock fat binary result showing the full implementation
125 let mut checks = HashMap::new();
126 checks.insert("total_architectures".to_string(), "2".to_string());
127 checks.insert("secure_architectures".to_string(), "1".to_string());
128 checks.insert("architectures".to_string(), "x86_64, arm64".to_string());
129
130 // Per-architecture security checks
131 checks.insert("x86_64_pie".to_string(), "PIE Enabled".to_string());
132 checks.insert("arm64_pie".to_string(), "PIE Enabled".to_string());
133 checks.insert("x86_64_canary".to_string(), "Canary Found".to_string());
134 checks.insert("arm64_canary".to_string(), "No Canary Found".to_string());
135 checks.insert("x86_64_nx".to_string(), "NX enabled".to_string());
136 checks.insert("arm64_nx".to_string(), "NX enabled".to_string());
137
138 let mock_result = execheck::SecurityCheck {
139 file_path: "/example/universal_app".to_string(),
140 file_type: "Mach-O Fat (2 archs)".to_string(),
141 checks,
142 overall_status: "Mixed".to_string(),
143 };
144
145 let report = execheck::SecurityReport {
146 files: vec![mock_result],
147 summary: execheck::ReportSummary {
148 total_files: 1,
149 secure_files: 0,
150 insecure_files: 1,
151 unsupported_files: 0,
152 },
153 };
154
155 // Show current output
156 println!("Current Output (Human Format):");
157 print_report(&report, &OutputFormat::Human, None)?;
158
159 println!("\nFuture Enhanced Output (When Fully Implemented):");
160 println!("File: /example/universal_app");
161 println!("Type: Mach-O Fat (2 archs)");
162 println!("Status: ⚠ Mixed");
163 println!("Security Checks:");
164 println!(" X86_64 Architecture:");
165 println!(" PIE : ✓ PIE Enabled");
166 println!(" Stack Canary : ✓ Canary Found");
167 println!(" NX : ✓ NX enabled");
168 println!();
169 println!(" ARM64 Architecture:");
170 println!(" PIE : ✓ PIE Enabled");
171 println!(" Stack Canary : ✗ No Canary Found");
172 println!(" NX : ✓ NX enabled");
173
174 Ok(())
175}examples/advanced_filtering.rs (line 148)
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}