Skip to main content

August 5, 2026

Windows Forensics for CTF: Event Logs, Registry Hives, BitLocker, and SMB

Work Windows artifacts from Linux: parse .evtx event logs, read registry hives offline, crack and mount BitLocker volumes, enumerate SMB shares, write YARA rules.

Introduction

Nearly every forensics guide, including the ones on this site, assumes a Linux target: an ext4 image, a pcap, a memory dump of a Linux box. Then a challenge hands you a Security.evtx, a SYSTEM hive, or a BitLocker-encrypted VHD, and none of the reflexes transfer. strings gives you nothing readable, file says data, and the tooling everyone recommends is a Windows GUI you do not have.

You do not need Windows. Every artifact in this guide can be parsed, cracked, mounted, and read from a Linux shell, usually with one tool per artifact type. What you need instead is the map: knowing that Windows keeps its evidence in a small number of specific places, in formats that are structured rather than textual, and that each of those formats has a dedicated parser.

Windows artifacts are not hidden. They are structured, and structure is invisible to the text tools most people reach for first.

This guide walks the five artifact families that actually appear in CTF challenges, with the Linux command for each. It pairs with disk forensics for the imaging and filesystem layer and Volatility 3 for memory.

The artifact map

When you are handed a Windows image or a loose file and do not know where to look, this is the order of value. It is sorted by how often the flag turns out to be there.

ArtifactWhere it livesWhat it answers
Event logsC:\Windows\System32\winevt\Logs\*.evtxWhat happened, when, and under whose account
Registry hivesC:\Windows\System32\config\{SYSTEM,SOFTWARE,SAM,SECURITY}Configuration, installed software, autoruns, USB history
User hiveC:\Users\<name>\NTUSER.DATPer-user settings, recent documents, typed paths
PrefetchC:\Windows\Prefetch\*.pfWhich executables ran, how often, and when last
Recycle bin$Recycle.Bin\<SID>\$I*Deleted file names, original paths, deletion times
Memory image*.raw, *.mem, *.dmp, hiberfil.sysEverything the disk encrypted away
Tip: Challenge titles in this category are unusually honest. A challenge called Event Viewing wants event logs; one called BitLocker wants volume decryption. Read the title as the artifact selector and skip the survey.

Event logs (.evtx)

The .evtx format is binary XML: chunked, partially compressed, and completely opaque to strings. That opacity is why event log challenges frustrate people who try to grep them. Parse first, then grep.

pip install python-evtx
 
# Dump the whole log as readable XML
evtx_dump.py Security.evtx > security.xml
 
# Or, if you have the Rust reimplementation, it is much faster:
evtx_dump -o xml Security.evtx > security.xml
 
# Now ordinary text tools work
grep -c '<Event ' security.xml
grep -oP '<EventID[^>]*>\K[0-9]+' security.xml | sort | uniq -c | sort -rn | head -20

That last command is the one to run first on any event log. It histograms the event IDs, and the histogram tells you what kind of story the log contains before you read a single record.

Event IDs are the vocabulary of this artifact. You do not need to memorise many, but these come up constantly:

Event IDMeaningWhy it matters
4624Successful logonWho got in, from where, and by which logon type
4625Failed logonBrute force attempts show up as bursts
4657A registry value was modifiedPersistence and configuration tampering
4688A new process was createdThe closest thing to a command history
1033Application install completedCarries free-text Manufacturer and Comment fields
1074System shutdown initiatedRecords which process and user requested it, plus a reason string
7045A service was installedClassic persistence, and a favourite of challenge authors

Event Viewing is built directly on this vocabulary. Three events tell the story of a compromised host that keeps shutting down: an install (1033), a registry change (4657), and a shutdown (1074). Each carries one Base64 fragment of the flag, hidden in exactly the place the format invites, which is the free-text fields.

