Skip to content
All posts
forensicsrevised March 3, 20264 min read

Memory dump triage: what was running, what was typed, what was on disk

A raw memory image answers three questions and you should ask them in that order. Why psscan beats pslist for a challenge, where command lines actually live, and how to get from a dump to a registry hive.

A .raw, .mem, .vmem or .dmp file is a photograph of everything a machine was thinking at one instant. That sounds like a lot to search and it is - but the questions a challenge asks of it are almost always the same three, and asking them in the right order turns gigabytes into a page.

  1. What was running? The process list, including things that had already exited.
  2. What was typed or executed? Command lines, console history, clipboard.
  3. What was on disk? Registry hives, file objects, and cached file contents.

pslist and psscan are not the same question

This is the distinction that decides whether you find the answer. pslist walks the kernel's own doubly-linked list of active processes from a known pointer. It is fast, it is accurate, and it can only ever show you what the kernel still considers to be running.

psscan ignores the list entirely and scans the whole image for Proc pool allocations - the memory the kernel allocated for each process object. Those allocations survive process exit until the memory is reused, so psscan finds terminated processes. In an incident, that is the malware that ran and quit. In a CTF, that is very often the entire point.

The cost of the scanning approach is that it needs validation rather than trust. A four-byte tag matches by chance in ordinary data, so anything that claims to be a process has to be checked: does the name field look like a name, is there a plausible creation timestamp before it, is the parent pid a pid that exists elsewhere in the dump? A scanner that reports every match is worse than one that reports fewer.

Command lines are UTF-16, which is why strings misses them

Windows keeps essentially all of its interesting text as UTF-16: command lines, file paths, registry paths, URLs. That is the same reason a byte-oriented sweep misses things in disk image forensics. A byte-oriented strings run sees p\0o\0w\0e\0r\0 and reports nothing, which is how people conclude a dump is empty when it is full.

# The flag that matters, and the one most often forgotten
strings -el memory.raw | grep -i powershell

# Both encodings, since a dump has plenty of ASCII too
strings -a memory.raw    > ascii.txt
strings -a -el memory.raw > utf16.txt
-el is 16-bit little-endian. On a Windows dump it finds more than the default run does.

What to look for once you can see them: -enc or -EncodedCommand (a base64 PowerShell payload, one decode from the answer), certutil -urlcache, bitsadmin /transfer, mshta, rundll32 with a path that is not a DLL, and any path under a user's Downloads or Temp directory.

Registry hives are in the dump too

The registry is a set of files, and while a machine is running those files are mapped into memory. A regf header in a memory image is a hive, and its own path is written at offset 0x30 - so SAM, SYSTEM, SOFTWARE and each user's NTUSER.DAT identify themselves.

Carve one out and it becomes an ordinary hive analysis: Run and RunOnce keys for persistence, MountedDevices for what was plugged in, TypedURLs and UserAssist for what somebody did, and the network profile keys for where the machine had been.

When nothing is recognised

Two things commonly look like a broken tool and are not. A Windows crash dump (PAGEDU64 in the first bytes) is not a raw image and has to be converted before it can be scanned. And a compressed or hibernation-file acquisition is not scannable in place at all.

The other case is that the dump is genuinely fine and the answer is not in any structure - or that it is about the account rather than the process, in which case tokens, SIDs and privileges is the vocabulary you need. A flag in a buffer that nothing points at any more is common, and a targeted strings search for the flag format takes seconds. Reach for it early rather than as a last resort - it costs almost nothing and it resolves a surprising fraction of memory challenges outright.

The order, condensed

  1. Confirm it is a raw image and not a crash dump or a hibernation file.
  2. Scan for processes and build the parent tree. Look for a shell under something that should not spawn one.
  3. Pull command lines - remembering UTF-16 - and decode anything encoded.
  4. Find the hives, carve them out, and read persistence and user activity.
  5. In parallel with all of it, grep both encodings for the flag format.