#!/usr/bin/env python3
"""Android malware reverse engineering agent using jadx and androguard subprocess wrappers."""

import subprocess
import os
import sys
import re
import hashlib
from xml.etree import ElementTree


def compute_apk_hashes(apk_path):
    """Compute hashes for APK identification."""
    with open(apk_path, "rb") as f:
        data = f.read()
    return {
        "md5": hashlib.md5(data).hexdigest(),
        "sha256": hashlib.sha256(data).hexdigest(),
        "size": len(data),
    }


def extract_manifest(apk_path, output_dir):
    """Extract and parse AndroidManifest.xml using apktool."""
    subprocess.run(
        ["apktool", "d", apk_path, "-o", output_dir, "-f"],
        capture_output=True, text=True, timeout=120
    )
    manifest_path = os.path.join(output_dir, "AndroidManifest.xml")
    if not os.path.exists(manifest_path):
        return {"error": "Manifest extraction failed"}
    tree = ElementTree.parse(manifest_path)
    root = tree.getroot()
    ns = {"android": "http://schemas.android.com/apk/res/android"}
    permissions = []
    for perm in root.findall(".//uses-permission"):
        name = perm.get(f"{{{ns['android']}}}name", "")
        permissions.append(name)
    activities = []
    for act in root.findall(".//activity"):
        name = act.get(f"{{{ns['android']}}}name", "")
        exported = act.get(f"{{{ns['android']}}}exported", "false")
        activities.append({"name": name, "exported": exported})
    services = []
    for svc in root.findall(".//service"):
        name = svc.get(f"{{{ns['android']}}}name", "")
        services.append(name)
    receivers = []
    for rcv in root.findall(".//receiver"):
        name = rcv.get(f"{{{ns['android']}}}name", "")
        intents = []
        for intent in rcv.findall(".//intent-filter/action"):
            intents.append(intent.get(f"{{{ns['android']}}}name", ""))
        receivers.append({"name": name, "intents": intents})
    package = root.get("package", "")
    return {
        "package": package,
        "permissions": permissions,
        "activities": activities,
        "services": services,
        "receivers": receivers,
    }


DANGEROUS_PERMISSIONS = [
    "android.permission.READ_SMS", "android.permission.SEND_SMS",
    "android.permission.RECEIVE_SMS", "android.permission.READ_CONTACTS",
    "android.permission.CAMERA", "android.permission.RECORD_AUDIO",
    "android.permission.ACCESS_FINE_LOCATION", "android.permission.READ_PHONE_STATE",
    "android.permission.CALL_PHONE", "android.permission.READ_CALL_LOG",
    "android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE",
    "android.permission.SYSTEM_ALERT_WINDOW", "android.permission.BIND_ACCESSIBILITY_SERVICE",
    "android.permission.REQUEST_INSTALL_PACKAGES", "android.permission.BIND_DEVICE_ADMIN",
]


def analyze_permissions(permissions):
    """Classify permissions by risk level."""
    dangerous = [p for p in permissions if p in DANGEROUS_PERMISSIONS]
    sms_related = [p for p in permissions if "SMS" in p]
    accessibility = [p for p in permissions if "ACCESSIBILITY" in p]
    admin = [p for p in permissions if "DEVICE_ADMIN" in p or "BIND_ADMIN" in p]
    risk = "LOW"
    if len(dangerous) > 5:
        risk = "HIGH"
    if sms_related or accessibility or admin:
        risk = "CRITICAL"
    return {
        "total": len(permissions),
        "dangerous": dangerous,
        "sms_related": sms_related,
        "accessibility": accessibility,
        "device_admin": admin,
        "risk": risk,
    }


def decompile_with_jadx(apk_path, output_dir):
    """Decompile APK to Java source using JADX."""
    result = subprocess.run(
        ["jadx", "-d", output_dir, "--deobf", apk_path],
        capture_output=True, text=True, timeout=300
    )
    return {
        "output_dir": output_dir,
        "returncode": result.returncode,
        "stdout": result.stdout[-500:] if result.stdout else "",
    }


