Module 3 — DLLs, Loaders, and PE
Module 3 — DLLs, Loaders, and PE
DLLs are shared PE modules loaded into process memory. The loader resolves imports and publishes exports. Security work often starts at "which DLL loaded, from where, signed or not?"
Path: Module 2 · Next: Module 4
0. Purpose
DLLs are the glue between applications and OS services — and a common trust pivot (hijack, proxy, patch, sideload). You need PE literacy before malware or defender analysis makes sense.
1. ELI5
An .exe is the main program. DLLs are plug-in packs many programs share.
When a program starts:
- Windows reads the import list ("I need
kernel32!CreateFile") - Loads each required DLL once per process (usually)
- Fills in pointers to exported functions
- Runs
DllMainfor attach (user-mode init)
You inspect the file on disk (PE headers) separately from modules in a running process (ProcExp).
2. Deep breakdown
See DLL structure on disk for the full PE walkthrough.
flowchart LR EXE[process.exe] -->|import table| K32[kernel32.dll] EXE --> AMSI[amsi.dll] AMSI --> K32 K32 --> NTD[ntdll.dll] NTD -->|syscall| KERN[kernel]
| Concept | Meaning | Security angle |
|---|---|---|
| Export | Function this DLL offers | Attack surface / hook point |
| Import | Function this DLL needs | Dependency chain analysis |
| Load order | Which DLL initializes first | Hijack before legitimate load |
| Search order | Where LoadLibrary looks |
DLL search order hijacking |
| Signature | Authenticode on file | Trust baseline |
Win11 System32 vs SysWOW64: on x64, native 64-bit DLLs live in System32; 32-bit copies in SysWOW64. Always match process bitness to DLL path.
Hands-on track in this folder
| Step | Guide |
|---|---|
| Pick a target | 00-dll-target-selection |
| Full read-only workflow | 01-read-only-dll-inspection-amsi-part-1 |
DLL search order (why path matters)
When LoadLibrary / the loader resolves a DLL by name only (not full path), Windows walks a search order — classic hijack surface when a writable directory precedes System32.
| Order (simplified) | Location |
|---|---|
| 1 | Application directory |
| 2 | System directory (System32 for 64-bit proc) |
| 3 | 16-bit system directory |
| 4 | Windows directory |
| 5 | Current directory (often disabled on modern builds) |
| 6 | Directories in PATH |
Mitigations: full paths in manifests, SafeDllSearchMode, CWDIllegalInDllSearch, code signing review.
Lab .114 verified DLLs
| DLL | Size (KB) | Version | Signature |
|---|---|---|---|
amsi.dll |
112 | 10.0.26100.7309 | Valid (inbox) |
wldp.dll |
433 | 10.0.26100.8521 | Valid |
ntdll.dll |
2,459 | 10.0.26100.8972 | Valid |
MpClient.dll is under C:\Program Files\Windows Defender\ — not System32. See 00-dll-target-selection.
Export count sanity check — amsi.dll
Eight exports (not six): includes AmsiNotifyOperation, AmsiResultIsMalware — see 01-read-only-dll-inspection-amsi-part-1.
Security engineer lens
| Hunt | Tool / artifact |
|---|---|
| Unexpected DLL in sensitive process | Process Explorer, Sysmon 7 (Image loaded) |
| DLL from user-writable path | Path + signature + parent process |
| Missing or wrong signature | Get-AuthenticodeSignature |
| Version drift vs fleet baseline | File version + hash inventory |
Read-only rule: copy DLLs to your desktop for PE-bear/Ghidra — never patch inbox system DLLs in place.
Lab checkpoint — 192.168.50.114
# Baseline three DLLs
$candidates = 'version.dll','amsi.dll','wldp.dll'
$candidates | ForEach-Object {
$p = Join-Path $env:windir "System32\$_"
$sig = Get-AuthenticodeSignature $p
[PSCustomObject]@{
DLL = $_
SizeKB = [math]::Round((Get-Item $p).Length/1KB,1)
Signature = $sig.Status
Version = (Get-Item $p).VersionInfo.FileVersion
}
} | Format-Table -AutoSize
# Runtime: modules in current PowerShell
Get-Process -Id $PID -Module | Sort-Object ModuleName |
Select-Object -First 15 ModuleName, FileName
Record in notebook
Navigation
← Module 2 · Module 4 →