Case Study 1 — The Malware That Was Never on Disk

A finance workstation keeps tripping the endpoint sensor, yet every disk scan comes back clean — no malicious file, no dropper, nothing in the usual autostart locations. The analyst captures RAM before the next reboot, and the implant that lived only in memory narrates the entire intrusion.

Background

A regional logistics company runs its accounts-payable function from a handful of hardened Windows 10 workstations. Over three days, the managed-detection sensor on AP-WS-07 raises low-confidence alerts — "suspicious script behavior," "anomalous outbound connection" — that close themselves before an analyst can act. The on-disk antivirus scan is clean every time. The IT lead is ready to write it off as a flaky sensor and reimage the box on the regular maintenance window that night.

The on-call DFIR analyst pushes back with a single question from Chapter 15 — Live Response and Triage: if the disk is clean but the sensor keeps firing, where is the code? The answer, if there is one, is in RAM — and the scheduled reboot would erase it. Working under the company's incident-response authorization, the analyst inserts a prepared USB device and runs WinPmem to external media before anyone touches the power, capturing AP-WS-07_mem.raw (16 GiB) with the pagefile included, then computes and logs the SHA-256 on the spot. The disk is imaged afterward per Chapter 14 — Forensic Acquisition. The memory image is the prize; the analyst just did not know yet how completely.

The investigation

The triage pass runs in a disciplined order, each plugin's output saved and hashed.

windows.info anchors the image: Windows 10 build 19041, eight processors, SystemTime 2024-05-14 13:58:21 UTC. Every timestamp that follows is read against that clock.

The process views disagree, and the disagreement is the first finding. windows.pslist and windows.psscan are diffed:

psscan ∖ pslist  (present in the pool scan, ABSENT from the list walk)

PID    PPID  ImageFileName    Offset(P)   CreateTime            ExitTime
6004   4488  rundll32.exe     0x...       2024-05-14 13:52:33   (none)   ◄── hidden, running

A rundll32.exe is running (no exit time) yet never appears in the official list — the signature of a process unlinked to hide. Its parent, PID 4488, is itself odd: windows.pstree shows a svchost.exe (4488) descending from explorer.exe, not from services.exe, and windows.cmdline shows it launched as C:\Users\Public\svchost.exe with no -k service argument. A real service host never looks like this.

windows.netscan ties it together:

Proto  LocalAddr   LPort  ForeignAddr     FPort  State        PID   Owner
TCPv4  10.0.0.71   49774  203.0.113.45    443    ESTABLISHED  4488  svchost.exe   ◄── C2

PID 4488 — the fake svchost — holds an established connection to an external host on 443. Packet capture alone could see the flow but could never attribute it to a specific binary; memory names the owner.

Now the heart of the case. windows.malfind examines the suspect process and lights up:

PID: 4488  Process: svchost.exe
VadTag: VadS   Protection: PAGE_EXECUTE_READWRITE   PrivateMemory: 1
Address range: 0x1d0000 - 0x1e2fff
0x1d0000  4d 5a 90 00 03 00 00 00  04 00 00 00 ff ff 00 00   MZ..............

A region that is private (no file backs it), marked RWX, and begins with 4D 5A ("MZ") — a whole executable living in memory that the disk knows nothing about. That is the fileless payload. windows.ldrmodules adds a second technique in a different process: inside explorer.exe, a mapped, executable region reports False / False / False across the three PEB module lists with no path — a reflectively-injected DLL the loader never recorded.

The attacker's own hands are recoverable. windows.cmdscan and windows.consoles reconstruct the console:

Cmd #0: whoami
Cmd #1: net user svc_help P@ss!2024 /add
Cmd #2: net localgroup administrators svc_help /add
Cmd #3: reg add ...\CurrentVersion\Run /v Updater /d C:\Users\Public\svchost.exe /f
Cmd #4: del C:\Users\Public\dropper.exe

