reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
Apache License 2.0 — see the repository root LICENSE file for the full text.
|
||||
|
||||
Copyright the AnalystAIPack contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: analyzing-malware-in-memory-with-volatility3
|
||||
description: 'Analyzes a memory image with Volatility 3 to find malware: rogue processes,
|
||||
injected code, suspicious network connections, loaded modules, and persistence, then
|
||||
extracts artifacts for further analysis. Activates for requests to do memory forensics,
|
||||
analyze a RAM dump, or hunt malware in memory with Volatility.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware
|
||||
- memory-forensics
|
||||
- volatility3
|
||||
- process-injection
|
||||
- dfir
|
||||
- windows
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1055
|
||||
- T1057
|
||||
- T1003
|
||||
- T1056
|
||||
d3fend:
|
||||
- D3-PSA
|
||||
- D3-PMAD
|
||||
references:
|
||||
- 'Volatility 3 documentation — https://volatility3.readthedocs.io/'
|
||||
- 'The Art of Memory Forensics (concepts) — https://www.memoryanalysis.net/'
|
||||
---
|
||||
|
||||
# Analyzing Malware in Memory with Volatility 3
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a RAM image from a suspected-infected host and need to find malicious activity.
|
||||
- Disk artifacts are insufficient (fileless/in-memory malware) and you need volatile evidence.
|
||||
- You want to extract injected code, command lines, or network connections for analysis.
|
||||
|
||||
**Do not use** Volatility plugins blindly without an order of investigation — start broad
|
||||
(processes, network) before deep per-process dumps.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Volatility 3 (`pip install volatility3`) with appropriate symbol tables.
|
||||
- A memory image acquired with a sound tool (WinPmem, LiME, or hypervisor snapshot).
|
||||
- Knowledge of the source OS/version to select the right symbols.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Work on a copy of the image; preserve the original with a recorded hash.
|
||||
- Treat any dumped executable region as a live sample — store and handle it accordingly.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Enumerate processes and spot anomalies
|
||||
|
||||
```bash
|
||||
vol -f memory.raw windows.pslist
|
||||
vol -f memory.raw windows.pstree
|
||||
```
|
||||
|
||||
Look for unusual parents (Word spawning cmd/powershell), masquerading names
|
||||
(`scvhost.exe`), processes with no disk path, and orphaned children.
|
||||
|
||||
### Step 2: Hunt injected code
|
||||
|
||||
```bash
|
||||
vol -f memory.raw windows.malfind
|
||||
```
|
||||
|
||||
`malfind` flags private, executable, RWX regions with no backing file — classic injection.
|
||||
Note the PID and base address for dumping.
|
||||
|
||||
### Step 3: Review network connections
|
||||
|
||||
```bash
|
||||
vol -f memory.raw windows.netscan
|
||||
```
|
||||
|
||||
Correlate listening/established connections with suspicious PIDs and the C2 endpoints from
|
||||
other analysis.
|
||||
|
||||
### Step 4: Check modules, handles, and persistence
|
||||
|
||||
Examine loaded DLLs (`windows.dlllist`), services, and registry (`windows.registry.*`) for
|
||||
persistence and unexpected modules.
|
||||
|
||||
### Step 5: Dump artifacts
|
||||
|
||||
Dump the suspicious process or injected region for static/RE analysis:
|
||||
|
||||
```bash
|
||||
vol -f memory.raw windows.dumpfiles --pid <pid>
|
||||
```
|
||||
|
||||
The helper script parses Volatility's JSON renderer output to highlight injection candidates.
|
||||
|
||||
```bash
|
||||
vol -f memory.raw -r json windows.malfind | python scripts/analyst.py malfind -
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
- Injection candidates from `malfind` correspond to anomalous processes from `pstree`.
|
||||
- Network connections map to known C2 or the sample's extracted config.
|
||||
- Dumped regions disassemble into meaningful code, not random bytes.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Wrong symbols/profile producing empty or garbage results — confirm OS build first.
|
||||
- Treating every RWX region as malicious; some legitimate JIT engines use RWX. Corroborate.
|
||||
- Forgetting to hash and preserve the original image before analysis.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the malfind output
|
||||
parser.
|
||||
- Volatility 3 documentation and memory-forensics concepts (linked in frontmatter).
|
||||
@@ -0,0 +1,40 @@
|
||||
# API Reference: Analyzing Malware in Memory with Volatility 3
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` consumes Volatility 3 `windows.malfind` JSON output and ranks memory
|
||||
regions by injection signal (RWX protection, embedded MZ header, executable prologue). It
|
||||
analyzes plugin output, not raw memory.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | JSON parsing |
|
||||
| volatility3 | >= 2.5 | Produces the memory-plugin output this tool consumes |
|
||||
|
||||
## External tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| Volatility 3 | Memory image analysis (pslist, pstree, malfind, netscan, dumpfiles) |
|
||||
| WinPmem / LiME | Memory acquisition |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `rank_malfind(doc)`
|
||||
Parses malfind rows and scores each by injection indicators, returning a sorted candidate
|
||||
list with PID, process, address, and protection.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
pip install volatility3
|
||||
vol -f memory.raw -r json windows.malfind | python scripts/analyst.py malfind -
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- Volatility 3 documentation — https://volatility3.readthedocs.io/
|
||||
- The Art of Memory Forensics — concepts of injection detection (malfind/RWX)
|
||||
- Volatility 3 JSON renderer output structure (project docs)
|
||||
@@ -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