#!/usr/bin/env python3 """Wiper malware analyzer — analyze destructive malware targeting disk and file integrity.""" from __future__ import annotations import argparse import hashlib import json import re import sys from pathlib import Path def compute_hashes(filepath: str) -> dict: """Compute file hashes.""" data = Path(filepath).read_bytes() return { "md5": hashlib.md5(data).hexdigest(), "sha256": hashlib.sha256(data).hexdigest(), "size_bytes": len(data), } def identify_wiper_family(filepath: str) -> dict: """Identify the wiper family based on binary markers.""" data = Path(filepath).read_bytes() families = { "HermeticWiper": [b"epmntdrv", b"PhysicalDrive", b"IOCTL_DISK"], "WhisperGate": [b"tBGcYoHp", b"stage1", b"stage2", b"discord"], "CaddyWiper": [b"DsRoleGetPrimaryDomainInformation", b"\x00" * 100], "Shamoon": [b"Shamoon", b"elrawdsk", b"RawDisk", b"ArabianGulf"], "NotPetya": [b"wmic", b"perfc.dat", b"MFT", b"Petya"], "AcidRain": [b"/dev/mtd", b"/dev/block", b"MIPS"], "IsaacWiper": [b"isaac", b"RemoteAccess"], } result = {"family": "unknown", "confidence": "low", "markers": []} best_match = "" best_count = 0 for family, markers in families.items(): found = [m.decode("utf-8", errors="ignore") for m in markers if m in data] if len(found) > best_count: best_count = len(found) best_match = family result["markers"] = found if best_count >= 2: result["family"] = best_match result["confidence"] = "high" elif best_count == 1: result["family"] = best_match result["confidence"] = "medium" return result def analyze_disk_destruction(filepath: str) -> dict: """Analyze disk-level destruction capabilities.""" data = Path(filepath).read_bytes() indicators = { "raw_disk_access": False, "mbr_overwrite": False, "partition_destruction": False, "driver_abuse": False, "apis_found": [], } disk_apis = { b"PhysicalDrive": "raw_disk_access", b"\\\\.\\PhysicalDrive": "raw_disk_access", b"DeviceIoControl": "raw_disk_access", b"IOCTL_DISK": "raw_disk_access", b"SetFilePointer": "mbr_overwrite", b"NtWriteFile": "mbr_overwrite", b"CreateService": "driver_abuse", b"NtLoadDriver": "driver_abuse", b"ZwLoadDriver": "driver_abuse", } for api, category in disk_apis.items(): if api in data: indicators[category] = True indicators["apis_found"].append(api.decode("utf-8", errors="ignore")) # Check for partition table access patterns if b"\x55\xaa" in data or b"partition" in data.lower(): indicators["partition_destruction"] = True return indicators def analyze_file_destruction(filepath: str) -> dict: """Analyze file-level destruction capabilities.""" data = Path(filepath).read_bytes() indicators = { "file_overwrite": False, "file_deletion": False, "targeted_extensions": [], "overwrite_pattern": "unknown", "apis_found": [], } file_apis = [ b"CreateFileW", b"CreateFileA", b"WriteFile", b"DeleteFileW", b"DeleteFileA", b"RemoveDirectory", b"FindFirstFile", b"FindNextFile", ] for api in file_apis: if api in data: indicators["apis_found"].append(api.decode()) if b"Write" in api: indicators["file_overwrite"] = True if b"Delete" in api: indicators["file_deletion"] = True # Extract targeted extensions ext_pattern = rb'\.\w{2,4}' extensions = set() for match in re.finditer(ext_pattern, data): ext = match.group().decode("utf-8", errors="ignore").lower() if ext in (".doc", ".xls", ".pdf", ".jpg", ".png", ".sql", ".mdb", ".zip", ".bak", ".vmdk", ".ppt", ".docx", ".xlsx"): extensions.add(ext) indicators["targeted_extensions"] = sorted(extensions) return indicators def detect_embedded_drivers(filepath: str) -> list[dict]: """Detect embedded driver files in the binary.""" data = Path(filepath).read_bytes() drivers = [] # Look for PE signatures within the file (embedded executables) idx = 0 while True: idx = data.find(b"MZ", idx + 1) if idx == -1 or idx == 0: break # Check for valid PE header if idx + 0x3c < len(data): pe_offset_bytes = data[idx + 0x3c:idx + 0x40] if len(pe_offset_bytes) == 4: import struct pe_offset = struct.unpack_from(" dict: """Analyze anti-recovery techniques.""" data = Path(filepath).read_bytes() techniques = { "shadow_copy_deletion": False, "backup_destruction": False, "event_log_clearing": False, "boot_config_modification": False, "self_deletion": False, "commands_found": [], } checks = { b"vssadmin": "shadow_copy_deletion", b"shadowcopy": "shadow_copy_deletion", b"wbadmin": "backup_destruction", b"delete catalog": "backup_destruction", b"bcdedit": "boot_config_modification", b"recoveryenabled": "boot_config_modification", b"bootstatuspolicy": "boot_config_modification", b"wevtutil": "event_log_clearing", b"ClearEventLog": "event_log_clearing", b"SelfDelete": "self_deletion", b"MoveFileEx": "self_deletion", } for pattern, technique in checks.items(): if pattern in data: techniques[technique] = True techniques["commands_found"].append(pattern.decode("utf-8", errors="ignore")) return techniques def analyze_propagation(filepath: str) -> dict: """Analyze network propagation capabilities.""" data = Path(filepath).read_bytes() propagation = { "smb_spread": False, "wmi_spread": False, "credential_theft": False, "exploit_based": False, "indicators": [], } checks = { b"NetShareEnum": "smb_spread", b"ADMIN$": "smb_spread", b"IPC$": "smb_spread", b"WbemLocator": "wmi_spread", b"Win32_Process": "wmi_spread", b"ExecMethod": "wmi_spread", b"mimikatz": "credential_theft", b"sekurlsa": "credential_theft", b"lsadump": "credential_theft", b"EternalBlue": "exploit_based", b"MS17-010": "exploit_based", } for pattern, technique in checks.items(): if pattern in data: propagation[technique] = True propagation["indicators"].append(pattern.decode("utf-8", errors="ignore")) return propagation def main() -> None: parser = argparse.ArgumentParser(description="Wiper Malware Analyzer") parser.add_argument("--input", "--sample", required=True, help="Sample file path") parser.add_argument( "--mode", choices=["identify", "disk-destruction", "file-destruction", "driver", "propagation", "timeline", "anti-recovery", "full"], default="identify", help="Analysis mode", ) parser.add_argument("--output", default="wiper_analysis.json", help="Output file path") parser.add_argument("--format", choices=["json", "csv", "markdown"], default="json") args = parser.parse_args() sample_path = Path(args.sample) if not sample_path.exists(): print(f"[!] Sample not found: {args.sample}", file=sys.stderr) sys.exit(1) print(f"[*] Wiper Analysis — mode: {args.mode}") hashes = compute_hashes(args.sample) print(f"[*] SHA-256: {hashes['sha256']}") results = {"sample": args.sample, "hashes": hashes, "mode": args.mode} if args.mode == "identify": results["identification"] = identify_wiper_family(args.sample) elif args.mode == "disk-destruction": results["disk_destruction"] = analyze_disk_destruction(args.sample) elif args.mode == "file-destruction": results["file_destruction"] = analyze_file_destruction(args.sample) elif args.mode == "driver": results["embedded_drivers"] = detect_embedded_drivers(args.sample) elif args.mode == "propagation": results["propagation"] = analyze_propagation(args.sample) elif args.mode == "anti-recovery": results["anti_recovery"] = analyze_anti_recovery(args.sample) elif args.mode == "full": results["identification"] = identify_wiper_family(args.sample) results["disk_destruction"] = analyze_disk_destruction(args.sample) results["file_destruction"] = analyze_file_destruction(args.sample) results["embedded_drivers"] = detect_embedded_drivers(args.sample) results["propagation"] = analyze_propagation(args.sample) results["anti_recovery"] = analyze_anti_recovery(args.sample) output_path = Path(args.output) output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(json.dumps(results, indent=2)) print(f"[*] Results written to {args.output}") if __name__ == "__main__": main()