Skip to main content

fat_binary_analysis/
fat_binary_analysis.rs

1use execheck::{analyze_file, print_report, OutputFormat};
2use std::path::PathBuf;
3
4/// Example demonstrating analysis of Mach-O fat binaries (universal binaries).
5/// 
6/// Fat binaries contain multiple architectures in a single file, commonly used
7/// on macOS to support both Intel and Apple Silicon architectures.
8/// 
9/// This example shows how ExeCheck handles fat binaries and reports
10/// architecture information.
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}