reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Parse Volatility 3 JSON output to highlight likely process-injection candidates.
|
||||
|
||||
Volatility 3 can render plugin output as JSON (``vol -r json ...``). This tool consumes a
|
||||
``windows.malfind`` JSON document (from a file or stdin) and ranks regions by injection
|
||||
signal: RWX protection and the presence of an MZ header or executable prologue bytes.
|
||||
|
||||
It analyzes plugin output only; it does not parse raw memory itself.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
def _rows(doc) -> list[dict]:
|
||||
# Volatility 3 JSON renderer emits a list of row dicts; tolerate a wrapped form.
|
||||
if isinstance(doc, list):
|
||||
return doc
|
||||
if isinstance(doc, dict):
|
||||
for key in ("rows", "data"):
|
||||
if isinstance(doc.get(key), list):
|
||||
return doc[key]
|
||||
return []
|
||||
|
||||
|
||||
def rank_malfind(doc) -> list[dict]:
|
||||
out = []
|
||||
for row in _rows(doc):
|
||||
prot = str(row.get("Protection", row.get("protection", ""))).upper()
|
||||
disasm = str(row.get("Disasm", row.get("disasm", "")))
|
||||
hexdump = str(row.get("Hexdump", row.get("hexdump", "")))
|
||||
score = 0
|
||||
if "EXECUTE_READWRITE" in prot or "RWX" in prot:
|
||||
score += 3
|
||||
if "4D 5A" in hexdump or hexdump.lstrip().startswith("MZ"):
|
||||
score += 3 # PE header in an injected region
|
||||
if any(op in disasm for op in ("push", "mov", "call", "jmp")):
|
||||
score += 1
|
||||
out.append({
|
||||
"pid": row.get("PID", row.get("pid")),
|
||||
"process": row.get("Process", row.get("process")),
|
||||
"address": row.get("Start VPN", row.get("Address", row.get("address"))),
|
||||
"protection": prot,
|
||||
"injection_score": score,
|
||||
})
|
||||
return sorted(out, key=lambda r: r["injection_score"], reverse=True)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Rank Volatility malfind output")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("malfind")
|
||||
p.add_argument("json", help="path to malfind JSON, or - for stdin")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
text = sys.stdin.read() if args.json == "-" else open(args.json, encoding="utf-8").read()
|
||||
doc = json.loads(text)
|
||||
print(json.dumps(rank_malfind(doc), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user