Files
Anthropic-Cybersecurity-Skills/skills/analyzing-windows-amcache-artifacts/scripts/agent.py
T
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- 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
2026-03-19 13:26:49 +01:00

165 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""Windows Amcache.hve forensic analysis agent.
Parses Amcache.hve registry hive to extract program execution history,
file metadata, and device information using the regipy library.
"""
import argparse
import json
import sys
import datetime
try:
from regipy.registry import RegistryHive
HAS_REGIPY = True
except ImportError:
HAS_REGIPY = False
AMCACHE_FILE_KEY = "Root\InventoryApplicationFile"
AMCACHE_APP_KEY = "Root\InventoryApplication"
AMCACHE_DEVICE_KEY = "Root\InventoryDevicePnp"
AMCACHE_DRIVER_KEY = "Root\InventoryDriverBinary"
SUSPICIOUS_PATHS = [
"\\temp\\", "\\tmp\\", "\\appdata\\local\\temp",
"\\downloads\\", "\\public\\", "\\programdata\\",
"\\recycle", "\\users\\public",
]
SUSPICIOUS_NAMES = [
"mimikatz", "psexec", "lazagne", "procdump", "rubeus",
"sharphound", "bloodhound", "cobalt", "beacon",
"powershell_ise", "certutil", "mshta",
]
def parse_amcache_files(hive_path):
"""Parse InventoryApplicationFile entries from Amcache.hve."""
if not HAS_REGIPY:
return {"error": "regipy not installed. pip install regipy"}
try:
reg = RegistryHive(hive_path)
entries = []
for subkey in reg.get_key(AMCACHE_FILE_KEY).iter_subkeys():
values = {v.name: v.value for v in subkey.iter_values()}
entries.append({
"name": values.get("Name", ""),
"lower_case_path": values.get("LowerCaseLongPath", ""),
"publisher": values.get("Publisher", ""),
"version": values.get("Version", ""),
"sha1": values.get("FileId", "").lstrip("0000").lower() if values.get("FileId") else "",
"size": values.get("Size", 0),
"link_date": values.get("LinkDate", ""),
"program_id": values.get("ProgramId", ""),
"last_modified": subkey.header.last_modified.isoformat() if subkey.header.last_modified else "",
})
return entries
except Exception as e:
return {"error": str(e)}
def parse_amcache_apps(hive_path):
"""Parse InventoryApplication entries."""
if not HAS_REGIPY:
return {"error": "regipy not installed"}
try:
reg = RegistryHive(hive_path)
apps = []
for subkey in reg.get_key(AMCACHE_APP_KEY).iter_subkeys():
values = {v.name: v.value for v in subkey.iter_values()}
apps.append({
"name": values.get("Name", ""),
"version": values.get("Version", ""),
"publisher": values.get("Publisher", ""),
"install_date": values.get("InstallDate", ""),
"source": values.get("Source", ""),
"uninstall_string": values.get("UninstallString", ""),
"registry_key_path": values.get("RegistryKeyPath", ""),
})
return apps
except Exception as e:
return {"error": str(e)}
def detect_suspicious(entries):
"""Flag suspicious entries based on path and name patterns."""
findings = []
for entry in entries:
if isinstance(entry, dict) and "error" not in entry:
path = entry.get("lower_case_path", "").lower()
name = entry.get("name", "").lower()
reasons = []
for sp in SUSPICIOUS_PATHS:
if sp in path:
reasons.append(f"Suspicious path: {sp}")
for sn in SUSPICIOUS_NAMES:
if sn in name:
reasons.append(f"Suspicious name: {sn}")
if not entry.get("publisher"):
reasons.append("Missing publisher metadata")
if reasons:
findings.append({
"name": entry.get("name", ""),
"path": entry.get("lower_case_path", ""),
"sha1": entry.get("sha1", ""),
"reasons": reasons,
})
return findings
def main():
parser = argparse.ArgumentParser(description="Amcache.hve forensic analysis agent")
parser.add_argument("hive", nargs="?", help="Path to Amcache.hve file")
parser.add_argument("--apps", action="store_true", help="Parse InventoryApplication entries")
parser.add_argument("--suspicious-only", action="store_true", help="Show only suspicious entries")
parser.add_argument("--output", "-o", help="Output JSON report path")
args = parser.parse_args()
print("[*] Amcache.hve Forensic Analysis Agent")
print(f" regipy available: {HAS_REGIPY}")
if not args.hive:
print("\n[DEMO] Amcache.hve location: C:\\Windows\\AppCompat\\Programs\\Amcache.hve")
print(" Usage: python agent.py Amcache.hve [--apps] [--suspicious-only]")
print(" Extracts: file paths, SHA-1 hashes, publisher, timestamps, install info")
print(json.dumps({"demo": True, "regipy_available": HAS_REGIPY}, indent=2))
sys.exit(0)
report = {"timestamp": datetime.datetime.utcnow().isoformat() + "Z", "hive": args.hive}
files = parse_amcache_files(args.hive)
if isinstance(files, list):
report["file_entries"] = len(files)
suspicious = detect_suspicious(files)
report["suspicious_count"] = len(suspicious)
if args.suspicious_only:
report["findings"] = suspicious
else:
report["entries"] = files[:100]
report["suspicious"] = suspicious
print(f"[*] File entries: {len(files)}")
print(f"[*] Suspicious: {len(suspicious)}")
for s in suspicious[:10]:
print(f" [!] {s['name']}: {', '.join(s['reasons'])}")
else:
report["error"] = files
if args.apps:
apps = parse_amcache_apps(args.hive)
if isinstance(apps, list):
report["app_entries"] = len(apps)
print(f"[*] Application entries: {len(apps)}")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(json.dumps({"file_entries": report.get("file_entries", 0),
"suspicious": report.get("suspicious_count", 0)}, indent=2))
if __name__ == "__main__":
main()