Memory Forensics: How to Analyze RAM Dumps to Find Hidden Malware

Memory forensics — analyzing the contents of a computer’s RAM — is one of the most powerful techniques in incident response. Malware often hides in memory, leaving no traces on disk. Encryption keys, command-and-control communications, running processes, and network connections that aren’t visible in logs may be captured in a memory dump. This guide introduces memory forensics using the free and powerful Volatility framework.

Why Memory Forensics Matters

Modern malware uses “fileless” techniques that operate entirely in memory:

  • PowerShell scripts run in memory without writing to disk
  • Process injection (code injected into legitimate processes like svchost.exe)
  • Reflective DLL injection (DLLs loaded without touching disk)
  • Living-off-the-land (using built-in Windows tools: certutil, mshta, wscript)

Capturing a Memory Dump

# Windows - free tools:
# WinPmem (open source):
winpmem.exe -o memory.raw

# Belkasoft RAM Capturer (free):
# Download from: belkasoft.com/ram-capturer
# Run as administrator -> save image

# For VMs (VMware): Suspend VM, .vmem file IS the memory dump
# For VMs (Hyper-V): 
Get-VM "VM Name" | Save-VMState  # Creates .bin file

# Linux:
sudo dd if=/dev/mem of=/tmp/memory.dmp bs=1M
# Or use LiME (more complete):
sudo insmod lime.ko "path=/tmp/memory.dmp format=lime"

Volatility 3: The Essential Tool

# Install Volatility 3:
git clone https://github.com/volatilityfoundation/volatility3.git
cd volatility3
pip install -e .

# Basic usage:
python vol.py -f memory.raw PLUGIN

# Key plugins for Windows analysis:

# List running processes:
python vol.py -f memory.raw windows.pslist

# Process tree (shows parent-child relationships):
python vol.py -f memory.raw windows.pstree

# Network connections at time of capture:
python vol.py -f memory.raw windows.netstat

# DLLs loaded by each process:
python vol.py -f memory.raw windows.dlllist --pid 1234

# Find injected code (process hollowing, injection):
python vol.py -f memory.raw windows.malfind

# Extract strings from memory (find C2 domains, commands):
python vol.py -f memory.raw windows.strings | grep -E "http|cmd|powershell"

# Registry hive in memory:
python vol.py -f memory.raw windows.registry.hivelist
python vol.py -f memory.raw windows.registry.printkey --key "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"

Hunting for Malware in Memory

# Red flags to look for:

# 1. Suspicious parent-child relationships:
python vol.py -f memory.raw windows.pstree
# SUSPICIOUS:
# svchost.exe -> powershell.exe  (svchost should not spawn powershell!)
# explorer.exe -> cmd.exe -> nc.exe  (reverse shell)
# winword.exe -> wscript.exe  (macro malware)

# 2. Processes with injected code (malfind):
python vol.py -f memory.raw windows.malfind
# malfind finds memory regions with:
# - PAGE_EXECUTE_READWRITE permission (writable + executable = suspicious)
# - MZ header (PE file) in non-expected location

# 3. Network connections to unknown IPs:
python vol.py -f memory.raw windows.netstat | grep ESTABLISHED
# Look for: svchost.exe connecting to 185.x.x.x on port 443 (C2 via HTTPS)

# 4. Loaded unsigned DLLs:
python vol.py -f memory.raw windows.dlllist --pid SUSPICIOUS_PID | grep -v "Microsoft"

# 5. Extract suspicious processes for AV scanning:
python vol.py -f memory.raw windows.dumpfiles --pid SUSPICIOUS_PID
# Submit extracted files to VirusTotal

Real Case: Finding a RAT in Memory

# Example investigation workflow:

# Step 1: Check for unexpected network connections:
python vol.py -f memory.raw windows.netstat | grep ESTABLISHED
# Found: PID 4872 (svchost.exe) connecting to 185.234.x.x:443

# Step 2: Why is THIS svchost connecting to an external IP?
python vol.py -f memory.raw windows.pstree | grep 4872
# Parent: services.exe (normal for svchost)
# But other details look wrong...

# Step 3: Check for injected code:
python vol.py -f memory.raw windows.malfind | grep 4872
# Found! MZ header in executable memory region within svchost = process injection!

# Step 4: Extract the injected code:
python vol.py -f memory.raw windows.dumpfiles --physaddr 0x... 
# Submit to VirusTotal -> detected as Cobalt Strike beacon

# Step 5: Find C2 in extracted code:
strings injected_code.dmp | grep -oP '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}'
# Found: 185.234.218.99 - attacker's C2 server

Wrap Up

Memory forensics reveals what disk forensics misses. If you encounter a suspected compromise, capture memory before doing anything else — before rebooting, before killing processes, before pulling the network cable. Volatility makes memory analysis accessible to any security professional. The malfind and netstat plugins alone will find indicators of compromise in most memory dumps.