[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/bad-antics/nullsec-binarydiff/main/binarydiff.swift [Back]  [Original]

// NullSec BinaryDiff - Binary Comparison Tool
// Swift security tool demonstrating:
//   - Protocol-oriented programming
//   - Value types and copy-on-write
//   - Optionals and nil coalescing
//   - Strong type system
//   - Extensions
//   - Enums with associated values
//
// Author: bad-antics
// License: MIT

import Foundation

let VERSION = "1.0.0"

// ANSI Colors
enum Color: String {
    case red    = "\u{1B}[31m"
    case green  = "\u{1B}[32m"
    case yellow = "\u{1B}[33m"
    case cyan   = "\u{1B}[36m"
    case gray   = "\u{1B}[90m"
    case reset  = "\u{1B}[0m"
}

// Severity levels
enum Severity: String, CaseIterable {
    case critical = "CRITICAL"
    case high = "HIGH"
    case medium = "MEDIUM"
    case low = "LOW"
    case info = "INFO"
    
    var color: Color {
        switch self {
        case .critical, .high: return .red
        case .medium: return .yellow
        case .low: return .cyan
        case .info: return .gray
        }
    }
}

// Diff type
enum DiffType: String {
    case added = "ADDED"
    case removed = "REMOVED"
    case modified = "MODIFIED"
    case unchanged = "UNCHANGED"
}

// Binary section
struct Section {
    let name: String
    let offset: UInt64
    let size: UInt64
    let permissions: String
    let hash: String
}

// Function entry
struct FunctionEntry {
    let name: String
    let offset: UInt64
    let size: UInt64
    let complexity: Int
    let hash: String
}

// Diff result for sections
struct SectionDiff {
    let diffType: DiffType
    let oldSection: Section?
    let newSection: Section?
    let severity: Severity
    let reason: String
}

// Diff result for functions
struct FunctionDiff {
    let diffType: DiffType
    let oldFunc: FunctionEntry?
    let newFunc: FunctionEntry?
    let severity: Severity
    let changes: [String]
}

// Binary info
struct BinaryInfo {
    let path: String
    let size: UInt64
    let hash: String
    let sections: [Section]
    let functions: [FunctionEntry]
    let imports: [String]
    let exports: [String]
}

// Analysis result
struct DiffAnalysis {
    let oldBinary: BinaryInfo
    let newBinary: BinaryInfo
    let sectionDiffs: [SectionDiff]
    let functionDiffs: [FunctionDiff]
    let importDiffs: [String: DiffType]
    let exportDiffs: [String: DiffType]
    let similarityScore: Double
}

// Security-sensitive function names
let securityFunctions = [
    "strcpy", "strcat", "sprintf", "gets",
    "memcpy", "memmove", "malloc", "free",
    "system", "exec", "popen", "fork",
    "connect", "bind", "listen", "accept",
    "read", "write", "recv", "send",
    "crypt", "encrypt", "decrypt",
    "auth", "login", "verify", "validate"
]

// Check if function is security-sensitive
func isSecuritySensitive(_ name: String) -> Bool {
    let lower = name.lowercased()
    return securityFunctions.contains { lower.contains($0) }
}

// Demo binary info
func demoBinaryOld() -> BinaryInfo {
    BinaryInfo(
        path: "/usr/bin/app_v1.0",
        size: 1048576,
        hash: "a1b2c3d4e5f6",
        sections: [
            Section(name: ".text", offset: 0x1000, size: 0x50000, permissions: "r-x", hash: "text_hash_old"),
            Section(name: ".data", offset: 0x60000, size: 0x10000, permissions: "rw-", hash: "data_hash_old"),
            Section(name: ".rodata", offset: 0x70000, size: 0x5000, permissions: "r--", hash: "rodata_hash"),
            Section(name: ".bss", offset: 0x80000, size: 0x2000, permissions: "rw-", hash: "bss_hash"),
        ],
        functions: [
            FunctionEntry(name: "main", offset: 0x1000, size: 500, complexity: 15, hash: "main_old"),
            FunctionEntry(name: "auth_user", offset: 0x2000, size: 200, complexity: 8, hash: "auth_old"),
            FunctionEntry(name: "validate_input", offset: 0x3000, size: 150, complexity: 6, hash: "validate_old"),
            FunctionEntry(name: "process_data", offset: 0x4000, size: 300, complexity: 12, hash: "process_old"),
            FunctionEntry(name: "unsafe_strcpy", offset: 0x5000, size: 50, complexity: 2, hash: "strcpy_hash"),
        ],
        imports: ["libc.so.6", "libssl.so.1.1", "libcrypto.so.1.1"],
        exports: ["app_init", "app_run", "app_cleanup"]
    )
}

func demoBinaryNew() -> BinaryInfo {
    BinaryInfo(
        path: "/usr/bin/app_v2.0",
        size: 1148576,
        hash: "f6e5d4c3b2a1",
        sections: [
            Section(name: ".text", offset: 0x1000, size: 0x58000, permissions: "r-x", hash: "text_hash_new"),
            Section(name: ".data", offset: 0x60000, size: 0x10000, permissions: "rw-", hash: "data_hash_new"),
            Section(name: ".rodata", offset: 0x70000, size: 0x5000, permissions: "r--", hash: "rodata_hash"),
            Section(name: ".bss", offset: 0x80000, size: 0x3000, permissions: "rw-", hash: "bss_hash_new"),
            Section(name: ".plt", offset: 0x90000, size: 0x1000, permissions: "r-x", hash: "plt_hash"),
        ],
        functions: [
            FunctionEntry(name: "main", offset: 0x1000, size: 600, complexity: 18, hash: "main_new"),
            FunctionEntry(name: "auth_user", offset: 0x2000, size: 350, complexity: 12, hash: "auth_new"),
            FunctionEntry(name: "validate_input", offset: 0x3000, size: 150, complexity: 6, hash: "validate_old"),
            FunctionEntry(name: "process_data", offset: 0x4000, size: 400, complexity: 15, hash: "process_new"),
            FunctionEntry(name: "new_feature", offset: 0x6000, size: 250, complexity: 10, hash: "feature_hash"),
        ],
        imports: ["libc.so.6", "libssl.so.3", "libcrypto.so.3", "libpthread.so.0"],
        exports: ["app_init", "app_run", "app_cleanup", "app_configure"]
    )
}

// Analyze binary differences
func analyzeDiff(old: BinaryInfo, new: BinaryInfo) -> DiffAnalysis {
    var sectionDiffs: [SectionDiff] = []
    var functionDiffs: [FunctionDiff] = []
    var importDiffs: [String: DiffType] = [:]
    var exportDiffs: [String: DiffType] = [:]
    
    // Compare sections
    let oldSectionNames = Set(old.sections.map { $0.name })
    let newSectionNames = Set(new.sections.map { $0.name })
    
    for section in old.sections {
        if let newSection = new.sections.first(where: { $0.name == section.name }) {
            if section.hash != newSection.hash {
                let severity: Severity = section.name == ".text" ? .high : .medium
                sectionDiffs.append(SectionDiff(
                    diffType: .modified,
                    oldSection: section,
                    newSection: newSection,
                    severity: severity,
                    reason: "Section content changed"
                ))
            }
        } else {
            sectionDiffs.append(SectionDiff(
                diffType: .removed,
                oldSection: section,
                newSection: nil,
                severity: .medium,
                reason: "Section removed"
            ))
        }
    }
    
    for section in new.sections where !oldSectionNames.contains(section.name) {
        sectionDiffs.append(SectionDiff(
            diffType: .added,
            oldSection: nil,
            newSection: section,
            severity: .low,
            reason: "New section added"
        ))
    }
    
    // Compare functions
    let oldFuncNames = Set(old.functions.map { $0.name })
    
    for func_ in old.functions {
        if let newFunc = new.functions.first(where: { $0.name == func_.name }) {
            if func_.hash != newFunc.hash {
                var changes: [String] = []
                if func_.size != newFunc.size {
                    changes.append("Size: \(func_.size)  \(newFunc.size)")
                }
                if func_.complexity != newFunc.complexity {
                    changes.append("Complexity: \(func_.complexity)  \(newFunc.complexity)")
                }
                
                let severity: Severity = isSecuritySensitive(func_.name) ? .high : .medium
                functionDiffs.append(FunctionDiff(
                    diffType: .modified,
                    oldFunc: func_,
                    newFunc: newFunc,
                    severity: severity,
                    changes: changes
                ))
            }
        } else {
            let severity: Severity = isSecuritySensitive(func_.name) ? .high : .low
            functionDiffs.append(FunctionDiff(
                diffType: .removed,
                oldFunc: func_,
                newFunc: nil,
                severity: severity,
                changes: ["Function removed"]
            ))
        }
    }
    
    for func_ in new.functions where !oldFuncNames.contains(func_.name) {
        functionDiffs.append(FunctionDiff(
            diffType: .added,
            oldFunc: nil,
            newFunc: func_,
            severity: .info,
            changes: ["New function"]
        ))
    }
    
    // Compare imports
    let oldImports = Set(old.imports)
    let newImports = Set(new.imports)
    
    for imp in oldImports.subtracting(newImports) {
        importDiffs[imp] = .removed
    }
    for imp in newImports.subtracting(oldImports) {
        importDiffs[imp] = .added
    }
    
    // Compare exports
    let oldExports = Set(old.exports)
    let newExports = Set(new.exports)
    
    for exp in oldExports.subtracting(newExports) {
        exportDiffs[exp] = .removed
    }
    for exp in newExports.subtracting(oldExports) {
        exportDiffs[exp] = .added
    }
    
    // Calculate similarity
    let totalItems = old.functions.count + new.functions.count
    let unchanged = old.functions.filter { oldF in
        new.functions.contains { $0.hash == oldF.hash }
    }.count * 2
    let similarity = totalItems > 0 ? Double(unchanged) / Double(totalItems) * 100 : 100
    
    return DiffAnalysis(
        oldBinary: old,
        newBinary: new,
        sectionDiffs: sectionDiffs,
        functionDiffs: functionDiffs,
        importDiffs: importDiffs,
        exportDiffs: exportDiffs,
        similarityScore: similarity
    )
}

// Print functions
func printBanner() {
    print()
    print("")
    print("            NullSec BinaryDiff - Binary Comparison Tool           ")
    print("")
    print()
}

func printUsage() {
    print("USAGE:")
    print("    binarydiff [OPTIONS]  ")
    print()
    print("OPTIONS:")
    print("    -h, --help       Show this help")
    print("    -j, --json       JSON output")
    print("    -f, --functions  Function-level diff only")
    print("    -s, --sections   Section-level diff only")
    print()
    print("EXAMPLES:")
    print("    binarydiff app_v1 app_v2")
    print("    binarydiff -f library.so.1 library.so.2")
}

func printSectionDiff(_ diff: SectionDiff) {
    let col = diff.severity.color
    let symbol: String
    switch diff.diffType {
    case .added: symbol = "+"
    case .removed: symbol = "-"
    case .modified: symbol = "~"
    case .unchanged: symbol = " "
    }
    
    let name = diff.newSection?.name ?? diff.oldSection?.name ?? "unknown"
    print()
    print("  \(col.rawValue)[\(symbol)] \(name)\(Color.reset.rawValue)")
    print("    Type:   \(diff.diffType.rawValue)")
    print("    Reason: \(diff.reason)")
    
    if let oldS = diff.oldSection, let newS = diff.newSection {
        if oldS.size != newS.size {
            print("    Size:   \(oldS.size)  \(newS.size)")
        }
    }
}

func printFunctionDiff(_ diff: FunctionDiff) {
    let col = diff.severity.color
    let sev = diff.severity.rawValue
    let symbol: String
    switch diff.diffType {
    case .added: symbol = "+"
    case .removed: symbol = "-"
    case .modified: symbol = "~"
    case .unchanged: symbol = " "
    }
    
    let name = diff.newFunc?.name ?? diff.oldFunc?.name ?? "unknown"
    let secMarker = isSecuritySensitive(name) ? " " : ""
    
    print()
    print("  \(col.rawValue)[\(sev)] \(symbol) \(name)\(secMarker)\(Color.reset.rawValue)")
    
    for change in diff.changes {
        print("     \(change)")
    }
}

func printSummary(_ analysis: DiffAnalysis) {
    print()
    print("\(Color.gray.rawValue)\(Color.reset.rawValue)")
    print()
    print("  Summary:")
    print("    Old Binary:  \(analysis.oldBinary.path)")
    print("    New Binary:  \(analysis.newBinary.path)")
    print("    Similarity:  \(String(format: "%.1f", analysis.similarityScore))%")
    print()
    print("  Changes:")
    print("    Sections:    \(analysis.sectionDiffs.filter { $0.diffType != .unchanged }.count)")
    print("    Functions:   \(analysis.functionDiffs.filter { $0.diffType != .unchanged }.count)")
    print("    Imports:     \(analysis.importDiffs.count)")
    print("    Exports:     \(analysis.exportDiffs.count)")
    
    let critCount = analysis.functionDiffs.filter { $0.severity == .critical }.count
    let highCount = analysis.functionDiffs.filter { $0.severity == .high }.count
    
    if critCount > 0 || highCount > 0 {
        print()
        print("  \(Color.red.rawValue)Security-Sensitive Changes: \(critCount + highCount)\(Color.reset.rawValue)")
    }
}

func demoMode() {
    print("\(Color.yellow.rawValue)[Demo Mode]\(Color.reset.rawValue)")
    print()
    print("\(Color.cyan.rawValue)Comparing sample binaries...\(Color.reset.rawValue)")
    
    let oldBinary = demoBinaryOld()
    let newBinary = demoBinaryNew()
    let analysis = analyzeDiff(old: oldBinary, new: newBinary)
    
    print()
    print("  Section Differences:")
    for diff in analysis.sectionDiffs {
        printSectionDiff(diff)
    }
    
    print()
    print("  Function Differences:")
    for diff in analysis.functionDiffs.sorted(by: { $0.severity.rawValue < $1.severity.rawValue }) {
        printFunctionDiff(diff)
    }
    
    if !analysis.importDiffs.isEmpty {
        print()
        print("  Import Changes:")
        for (name, type) in analysis.importDiffs {
            let symbol = type == .added ? "+" : "-"
            print("    [\(symbol)] \(name)")
        }
    }
    
    if !analysis.exportDiffs.isEmpty {
        print()
        print("  Export Changes:")
        for (name, type) in analysis.exportDiffs {
            let symbol = type == .added ? "+" : "-"
            print("    [\(symbol)] \(name)")
        }
    }
    
    printSummary(analysis)
}

// Main
printBanner()

let args = CommandLine.arguments
if args.count 

Web Proxy Viewer  |  New URL  |  Original Page