Key insight: Event log records have structured fields (timestamps, SIDs, event IDs) and free-text fields (Manufacturer, Comment, Description, shutdown Reason). The structured fields are generated by Windows and are hard to abuse. The free-text fields accept anything. When a flag is hidden in a log, it is in the free-text fields essentially every time.
# Pull one event ID with surrounding context
grep -B5 -A30 '<EventID[^>]*>1074<' security.xml
 
# Sweep every Base64-looking blob in the log and try decoding each
grep -oE '[A-Za-z0-9+/]{16,}={0,2}' security.xml | sort -u | \
while read -r b; do printf '%s -> ' "$b"; echo "$b" | base64 -d 2>/dev/null; echo; done | grep -i pico

Registry hives

The registry is a set of binary tree files, one per hive, and mounting the disk gives you the files directly. There is no need for a Windows machine to read them; there is a mature Linux parser.

sudo apt install libhivex-bin libwin-hivex-perl registry-tools chntpw
 
# Dump an entire hive to text (hivexregedit comes from libwin-hivex-perl)
hivexregedit --export SYSTEM '\' > system.reg
 
# Export the same thing with reged, from registry-tools
reged -x SYSTEM '\' '\' out.reg
 
# Browse interactively instead
hivexsh SYSTEM
chntpw -e SOFTWARE

The keys worth knowing, because they answer the questions challenges ask:

KeyAnswers
SYSTEM\CurrentControlSet\Control\ComputerNameWhat was this machine called
SYSTEM\CurrentControlSet\Enum\USBSTORWhich USB storage devices were ever attached
SOFTWARE\Microsoft\Windows\CurrentVersion\RunWhat starts automatically. The first place to look for persistence
SAM\Domains\Account\UsersLocal accounts and their password hashes
NTUSER.DAT\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocsWhat the user recently opened

Two habits pay off. First, registry values are frequently stored as UTF-16LE, so a flag in a value looks like p.i.c.o.C.T.F. to a byte-oriented search. Always search both encodings:

strings -e l SOFTWARE | grep -i pico # UTF-16LE
strings -e s SOFTWARE | grep -i pico # ASCII

Second, when a hive comes out of a mounted image and looks truncated or refuses to parse, check for transaction logs beside it (SYSTEM.LOG1 and SYSTEM.LOG2). Windows writes changes there before merging, so a hive captured from a running system can be missing its most recent and most interesting edits.

Warning: A challenge tagged as a registry problem is not automatically one. Read what the file actually is before choosing tools: metadata challenges, PDF property puzzles, and registry hive parsing all get filed under similar-sounding names, and running file on the artifact settles it in one second.

BitLocker volumes

BitLocker is full-volume encryption, and a BitLocker image looks like noise with a small readable header. Under Linux the workflow is a two-step: recover the key protector, then mount through dislocker, which presents a decrypted virtual NTFS file you then loop-mount normally.

When the volume is protected by a user-chosen password, the attack is an offline dictionary attack. The volume metadata contains a derivable hash, and hashcat has a mode for it.

sudo apt install dislocker
# bitlocker2john is not a pip package: it ships with John the Ripper jumbo
git clone --depth 1 https://github.com/openwall/john && cd john/src && ./configure && make -s
 
# 1. Extract the crackable hash from the volume
john/run/bitlocker2john -i drive.dd > hashes.txt
grep '$bitlocker$0$' hashes.txt > target.hash
 
# 2. Crack it (mode 22100 is BitLocker)
hashcat -m 22100 -a 0 target.hash /usr/share/wordlists/rockyou.txt
 
# 3. Unlock and mount
mkdir -p /tmp/dis /tmp/mnt
sudo dislocker -V drive.dd -u<PASSWORD> -- /tmp/dis
sudo mount -o loop,ro /tmp/dis/dislocker-file /tmp/mnt
ls -la /tmp/mnt

BitLocker-1 is this exact sequence, and it is worth doing precisely because the sequence is fiddly and the individual steps are easy to look up wrong. The conceptual point it teaches is that full-disk encryption inherits the strength of whatever guards the key, so a weak password reduces AES-128 to a wordlist lookup.

