#!/usr/bin/env python3 """Agent for extracting memory forensic artifacts using Rekall.""" import json import argparse from datetime import datetime from rekall import session from rekall import plugins def create_session(image_path, profile_path=None): """Create a Rekall session for a memory image.""" kwargs = { "filename": image_path, "autodetect": ["rsds"], } if profile_path: kwargs["profile_path"] = [profile_path] else: kwargs["profile_path"] = [ "https://github.com/google/rekall-profiles/raw/master" ] return session.Session(**kwargs) def list_processes(s): """List all processes using pslist plugin.""" processes = [] for proc in s.plugins.pslist(): processes.append({ "pid": int(proc.pid), "ppid": int(proc.ppid), "name": str(proc.name), "create_time": str(getattr(proc, "create_time", "")), }) return processes def find_hidden_processes(s): """Detect hidden processes by comparing pslist vs psscan.""" pslist_pids = {} for proc in s.plugins.pslist(): pslist_pids[int(proc.pid)] = str(proc.name) psscan_pids = {} for proc in s.plugins.psscan(): psscan_pids[int(proc.pid)] = str(proc.name) hidden = [] for pid, name in psscan_pids.items(): if pid not in pslist_pids and pid > 0: hidden.append({"pid": pid, "name": name, "detection": "psscan only"}) return hidden def detect_code_injection(s): """Detect injected code using malfind plugin (VAD analysis).""" injections = [] for result in s.plugins.malfind(): injections.append({ "pid": int(getattr(result, "pid", 0)), "process": str(getattr(result, "name", "")), "address": hex(getattr(result, "address", 0)), "protection": str(getattr(result, "protection", "")), "tag": str(getattr(result, "tag", "")), }) return injections def list_network_connections(s): """List network connections using netscan plugin.""" connections = [] for conn in s.plugins.netscan(): connections.append({ "pid": int(getattr(conn, "pid", 0)), "local_addr": str(getattr(conn, "local_addr", "")), "remote_addr": str(getattr(conn, "remote_addr", "")), "state": str(getattr(conn, "state", "")), "protocol": str(getattr(conn, "protocol", "")), }) return connections def list_dlls(s, target_pid=None): """List loaded DLLs for processes using dlllist plugin.""" dlls = [] for entry in s.plugins.dlllist(pids=[target_pid] if target_pid else None): dlls.append({ "pid": int(getattr(entry, "pid", 0)), "process": str(getattr(entry, "name", "")), "dll_path": str(getattr(entry, "path", "")), "base": hex(getattr(entry, "base", 0)), "size": int(getattr(entry, "size", 0)), }) return dlls def check_drivers(s): """List loaded kernel drivers using modules plugin.""" drivers = [] for mod in s.plugins.modules(): drivers.append({ "name": str(getattr(mod, "name", "")), "base": hex(getattr(mod, "base", 0)), "size": int(getattr(mod, "size", 0)), }) return drivers def analyze_vad(s, target_pid): """Analyze Virtual Address Descriptor tree for a process.""" vad_entries = [] for entry in s.plugins.vadinfo(pids=[target_pid]): vad_entries.append({ "start": hex(getattr(entry, "start", 0)), "end": hex(getattr(entry, "end", 0)), "protection": str(getattr(entry, "protection", "")), "tag": str(getattr(entry, "tag", "")), "filename": str(getattr(entry, "filename", "")), }) return vad_entries def main(): parser = argparse.ArgumentParser(description="Rekall Memory Forensics Agent") parser.add_argument("--image", required=True, help="Path to memory image") parser.add_argument("--profile-path", help="Path to Rekall profiles") parser.add_argument("--pid", type=int, help="Target PID for focused analysis") parser.add_argument("--output", default="rekall_report.json") parser.add_argument("--action", choices=[ "pslist", "hidden", "malfind", "netscan", "dlls", "full_analysis" ], default="full_analysis") args = parser.parse_args() s = create_session(args.image, args.profile_path) report = {"image": args.image, "generated_at": datetime.utcnow().isoformat(), "findings": {}} if args.action in ("pslist", "full_analysis"): procs = list_processes(s) report["findings"]["processes"] = procs print(f"[+] Processes found: {len(procs)}") if args.action in ("hidden", "full_analysis"): hidden = find_hidden_processes(s) report["findings"]["hidden_processes"] = hidden print(f"[+] Hidden processes: {len(hidden)}") if args.action in ("malfind", "full_analysis"): injections = detect_code_injection(s) report["findings"]["code_injection"] = injections print(f"[+] Code injections detected: {len(injections)}") if args.action in ("netscan", "full_analysis"): conns = list_network_connections(s) report["findings"]["network_connections"] = conns print(f"[+] Network connections: {len(conns)}") if args.action in ("dlls", "full_analysis"): drivers = check_drivers(s) report["findings"]["kernel_drivers"] = drivers print(f"[+] Kernel drivers: {len(drivers)}") with open(args.output, "w") as f: json.dump(report, f, indent=2, default=str) print(f"[+] Report saved to {args.output}") if __name__ == "__main__": main()