The narrative writes itself: enumerate identity, create a backdoor admin, escalate it, install persistence, and delete the dropper to clean the disk. windows.registry.printkey on the Run key confirms the Updater value pointing at C:\Users\Public\svchost.exe, last-written minutes after the process started — the malware's own configuration change, frozen in memory. And the deletion in Cmd #4 is exactly why the disk was clean — the dropper was removed, but the running payload it left behind, and the very command that deleted it, both survived in RAM.

A final loose end ties off the "re-clean-on-reboot" mystery. windows.modules versus windows.modscan differ by one driver entry; the extra entry, present only in the pool scan, is a small unlinked driver that re-injects the implant at each boot from a heavily obfuscated registry autorun the on-disk scanners had dismissed as benign. That is why every reimage-and-watch cycle "fixed" nothing.

The analyst dumps the hollowed process image (windows.pslist --pid 4488 --dump), hashes it, and confirms it does not match the legitimate C:\Windows\System32\svchost.exe — the in-memory code is not the disk's code. The C2 address and the payload's SHA-256 become IOCs; a yarascan signature and the IP are swept across the rest of the fleet, turning one workstation's finding into an enterprise-wide hunt and containment. A timeliner bodyfile feeds the master timeline of Chapter 21 — Timeline Analysis.

Recovery vs. Forensics. The same live-capture discipline that saved this corporate investigation is what makes the book's anchor case #4 — the powered-on, BitLocker-locked laptop — solvable at all: capture the volatile state before power-off, or lose the only copy of evidence that exists. Here the prize was an implant; there it is an encryption key. Different artifact, identical rule.

The analysis

  1. A clean disk does not mean a clean machine. The most capable malware runs from memory and writes nothing incriminating to storage. When the sensor fires but the disk scan is clean, the working hypothesis is memory-resident code, and the only way to test it is to capture RAM before the reboot that would erase it.
  2. List and scan, then diff. pslist alone would have reported "no malicious process"; the hidden rundll32 surfaced only because psscan was run and the two were diffed. The difference between the views is the hidden process — the structure outliving its pointer.
  3. Correlation across independent structures is what convicts. Parentage (wrong), command line and path (wrong), malfind (RWX-private MZ), netscan (C2 owner), ldrmodules (reflective DLL), and the on-disk hash mismatch each answer a narrow question; braided together they are airtight, and they survive cross-examination precisely because no single thread carries the weight.
  4. The attacker's clean-up is itself evidence. del dropper.exe is why the disk looked clean — and the command that performed the deletion, plus the running payload it left, both survived in memory. The absence of a trace on disk became a dated trace in RAM.
  5. One finding becomes fleet defense. The payload hash, the C2 IP, and a YARA rule extracted from this single image drove a hunt across every endpoint. Memory forensics is not only how you understand one host; it is how you scope an incident.

Discussion questions

  1. The on-disk antivirus scan was clean on all three days. Explain, using at least three specific artifacts from this case, why "the AV is clean" is not evidence that the host is uncompromised — and what a responder should do instead.
  2. The hidden rundll32.exe (PID 6004) appeared in psscan but not pslist. Describe the kernel-level technique that produces this discrepancy and why the process structure still carries its Proc pool tag even though it is unreachable by the list walk.
  3. malfind flagged an RWX-private region beginning with MZ inside PID 4488. Why is malfind correctly described as a lead generator rather than a verdict, and which corroborating findings in this case justified moving from "candidate" to "injection confirmed"?
  4. ⭐ The implant re-injected itself on every boot, defeating the team's reimage-and-watch routine. Trace exactly which plugin finding explained this persistence, and design a containment sequence that would actually break the loop (consider network isolation, the autorun, credentials, and rebuild order). Where would simply pulling the plug have helped, and where would it have destroyed evidence?
  5. The recovered C2 IP and payload hash were swept across the fleet. Which later chapter follows that C2 connection out onto the network, and what can the wire show that memory cannot — and vice versa?