When the disk is locked, take the RAM

The most important idea in this whole guide, and the one that generalises furthest: encryption protects data at rest. A mounted volume is not at rest. While the drive is unlocked, the operating system holds the key and the plaintext in memory, so a RAM capture walks straight past the encryption regardless of how strong the password was.

BitLocker-2 is designed to teach exactly this. The password gets strengthened so that cracking is off the table, and in exchange you are handed a memory image captured while the drive was mounted. The plaintext file contents are simply present.

# Fastest first pass: the flag may be sitting there in plaintext
strings -n 8 memdump.raw | grep -i 'picoCTF{'
strings -e l -n 8 memdump.raw | grep -i 'picoCTF{' # UTF-16LE
 
# Structured pass with Volatility 3
vol -f memdump.raw windows.info
vol -f memdump.raw windows.pslist
vol -f memdump.raw windows.cmdline
vol -f memdump.raw windows.filescan | grep -i flag
 
# Registry hives live in memory too
vol -f memdump.raw windows.registry.hivelist
vol -f memdump.raw windows.registry.printkey --key 'Software\Microsoft\Windows\CurrentVersion\Run'

The full treatment of memory analysis is in the Volatility 3 guide; everything there applies to Windows images directly, since Windows is Volatility's best-supported target.

SMB shares and network artifacts

SMB is the Windows file-sharing protocol, and the reason it shows up in CTF is that devices ship with anonymous access enabled and nobody notices. Network printers and NAS boxes are the usual offenders, and they accumulate whatever people accidentally sent them.

sudo apt install smbclient
 
# List shares with a null session (no credentials)
smbclient -L //TARGET -N
 
# Connect to one
smbclient //TARGET/shares -N
smb: \> ls
smb: \> recurse ON
smb: \> prompt OFF
smb: \> mget *
 
# Or mount it and use normal tools
sudo mount -t cifs //TARGET/shares /mnt/smb -o guest,ro,vers=3.0

The Printer Shares series runs this ladder: part 2 and part 3 extend the same scenario, where a document sent to a print server is still sitting in a share nobody secured. In an assessment this is a genuine first stop rather than a contrivance.

Tip: If a capture rather than a live host is what you were given, the same data is in the pcap. Wireshark can carve files straight out of SMB traffic with File, then Export Objects, then SMB. See the Wireshark guide.

Windows binaries and YARA

Windows executables are PE files rather than ELF, which changes the tooling slightly and the concepts not at all. Ghidra reads PE natively. The differences worth knowing:

ConceptLinux ELFWindows PE
Magic bytes\x7fELFMZ ... PE\0\0
ImportsPLT and GOT entriesImport Address Table naming DLL plus function
Calling conventionSystem V: rdi, rsi, rdx, rcxMicrosoft x64: rcx, rdx, r8, r9
Debuggergdbx64dbg, or gdb under Wine
Warning: The calling convention difference is the one that silently ruins analysis. If you break at a strcmp in a PE binary and read rsi out of habit, you get garbage. On Windows x64 the second argument is in rdx.

The WinAntiDbg series (0x100, 0x200, and 0x300) are Windows binaries built around IsDebuggerPresent, which reads a flag the OS sets in the Process Environment Block when a debugger attaches. They are covered in depth in patching binaries and cracking crackmes; the short version is that 0x100 wants a register patched, 0x200 wants all three checks mapped before you attach, and 0x300 wants you to give up on debugging and edit the file.

PowerShelly covers the scripting side: a PowerShell transformation script plus its output, to be inverted step by step. Cumulative XOR is undone by XORing adjacent output lines, a seeded shuffle is undone by regenerating the same seed sequence, and a bit-encoding substitution is undone by reading the encoding table backwards. It is a custom-cipher problem wearing Windows clothes, and custom cipher reversing covers the general method.

YARA comes up when the task is not to analyse one sample but to describe a family of them. A rule is a set of conditions over strings and file structure:

