Digital forensics and a first look at malware
Lesson 3 of 3
3Digital forensics and a first look at malware
The big pictureAt a crime scene the investigator touches nothing before photographing and recording, because any touch may erase evidence or make it inadmissible in court. A computer is the same, only harder: rebooting wipes memory, and opening a file changes its last-access time. A forensic analyst moves with deliberate slowness, because here accuracy matters more than speed.
What the picture shows: The five stages in NIST SP 800-86 and similar guides: preserve the scene, collect evidence in order of volatility, examine it, analyse it into a timeline, then write a report a non-technical reader understands and that stands up to review.
Map of this part
The concepts in order, click any one to jump to it:
Two ways into the same idea
Picture a burglar in a house. Some evidence evaporates fast: footprints on a wet floor, the warmth of the chair they sat on (memory). Some stays: the broken safe (the disk). The investigator photographs the wet floor first. Every item goes in a sealed bag with who took it and when (chain of custody). And when the investigator finds a strange tool, they do not try it in the house; they take it to a lab.
Order of volatility (RFC 3227): registers and cache, then routing table, ARP, processes and memory, then temporary files, then disk, then remote logs, then archive media. Memory is captured live (with WinPmem or EDR tools), the disk as a bit-for-bit image (raw or E01) through a write blocker, with a SHA-256 hash of original and copy. Volatility 3: windows.pslist, windows.pstree, windows.netscan, windows.malfind. Windows artefacts: Prefetch (what ran), Amcache and ShimCache, Run keys in the registry, $MFT, and the event logs. Linux: auth.log, bash_history, cron and systemd. A super-timeline with Plaso (log2timeline), or artefact collection with KAPE and Velociraptor. Malware analysis: static (hashes, strings, imported functions, PE sections, entropy: near 8 means packed or encrypted) then dynamic in an isolated virtual machine with no real network. YARA rules match strings and bytes in files.
Before You Start
🔎The incident investigation project
You investigated logs and wrote a report.
🔐Cryptography
You know the SHA-256 hash.
The Core Idea
1Order of volatility and chain of custody
The first decision in an incident: do not switch the machine off. Switching off wipes memory, which holds running processes, open connections, encryption keys, and sometimes malware that never writes to disk. Isolate it from the network (through EDR or by pulling the network, not the power), capture memory, then image the disk. Every item has a custody record: who collected it, when, with which tool, its hash, and who received it next.
| Order | Source | Gone after | How to collect |
|---|---|---|---|
| 1 | Memory, processes, connections | A reboot | Live capture (WinPmem or EDR) |
| 2 | Temp files and browser cache | Hours or days | Artefact collection (KAPE) |
| 3 | The disk | Being overwritten | A bit-for-bit image through a write blocker |
| 4 | Remote logs (SIEM) | The retention period | Export with a hash |
One bit changes the whole hash, which is why the hash proves the copy is identical and untouched.
import hashlib, json, datetime
disk = bytes(range(256)) * 4096 # stands in for a disk image
copy = bytearray(disk)
original_hash = hashlib.sha256(disk).hexdigest()
copy_hash = hashlib.sha256(copy).hexdigest()
record = {"item": "LAPTOP-HR-07 disk", "collected_by": "analyst A", "tool": "imager v4",
"utc": datetime.datetime(2026, 11, 2, 9, 14).isoformat(), "sha256": original_hash[:16] + "..."}
print(json.dumps(record, indent=1))
print("copy verified:", copy_hash == original_hash)
copy[1000] ^= 1 # one bit changes by accident
print("after one bit flips:", hashlib.sha256(copy).hexdigest() == original_hash)2Memory and the timeline
In memory you see what was running at the moment of capture. With Volatility you ask: which processes? Who is their parent? Which connections are open? Is code injected into a healthy process (malfind)? Then you build one timeline from every source: event logs, Prefetch, file times, the proxy and email. The story appears when events line up to the minute.
# Volatility 3 on a memory image from the lab vol -f laptop-hr-07.mem windows.pstree # who started whom: winword.exe -> powershell.exe is a red flag vol -f laptop-hr-07.mem windows.netscan # open connections and the process that owns each vol -f laptop-hr-07.mem windows.malfind # memory regions that look like injected code vol -f laptop-hr-07.mem windows.cmdline # the full command line of every process
Seven events from five sources become a story: email, macro, control tool, persistence, spread. That is the heart of the incident report.
events = [
("2026-10-28 09:02:11", "email", "HR-07 receives 'Salary_review.docm' from an outside sender"),
("2026-10-28 09:05:40", "prefetch", "WINWORD.EXE runs"),
("2026-10-28 09:05:52", "sysmon 1", "winword.exe starts powershell.exe -enc ..."),
("2026-10-28 09:05:55", "proxy", "HR-07 -> cdn-update-sync.net (first time ever)"),
("2026-10-28 09:06:30", "sysmon 11","file C:\\Users\\Public\\upd.dll written"),
("2026-10-28 09:07:02", "4698", "scheduled task 'GoogleUpdateTaskCore' created"),
("2026-10-28 13:40:18", "4624", "HR-07 logs on to FILESRV-01 with admin rights (type 3)"),
]
for when, source, what in sorted(events):
print(f"{when} {source:<9} {what}")
first, last = events[0][0][11:16], events[-1][0][11:16]
print(f"from first email ({first}) to the file server ({last}): the attacker spent ~4.5 hours inside")3Examining a suspicious file safely
Rule one: never open the sample on your own machine. Use an isolated virtual machine with no real network (or a fake one such as INetSim), and take a clean snapshot to return to. Start static without running it: the hash (does anyone know it?), strings (addresses, commands, messages), imported functions (does it ask to inject processes or encrypt files?) and entropy: a section near 8 bits per byte means compressed or encrypted data hiding something. Then dynamic: run it and watch processes, files, the registry and the network.
The sample here is bytes made up for learning, not a real program. Notice the end of the file is near 8: that is what a packed part looks like.
import hashlib, math, re
from collections import Counter
def entropy(data):
counts = Counter(data)
return -sum(c / len(data) * math.log2(c / len(data)) for c in counts.values())
def strings(data, minimum=6):
return [s.decode() for s in re.findall(rb"[ -~]{%d,}" % minimum, data)]
sample = (b"MZ\x90\x00" + b"\x00" * 60 + b"This program cannot be run in DOS mode.\x00"
+ b"http://cdn-update-sync.net/gate.php" + b"\x00" * 20 + b"vssadmin delete shadows /all /quiet"
+ bytes((i * 167 + 13) % 256 for i in range(3000))) # a packed-looking blob
print("sha256 :", hashlib.sha256(sample).hexdigest()[:24], "...")
print("entropy: header", round(entropy(sample[:200]), 2), "| last 3000 bytes", round(entropy(sample[-3000:]), 2))
for s in strings(sample):
flag = " <- suspicious" if re.search(r"http|vssadmin|delete", s) else ""
print("string :", s[:60] + flag)4YARA: a rule that knows the family
After the analysis, keep what you learned in a YARA rule: distinctive strings and bytes and a condition joining them. Run it across every host (through EDR or Velociraptor) to find other members of the same family even if their hash changed.
rule Darb_Lab_Loader_Family
{
meta:
author = "your name"
description = "Loader seen in the HR-07 lab case: C2 gate + shadow-copy wipe"
date = "2026-11-02"
strings:
$mz = { 4D 5A }
$gate = "/gate.php" ascii
$vss = "vssadmin delete shadows" ascii nocase
$task = "GoogleUpdateTaskCore" ascii wide
condition:
$mz at 0 and filesize < 2MB and 2 of ($gate, $vss, $task)
}2 of): a lone string may appear in clean software, and combining them cuts false positives.Worked example
The task: the night-shift analyst saw an "encoded PowerShell from Word" alert on an HR laptop and wrote: "I rebooted the machine to stop the program". What was lost? What is still possible?
The answer: Lost: all of memory: processes, open connections, any code never written to disk, perhaps keys. Still possible: (1) Isolate the machine now. (2) Collect artefacts: Prefetch, Amcache, Run keys, scheduled tasks (4698), event logs and Sysmon. (3) Image the disk with a hash. (4) Pull the machine's records from the SIEM and proxy. (5) Build the timeline. (6) Examine the attachment in an isolated lab. (7) Write a YARA rule and run it across every host. And the lesson for the team: "isolate, do not switch off" goes in the response playbook.
Myth vs Reality
| Myth | Reality |
|---|---|
| Switch a compromised machine off at once. | Isolate it from the network and leave the power on; switching off wipes the most precious evidence, memory. |
| Deleting the malware ends the incident. | The bigger question is how it got in, what it did and where it spread. Without an answer it comes back. |
| Malware analysis is only for geniuses. | Basic static and dynamic analysis is enough for most incidents; deep reverse engineering is a later speciality. |
Where you meet it at work
🚨Incident response
The timeline decides the incident's scope and what must be cleaned.
⚖️Legal cases
The chain of custody and hashes make evidence admissible.
🧬Intelligence team
YARA rules from the analysis are shared with the sector.
Test your understanding
What do you collect first by order of volatility?
Memory vanishes on reboot; the disk stays.
Why hash both the original and the copy with SHA-256?
Any changed bit changes the whole hash.
A section in a file has entropy 7.9. What does it usually mean?
The maximum is 8 bits per byte, and close to it means high randomness.
Which tool analyses a memory image?
Volatility 3 shows processes, connections and injected code from memory.
Where do you run a malware sample for dynamic analysis?
Isolation stops it spreading, and the snapshot takes you back to clean.
Quick review cards
Check Your Understanding
Why isolate the machine from the network instead of switching it off?
Isolation cuts the attacker's contact and keeps memory for analysis.
What makes a timeline stronger than any single log?
It joins many sources, so the link between events shows: email, then macro, then connection, then spread.
Why static analysis before dynamic?
Because it is safe with nothing running, and tells you what to expect and watch when you do run the sample.
Resources for this lesson
Grouped by type. Start with the official docs for precision, or an article or video for the explanation.
Tools2
Done with this lesson?
Sign in to save your progress.