Lesson 2 of 5 · 25 min read

Code Injection Detection — malfind, ldrmodules, and Hollowing

Understanding code injection requires understanding what legitimate process memory looks like — injection is the deviation from that baseline. Every technique leaves a different memory signature.


Injection Technique Memory Signatures

Technique              | VAD Protection    | File-backed? | In PEB lists? | MZ header?
───────────────────────────────────────────────────────────────────────────────────────
Legitimate DLL load    | PAGE_EXECUTE_READ | Yes (.dll)   | Yes (3/3)     | Yes
Process hollowing      | PAGE_EXECUTE_RW   | No (private) | N/A (EXE)     | Yes
Reflective DLL inj.    | PAGE_EXECUTE_RW   | No (private) | No (0/3)      | Yes
Shellcode injection    | PAGE_EXECUTE_RW   | No (private) | N/A           | Sometimes
PE injection           | PAGE_EXECUTE_RW   | No (private) | No (0/3)      | Yes

windows.malfind — Injection Triage

# Run malfind against all processes
vol.py -f memory.raw windows.malfind

# Output fields:
# Process Name | PID | Start | End | Tag | Protection | Hexdump | Disassembly

# Run against a specific PID
vol.py -f memory.raw windows.malfind --pid 4492

# Example malfind output (injection):
# PID: 4492  Name: svchost.exe
# Start: 0x1f0000  End: 0x23ffff
# VadS  Protection: PAGE_EXECUTE_READWRITE
# 4d 5a 90 00 03 00 00 00  MZ......
# The 0x4d5a (MZ) header confirms a PE image in private RWX memory

# Example malfind output (JIT false positive):
# PID: 8234  Name: chrome.exe
# Start: 0x7f0000  End: 0x8effff
# VadS  Protection: PAGE_EXECUTE_READ
# 55 8b ec 83 ec 20 ...    (x86 function prologue — no MZ header)
# → No MZ header = JIT code, not a PE image = likely false positive

# Dump the suspicious region for static analysis
vol.py -f memory.raw windows.malfind --pid 4492 --dump
# Output: pid.4492.vad.0x1f0000-0x23ffff.dmp
# Analyze with: file pid.4492.*.dmp; strings pid.4492.*.dmp; xxd pid.4492.*.dmp | head

windows.ldrmodules — Reflective Injection Detection

# Check module lists for a specific PID
vol.py -f memory.raw windows.ldrmodules --pid 4492

# Output columns:
# PID | Process | Base | InLoad | InMem | InInit | MappedPath

# Legitimate DLL (all True):
# 4492  svchost.exe  0x7ff6f0000000  True  True  True  \Windows\System32\svchost.exe

# Reflectively injected DLL (all False):
# 4492  svchost.exe  0x1f0000000000  False  False  False  (no path)

# Partially present (anomalous — may indicate manual PEB unlinking):
# 4492  svchost.exe  0x2a0000000000  True  True  False  \Windows\System32\ntdll.dll

# False/False/False with no MappedPath = reflective injection
# The DLL is in memory but the Windows loader has no knowledge of it

Process Hollowing Detection

# Step 1: Check if the process's in-memory executable base matches the on-disk binary
# windows.cmdline reveals if svchost is missing expected -k argument
vol.py -f memory.raw windows.cmdline --pid 4492
# Hollowed svchost: "C:\Windows\System32\svchost.exe" (no -k flag) = anomalous
# Legitimate svchost: "C:\Windows\System32\svchost.exe -k netsvcs -p"

# Step 2: Check the VAD for the main executable region
vol.py -f memory.raw windows.vadinfo --pid 4492 | head -30
# Legitimate: \Windows\System32\svchost.exe appears as a file-mapped region
# Hollowed: executable region shows as private (VadS) not file-mapped

# Step 3: Dump the in-memory executable for hash comparison
vol.py -f memory.raw windows.dumpfiles --pid 4492 --name svchost.exe
# OR use procdump:
vol.py -f memory.raw windows.dumpfiles -o 0x[EPROCESS_offset]

# Step 4: Hash the dumped executable
sha256sum pid.4492.0x*.dmp

# Step 5: Compare against known-good svchost hash
# Get reference hash from clean Windows system:
# sha256sum C:\Windows\System32\svchost.exe (on a clean system)
# Or use VirusTotal to look up the hash

Full Injection Investigation Workflow

#!/bin/bash
# Systematic injection investigation for a suspicious PID
PID=4492
MEMORY_IMAGE="memory.raw"
OUTPUT_DIR="./injection_analysis"
mkdir -p "$OUTPUT_DIR"

echo "[1] Process context"
vol.py -f "$MEMORY_IMAGE" windows.pslist --pid "$PID" > "$OUTPUT_DIR/01_pslist.txt"
vol.py -f "$MEMORY_IMAGE" windows.cmdline --pid "$PID" > "$OUTPUT_DIR/02_cmdline.txt"
vol.py -f "$MEMORY_IMAGE" windows.dlllist --pid "$PID" > "$OUTPUT_DIR/03_dlllist.txt"

echo "[2] Network connections"
vol.py -f "$MEMORY_IMAGE" windows.netscan | grep "$PID" > "$OUTPUT_DIR/04_netscan.txt"

echo "[3] Injection detection"
vol.py -f "$MEMORY_IMAGE" windows.malfind --pid "$PID" > "$OUTPUT_DIR/05_malfind.txt"
vol.py -f "$MEMORY_IMAGE" windows.ldrmodules --pid "$PID" > "$OUTPUT_DIR/06_ldrmodules.txt"
vol.py -f "$MEMORY_IMAGE" windows.vadinfo --pid "$PID" > "$OUTPUT_DIR/07_vadinfo.txt"

echo "[4] Dump suspicious regions for static analysis"
vol.py -f "$MEMORY_IMAGE" windows.malfind --pid "$PID" --dump \
  --output-dir "$OUTPUT_DIR/dumped/"

echo "[5] Privileges check"
vol.py -f "$MEMORY_IMAGE" windows.privileges --pid "$PID" > "$OUTPUT_DIR/08_privileges.txt"

echo "Investigation artifacts in $OUTPUT_DIR"