#!/usr/bin/env python3 """Loader and dropper analyzer — analyze multi-stage malware delivery chains.""" from __future__ import annotations import argparse import hashlib import json import math import struct import sys from collections import Counter 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 calculate_entropy(data: bytes) -> float: """Calculate Shannon entropy.""" if not data: return 0.0 freq = Counter(data) length = len(data) return -sum((c / length) * math.log2(c / length) for c in freq.values()) def identify_delivery_type(filepath: str) -> dict: """Identify the delivery mechanism type.""" path = Path(filepath) data = path.read_bytes() suffix = path.suffix.lower() delivery = {"type": "unknown", "format": suffix, "indicators": []} magic_map = { b"\xd0\xcf\x11\xe0": "ole_document", b"PK": "zip_archive", b"CD001": "iso_image", b" list[dict]: """Analyze PE DLL exports for loader indicators.""" try: import pefile except ImportError: return [{"error": "pefile not installed"}] try: pe = pefile.PE(filepath) except Exception: return [] exports = [] if hasattr(pe, "DIRECTORY_ENTRY_EXPORT"): for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: name = exp.name.decode() if exp.name else f"ordinal_{exp.ordinal}" exports.append({ "name": name, "ordinal": exp.ordinal, "address": f"0x{exp.address:08x}", }) return exports def detect_injection_indicators(filepath: str) -> dict: """Detect process injection indicators in a PE binary.""" data = Path(filepath).read_bytes() injection_apis = { "process_hollowing": [ b"NtUnmapViewOfSection", b"ZwUnmapViewOfSection", b"WriteProcessMemory", b"NtWriteVirtualMemory", b"ResumeThread", b"NtResumeThread", ], "apc_injection": [ b"QueueUserAPC", b"NtQueueApcThread", ], "thread_hijacking": [ b"SuspendThread", b"SetThreadContext", b"GetThreadContext", ], "section_injection": [ b"NtCreateSection", b"NtMapViewOfSection", ], } results = {"techniques": [], "apis_found": []} for technique, apis in injection_apis.items(): found = [api.decode() for api in apis if api in data] if len(found) >= 2: results["techniques"].append(technique) results["apis_found"].extend(found) # Check for direct syscall stubs # Pattern: mov r10, rcx; mov eax, if b"\x4c\x8b\xd1\xb8" in data: results["techniques"].append("direct_syscalls") return results def extract_encrypted_resources(filepath: str) -> list[dict]: """Extract high-entropy resources that may contain encrypted payloads.""" try: import pefile except ImportError: return [{"error": "pefile not installed"}] try: pe = pefile.PE(filepath) except Exception: return [] resources = [] if hasattr(pe, "DIRECTORY_ENTRY_RESOURCE"): for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries: type_id = entry.id or (entry.name.string if entry.name else "unknown") if hasattr(entry, "directory"): for res in entry.directory.entries: if hasattr(res, "directory"): for lang in res.directory.entries: offset = lang.data.struct.OffsetToData size = lang.data.struct.Size data = pe.get_data(offset, size) entropy = calculate_entropy(data) resources.append({ "type_id": str(type_id), "size": size, "entropy": round(entropy, 2), "high_entropy": entropy > 7.0, "starts_with_mz": data[:2] == b"MZ", }) return resources def extract_c2_indicators(filepath: str) -> dict: """Extract C2 communication indicators from the binary.""" data = Path(filepath).read_bytes() indicators = { "urls": [], "ips": [], "user_agents": [], "protocols": [], } # Extract URLs import re url_pattern = rb'https?://[\x20-\x7e]{5,200}' for match in re.finditer(url_pattern, data): indicators["urls"].append(match.group().decode("ascii", errors="ignore")) # Extract IP:port patterns ip_pattern = rb'(?:\d{1,3}\.){3}\d{1,3}:\d{1,5}' for match in re.finditer(ip_pattern, data): indicators["ips"].append(match.group().decode()) # Check for HTTP-related strings if b"User-Agent:" in data or b"Content-Type:" in data: indicators["protocols"].append("HTTP") if b"CONNECT" in data and b"443" in data: indicators["protocols"].append("HTTPS_proxy") return indicators def main() -> None: parser = argparse.ArgumentParser(description="Loader & Dropper Analyzer") parser.add_argument("--input", "--sample", required=True, help="Sample file path") parser.add_argument( "--mode", choices=["delivery", "extract-macro", "sideload", "injection", "decrypt", "c2", "config", "chain"], default="delivery", help="Analysis mode", ) parser.add_argument("--output", default="loader_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"[*] Loader/Dropper Analysis — mode: {args.mode}") print(f"[*] Sample: {args.sample}") hashes = compute_hashes(args.sample) print(f"[*] SHA-256: {hashes['sha256']}") results = {"sample": args.sample, "hashes": hashes, "mode": args.mode} if args.mode == "delivery": results["delivery"] = identify_delivery_type(args.sample) elif args.mode == "sideload": results["exports"] = analyze_pe_exports(args.sample) elif args.mode == "injection": results["injection"] = detect_injection_indicators(args.sample) elif args.mode == "decrypt": results["encrypted_resources"] = extract_encrypted_resources(args.sample) elif args.mode == "c2": results["c2_indicators"] = extract_c2_indicators(args.sample) elif args.mode == "chain": results["delivery"] = identify_delivery_type(args.sample) results["exports"] = analyze_pe_exports(args.sample) results["injection"] = detect_injection_indicators(args.sample) results["encrypted_resources"] = extract_encrypted_resources(args.sample) results["c2_indicators"] = extract_c2_indicators(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()