def search_source_code(source_dir, patterns=None):
    """Search decompiled source for suspicious patterns."""
    if patterns is None:
        patterns = {
            "urls": r'https?://[^\s"\'<>]+',
            "ips": r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b',
            "crypto_keys": r'(?:AES|DES|RSA|key|secret|encrypt).*?["\']([^"\']{8,})["\']',
            "base64_strings": r'[A-Za-z0-9+/]{40,}={0,2}',
            "exec_commands": r'Runtime\.getRuntime\(\)\.exec|ProcessBuilder',
            "reflection": r'Class\.forName|getMethod|getDeclaredMethod',
            "dex_loading": r'DexClassLoader|PathClassLoader|InMemoryDexClassLoader',
            "overlay_attack": r'TYPE_APPLICATION_OVERLAY|SYSTEM_ALERT_WINDOW',
            "accessibility_abuse": r'AccessibilityService|onAccessibilityEvent',
            "sms_intercept": r'SmsReceiver|SMS_RECEIVED|sendTextMessage',
        }
    findings = {p: [] for p in patterns}
    for root, dirs, files in os.walk(source_dir):
        for filename in files:
            if not filename.endswith(".java"):
                continue
            filepath = os.path.join(root, filename)
            try:
                with open(filepath, "r", errors="ignore") as f:
                    content = f.read()
                for pattern_name, regex in patterns.items():
                    matches = re.findall(regex, content)
                    if matches:
                        findings[pattern_name].extend([
                            {"file": filepath, "match": m[:100]} for m in matches[:5]
                        ])
            except (OSError, UnicodeDecodeError):
                pass
    for key in findings:
        findings[key] = findings[key][:20]
    return findings


def analyze_apk(apk_path, output_base="/tmp/apk_analysis"):
    """Full APK analysis pipeline."""
    os.makedirs(output_base, exist_ok=True)
    report = {"apk": apk_path}
    report["hashes"] = compute_apk_hashes(apk_path)
    apktool_dir = os.path.join(output_base, "apktool")
    report["manifest"] = extract_manifest(apk_path, apktool_dir)
    if "permissions" in report["manifest"]:
        report["permission_analysis"] = analyze_permissions(report["manifest"]["permissions"])
    jadx_dir = os.path.join(output_base, "jadx_output")
    report["decompilation"] = decompile_with_jadx(apk_path, jadx_dir)
    if os.path.exists(jadx_dir):
        source_dir = os.path.join(jadx_dir, "sources")
        if os.path.exists(source_dir):
            report["code_analysis"] = search_source_code(source_dir)
    return report


def print_report(report):
    print("Android Malware Analysis Report")
    print("=" * 50)
    print(f"APK: {report['apk']}")
    print(f"SHA-256: {report['hashes']['sha256']}")
    print(f"Size: {report['hashes']['size']} bytes")
    manifest = report.get("manifest", {})
    print(f"\nPackage: {manifest.get('package', 'N/A')}")
    perm = report.get("permission_analysis", {})
    print(f"Permissions: {perm.get('total', 0)} (Risk: {perm.get('risk', 'N/A')})")
    if perm.get("dangerous"):
        print(f"  Dangerous: {', '.join(p.split('.')[-1] for p in perm['dangerous'][:8])}")
    print(f"Activities: {len(manifest.get('activities', []))}")
    print(f"Services: {len(manifest.get('services', []))}")
    print(f"Receivers: {len(manifest.get('receivers', []))}")
    code = report.get("code_analysis", {})
    if code:
        print("\nCode Analysis Findings:")
        for pattern, matches in code.items():
            if matches:
                print(f"  {pattern}: {len(matches)} match(es)")
                for m in matches[:3]:
                    print(f"    -> {m['match'][:80]}")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python agent.py <apk_file>")
        sys.exit(1)
    result = analyze_apk(sys.argv[1])
    print_report(result)