rule suspicious_sample
{
meta:
author = "ctf"
description = "Catches the sample by its anti-debug imports and marker strings"
 
strings:
$mz = { 4D 5A }
$api1 = "IsDebuggerPresent" ascii
$api2 = "CheckRemoteDebuggerPresent" ascii
$mark = "suspicious_marker" wide ascii
 
condition:
$mz at 0 and 2 of ($api*, $mark)
}
yara -s rule.yar sample.exe
yara -r rule.yar ./samples/

YaraRules0x100 asks for a rule that catches one specific sample when submitted to a remote harness. The design lesson is real: rules that pin exact byte offsets break on recompilation, while rules built from behavioural indicators (API names, packer artifacts, distinctive strings) survive it. Note also the wide ascii modifier above, which is the YARA answer to the UTF-16 problem that bit us in the registry section.

The Linux toolkit

Everything in this guide, installable in two commands.

sudo apt update && sudo apt install -y \
libhivex-bin registry-tools chntpw \
dislocker cifs-utils smbclient \
yara sleuthkit libesedb-utils
 
pip install python-evtx volatility3 regipy
ArtifactToolOne-line usage
.evtxpython-evtxevtx_dump.py Security.evtx > out.xml
Registry hivehivex / regipyhivexregedit --export SYSTEM '\'
BitLockerdislocker + hashcatdislocker -V img -u<pw> -- /tmp/dis
Memoryvolatility3vol -f mem.raw windows.pslist
SMBsmbclientsmbclient -L //TARGET -N
PE binaryGhidraImport, analyse, remember rcx not rdi
Sample matchingyarayara -s rule.yar sample.exe
NTFS imagesleuthkitfls -r -o 2048 image.dd

picoCTF challenges

ChallengeArtifactDifficulty
Event ViewingSecurity.evtx. Three event IDs, three Base64 flag fragmentsMedium
BitLocker-1BitLocker volume with a weak password. Extract, crack, mountMedium
BitLocker-2Strong password, but RAM captured while mounted. Encryption bypassedMedium
YaraRules0x100Windows PE sample. Collect indicators, write a rule, submit itMedium
Printer SharesAnonymous SMB. Enumerate shares, retrieve the misdirected documentEasy
Printer Shares 2The same surface with the easy path closedHard
Printer Shares 3Deepest of the three. SMB plus network forensicsHard
PowerShellyA PowerShell transformation to invert: XOR, shuffle, bit encodingHard
WinAntiDbg0x100PE binary with one IsDebuggerPresent checkMedium
WinAntiDbg0x200Three stacked anti-debug checksMedium
WinAntiDbg0x300UPX packed plus a continuous check. Patch instead of debugMedium

Quick reference

# Identify before you tool up
file artifact && xxd artifact | head -5
 
# Event log: parse, then histogram the event IDs
evtx_dump.py Security.evtx > out.xml
grep -oP '<EventID[^>]*>\K[0-9]+' out.xml | sort | uniq -c | sort -rn
 
# Registry: always search BOTH encodings
strings -e l HIVE | grep -i pico
strings -e s HIVE | grep -i pico
 
# BitLocker: what protects this volume?
dislocker-metadata -V drive.dd
hashcat -m 22100 target.hash rockyou.txt
 
# Memory beats encryption
strings -e l -n 8 mem.raw | grep -i 'picoCTF{'
vol -f mem.raw windows.pslist
 
# SMB null session
smbclient -L //TARGET -N

Next steps: the forensics roadmap for where this sits among the other categories, disk forensics for imaging and filesystem work, hash cracking for the hashcat side of the BitLocker workflow, and metadata forensics for the document artifacts that often accompany a Windows image.

Sources and further reading

Format documentation first, then the tools that parse it.

Run it in the browser

Tools on this site that do the work described above. No install, nothing uploaded: they run entirely in your browser.

Try it on these picoCTF challenges

Walkthroughs that put this technique to work, grouped by event.

Keep reading

Guides that build on the same ideas, plus the roadmap this topic sits under.