mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-10 21:24:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
197 lines
7.6 KiB
Python
197 lines
7.6 KiB
Python
#!/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)
|