All posts

A memory analysis workflow that finds things

5 min read

A memory analysis is not a checklist. It is a workflow with five stages that feed each other: triage points at suspects, suspects open pivots, pivots set up deep analysis, deep analysis surfaces things carving corroborates, and everything lands in a report that ties claims to evidence. Skip a stage and you miss things. Run them in order and you catch what modern threats look like in 2026.

This version is built around ramparser for triage and Volatility 3 for depth. For the bird's-eye view of the discipline, read RAM forensics: tools, techniques, and a 2026 workflow. For the per-tool trade-offs see the memory forensics tools comparison.

Stage 1: Triage

The goal is one question: is anything obviously wrong? You are looking for smoke, not fire. The stage assumes you already have a memory image on disk; if not, the Magnet RAM Capture guide covers acquisition end-to-end.

Drop the image into ramparser. Within seconds:

  • pslist — the live process tree from kernel ActiveProcessLinks.
  • psscan — every _EPROCESS object the pool scanner finds.
  • psxview — the diff. A row in psscan missing from pslist is the classic DKOM-hidden- process signature.
  • pstree — parent / child relationships.

Scan for:

  • Unexpected names. A svchost.exe running from C:\Users\…\AppData instead of System32. A chrome.exe with no Chrome parent.
  • Mismatched parents. cmd.exe spawned by winword.exe, powershell.exe parented to a service that has no business launching shells.
  • Hidden rows. Anything HIDDEN in psxview gets a star.
  • Suspicious counts. Five lsass.exe. Three wininit.exe. There should be exactly one of each.

Triage's deliverable is a suspect list — typically 1 to 5 PIDs.

Stage 2: Pivot on suspects

Three pivots per suspect tell the story.

Command line (PEB)

cmdline reads the Process Environment Block and recovers the exact command line. This is where you catch:

  • Base64-encoded PowerShell.
  • Suspicious flags (-EncodedCommand, -WindowStyle Hidden, -NoProfile -ExecutionPolicy Bypass).
  • Paths to dropped binaries.
  • Beacon configuration hints.

Loaded modules

dlllist shows every module loaded into the process. Look for:

  • DLLs from %TEMP% or unusual paths.
  • DLLs with names mimicking system ones (one-letter-off typosquats).
  • Missing expected DLLs (a credential manager with no samlib.dll).

Network endpoints

netscan ties the process to the outside world:

  • Outbound to unusual ASNs or known C2 infrastructure.
  • Local listeners on high ports.
  • Established connections to addresses that do not fit the host's role.

When two of these three agree — a suspicious cmdline running from a strange path with an outbound to known-bad infrastructure — that is a real finding, not a hunch.

Stage 3: Deep analysis

Triage is fast and broad. Deep analysis is slow and precise. Volatility 3 earns its place here.

malfind

windows.malfind looks for memory regions that are executable, writable, and not backed by a file. The structural fingerprint of:

  • Reflective DLL injection.
  • Shellcode injection (VirtualAllocEx + WriteProcessMemory + CreateRemoteThread).
  • Process hollowing (when combined with mismatched image base).

A clean malfind does not mean nothing is there; a non-empty malfind is almost always worth investigating.

Kernel inspection

windows.modscan enumerates kernel modules from the pool. Compare against windows.modules (the live list) to find unlinked drivers — the kernel equivalent of a DKOM-hidden process. windows.callbacks and windows.ssdt reveal kernel hooks that user-mode telemetry cannot see.

YARA scans

windows.yarascan.YaraScan runs rules across process address spaces. Pair with curated rules (yara-rules/rules on GitHub) plus any internal detections. Fastest way to confirm a known-bad payload.

Timeline

timeliner.Timeliner builds an event timeline from every plugin that emits timestamps. Pipe to a CSV, load into Timesketch or a spreadsheet, and follow the activity around the suspect timeframe. Cross-reference against the on-disk timeline from the MFT, the USN journal, and EVTX for the strongest narrative.

Stage 4: Carve

Some evidence is not in structured objects — it is just bytes. bulk_extractor pulls:

  • E-mail addresses (phishing pivot point).
  • URLs and domain names (infrastructure pivot).
  • IP addresses (network pivot).
  • Credit cards, Bitcoin addresses, key material.
  • ZIP and JPEG headers (carving for embedded artefacts).

Cross-reference what bulk_extractor finds with what triage and pivoting showed. A C2 domain that appears in netscan and in raw strings is stronger than either alone.

Stage 5: Conclude and document

A memory analysis is only as good as its report. Tie every claim to specific evidence:

  • "PID 4128 (svchost.exe) was injected with shellcode" → cite the malfind row, the suspicious memory region, the parent PID.
  • "Outbound C2 to 203.0.113.5:443" → cite the netscan row, the associated process, and any matching bulk_extractor string hit.
  • "Credentials harvested via lsass.exe access" → cite the handle (handles plugin), the suspect PID, and any kernel callbacks that fired.

A finding without evidence is a guess. A guess in an IR report can cost the case.

What "done" looks like

  1. Every triage suspect has been resolved (false positive, here's why) or confirmed (here's the evidence).
  2. Deep-analysis plugins ran end-to-end, not just against suspects — you do not want to find out later that there was a second compromise you never looked at.
  3. The carving pass turned up nothing new, or what it turned up was reconciled with the structural findings.
  4. The timeline matches the suspected attack narrative — or, if it does not, the narrative gets updated.

Where ramparser fits

ramparser is the triage engine. It exists to make stage 1 disappear into the workflow — no environment, no symbol packs, no upload, just the answer. When triage points at something, you move to Volatility 3 for the rest.

Further reading