Master Volatility-based memory analysis — understanding why RAM holds evidence invisible to disk forensics, using pslist vs psscan to detect rootkit-hidden processes, extracting active network connections from memory dumps, detecting process injection via malfind, recovering NTLM credentials from LSASS, and reconstructing attacker command history even after bash history was deliberately cleared.
Memory Forensics Explained
Memory forensics is the analysis of a computer's live RAM to uncover evidence of malicious activity. Unlike disk forensics, memory analysis reveals what was running at the moment of capture — processes, network connections, decrypted data, injected code, and credentials that never touch the disk.
Sophisticated malware specifically avoids writing to disk to evade antivirus and EDR tools. Fileless malware, process injection, and in-memory payloads can only be found through memory analysis — making it an essential skill for advanced incident response. The evidence on disk is incomplete by design; memory is where the complete picture lives.
Why Memory Is a Different Forensic Tier
The order of volatility — the principle that evidence sources should be collected from most volatile to least volatile — places CPU registers and RAM at the top, followed by running processes and network connections, with disk data at the bottom. Memory at the top is not because it's more important but because it disappears first. Disk evidence can wait hours; memory evidence is gone the moment power fails or the system restarts.
Beyond volatility, memory reveals a category of evidence that simply cannot exist on disk. Encryption keys are loaded into memory to decrypt files — the keys may never be written to disk in any form. Injected malware code exists only in the memory of the target process. Credentials cached in LSASS are in memory only. Network connections are kernel data structures in memory that an attacker with admin access can manipulate to hide from the OS — but not from raw memory analysis, which bypasses OS abstractions entirely.
Imagine a building where every office has a combination of permanent filing cabinets (disk) and an active whiteboard (RAM). The filing cabinets hold everything that's been officially recorded and stored. The whiteboard holds the work currently in progress — calculations being performed, names and phone numbers being referenced in active conversations, open meeting notes, things that were useful now but haven't been filed yet. A thief who works carefully might leave nothing in the filing cabinets — every document shredded, every trace wiped. But the whiteboard shows exactly what they were doing at the moment they were interrupted. When you turn the lights off (power off), the whiteboard erases. Memory forensics is the science of reading the whiteboard before someone reaches for the light switch.
What Memory Reveals That Disk Cannot
Injected code Malware injected into legitimate process memory -- no disk file Decrypted data Encrypted files decrypted in RAM at access time -- key only in memory Network sockets Active C2 connections, including those hidden from OS-level netstat Credentials NTLM hashes, Kerberos tickets, plaintext passwords in LSASS Process hollowing Legitimate process shell with malicious payload inside -- no disk trace Rootkit artefacts Hooks, hidden processes, modified kernel structures in raw memory
Volatility Framework Core Commands
python3 vol.py -f memory.raw [plugin] windows.pslist Running processes from EPROCESS doubly-linked list windows.pstree Process tree showing parent-child relationships windows.psscan Raw EPROCESS structure scan -- finds processes hidden from pslist windows.netscan All network connections and listening sockets windows.cmdline Full command line arguments for each process windows.dlllist DLLs loaded into each process address space windows.malfind RWX memory regions with PE headers -- injection detection windows.hashdump Extract NTLM hashes from SAM/SYSTEM in memory
Memory Analysis in Practice
pslist reads the OS linked list — rootkits can remove entries from this list to hide. psscan scans raw memory for EPROCESS structures directly, bypassing the OS. A process in psscan but not pslist is hidden by a rootkit.
python3 vol.py -f memory.raw windows.pstree 648 winlogon.exe 772 svchost32.exe (not a real Windows process name) 1204 cmd.exe (child of suspicious process) python3 vol.py -f memory.raw windows.psscan PID 3321 rootkit_loader.exe (NOT in pslist -- hidden by rootkit) # PID 3321 is running but hidden from OS process list # Only raw memory scan reveals it -- this is the rootkit's persistence mechanism
netscan extracts all network connections from kernel memory structures — including those hidden from netstat by rootkits and connections made before the dump.
python3 vol.py -f memory.raw windows.netscan Proto LocalAddr ForeignAddr State PID Name TCPv4 10.0.1.55:49221 185.220.101.45:443 ESTABLISHED 772 svchost32.exe TCPv4 10.0.1.55:49301 10.0.0.5:445 ESTABLISHED 772 svchost32.exe # svchost32 has C2 connection AND internal SMB connection simultaneously # C2 beaconing to 185.220.101.45 + lateral movement to 10.0.0.5 in progress
malfind finds memory regions that are executable (PAGE_EXECUTE_READWRITE), not backed by any file on disk, and contain PE headers (MZ signature) — the classic indicators of injected code.
python3 vol.py -f memory.raw windows.malfind PID Process VPN Start Protect 1204 explorer.exe 0x1f0000 PAGE_EXECUTE_READWRITE Hexdump: 4d 5a 90 00 MZ... (PE header in RWX non-file-backed memory = injection) # Dump the injected region for malware triage analysis: python3 vol.py -f memory.raw windows.malfind --dump --pid 1204 # Output: pid.1204.0x1f0000.dmp -- analyse with malware triage workflow
Windows caches NTLM hashes in the LSASS process. hashdump extracts these forensically from a memory image — without running any tools on the live system that might alert the attacker.
python3 vol.py -f memory.raw windows.hashdump User NTLM Hash Administrator 8846f7eaee8fb117ad06bdd830b7586c jsmith c4b0e1b10c7ce2c4723b4e2407ef81a2 svc_backup 3b0086cd3a4a36b8f31e25ed5d3219c3 # All NTLM hashes from locally cached logon sessions # Every account here must be treated as fully compromised # Hashes can be cracked offline or used directly in Pass-the-Hash attacks
cmdline reconstructs the full command-line arguments for every process from kernel memory structures — even if the attacker cleared bash history or Event Log 4688 was not enabled.
python3 vol.py -f memory.raw windows.cmdline 772 svchost32.exe "C:\Users\Public\svchost32.exe" -c 185.220.101.45 -p 443 1204 cmd.exe cmd /c "whoami && net user /domain && nltest /domain_trusts" 3104 powershell.exe powershell -ep bypass -enc JABzAGgAZQBsAGwA... # C2 IP and port visible in svchost32 command line # Domain enumeration: whoami, net user /domain, nltest -- AD recon in progress # PowerShell encoded payload -- decode for IOC extraction
What You Need to Know
Full Plugin Reference — What to Run and When
A systematic memory forensics investigation follows a structured plugin sequence. Each plugin answers a specific question; together they reconstruct the complete picture of compromise. The sequence matters: start with process enumeration (the inventory), move to network connections (active communication), then drill into injection and credentials.
| Plugin | Question Answered | Key Evidence Fields | When to Use |
|---|---|---|---|
| windows.pstree | What processes are running, and who spawned them? | PID, PPID, process name, start time | Always first — identifies suspicious parent-child pairs |
| windows.psscan | Are any processes hidden from the OS? | Same fields but scanned raw — includes hidden processes | Always — compare to pslist, investigate any discrepancies |
| windows.netscan | What network connections exist? | Protocol, local/foreign addr, state, PID | Always — reveals C2 and lateral movement in progress |
| windows.cmdline | What exact commands were processes started with? | Full command line per process | Always — reveals C2 IPs in malware args, attacker recon commands |
| windows.malfind | Is code injected into any process? | PID, process, virtual address, memory protection, hex dump | When injection suspected (suspicious process with C2 connection) |
| windows.dlllist | What DLLs are loaded into each process? | Base address, DLL path, per-process | When DLL sideloading or reflective injection is suspected |
| windows.hashdump | What NTLM hashes are cached in LSASS? | Username, NTLM hash | After confirming compromise — maps all accounts at risk |
| windows.handles | What files/registry keys/mutexes does each process have open? | Handle type, name, PID | To identify mutex names (malware family IOC) and open file handles |
Process Injection Deep Dive
Process injection is the technique of running malicious code inside the memory space of a legitimate process. It serves two purposes: hiding (the malicious code appears to come from a trusted process like explorer.exe or svchost.exe) and privilege escalation (injecting into a higher-privileged process inherits that process's access token). Memory forensics detects injection precisely because it leaves specific memory signatures that malfind is designed to find.
Uses WriteProcessMemory to write the DLL path into the target process's memory, then CreateRemoteThread to call LoadLibrary — loading the malicious DLL into the target process's address space.
Memory signature: Unexpected DLL in the target process's DLL list (windows.dlllist) that is not present in other instances of the same process type, and has an unusual disk path (AppData, Temp, ProgramData).
Volatility detection: windows.dlllist --pid [target] shows all loaded DLLs. Any DLL outside System32/SysWOW64 in a system process is suspicious.
Creates a legitimate process in suspended state, unmaps (hollows out) its code section, and replaces it with malicious code before resuming. The process table shows the legitimate process name, but it executes malicious code.
Memory signature: The process's base executable image does not match what's on disk. The virtual address of the PE header in memory does not correspond to the file the process supposedly loaded from.
Volatility detection: windows.malfind finds RWX regions with PE headers in processes that should not have them. Dumping with --dump then comparing to disk image reveals the substitution.
After malfind identifies injected code, dump the region and analyse it with the malware triage workflow to extract C2 IOCs and identify the family.
# Step 1: malfind identifies injection in explorer.exe python3 vol.py -f memory.raw windows.malfind --pid 1204 PID 1204 explorer.exe 0x1f0000 PAGE_EXECUTE_READWRITE Hexdump: 4d 5a 90 00 03 00 00 00 (MZ header -- PE file injected) # Step 2: Dump the injected region to file python3 vol.py -f memory.raw windows.malfind --dump --pid 1204 Saved: pid.1204.0x1f0000.dmp # Step 3: Analyse the dumped region as a PE file strings pid.1204.0x1f0000.dmp | grep -E "http|gate|MUTEX|powershell" http://185.220.101.45/gate.php Global\CobaltStrikeMutex_4b2f # Cobalt Strike beacon injected into explorer.exe # C2 URL and mutex extracted as IOCs # Hash the dumped PE for VirusTotal lookup and threat intel correlation
Memory Acquisition on a Live Incident
Situation: EDR flags anomalous HTTPS traffic from explorer.exe (PID 1204) to 185.220.101.45 at 300-second intervals on CORP-WS-033. No malicious files detected on disk. AV scan clean. Suspicion: fileless malware operating entirely in memory.
Memory acquisition: WinPmem deployed via EDR remote execution to CORP-WS-033. Memory image acquired (8 GB): corp-ws-033-memory.raw. Timestamp: 2026-05-15 09:14:33. System NOT shut down — memory preserved for analysis. Image transferred to isolated analysis workstation.
windows.pstree: Normal-looking process tree. explorer.exe (PID 1204) present normally. No obviously suspicious process names. windows.psscan shows same results — no hidden processes (this is a stealthy injector, not a rootkit).
windows.netscan: explorer.exe (PID 1204) has ESTABLISHED TCP connection to 185.220.101.45:443 — confirmed. Also shows an internal SMB connection from the same PID to 10.0.0.5:445 (the file server) — lateral movement attempted.
windows.malfind on PID 1204: Finds one RWX memory region at 0x1f0000 with MZ header not backed by any file. Dumped to pid.1204.0x1f0000.dmp. String extraction: http://185.220.101.45/gate.php, Global\CobaltStrikeMutex, cobalt strike shellcode pattern in hex dump. Cobalt Strike beacon injected into explorer.exe confirmed.
windows.cmdline: explorer.exe command line normal. But cmd.exe (PID 3104, child of injected code): whoami && net user /domain && nltest /domain_trusts — AD enumeration commands visible in memory even though they completed and left no persistent log (4688 not enabled on this host).
windows.hashdump: Extracts Administrator hash and two other local account hashes. All three treated as compromised. AD credentials that were used on this host during the session are also in scope for reset.
Outcome: A machine that appeared clean on disk, with AV confirming no threats found, was running Cobalt Strike for an unknown period. Memory forensics was the only analysis technique that revealed the compromise. The injected PE hash, C2 IP, and mutex name are now IOCs for environment-wide hunting. The EPROCESS dump timestamp establishes the earliest proven compromise time for the incident timeline.
Core Concepts Summary
You've covered the theory. Now apply it hands-on in the simulated environment.
Start Lab — Memory Forensics→← Return to all labs