DLL sideloading and search-order hijacking abuse the way Windows resolves libraries: an application loads a DLL from its own folder before it checks system locations. An attacker copies a legitimate signed executable into a writable directory, places a malicious DLL with the expected name beside it, and persists by launching that pair from a Run key or scheduled task. The process name and signature are trustworthy, so detection has to focus on the module and its path.
Signals at a Glance
| Signal | Where | ATT&CK |
|---|---|---|
| Unsigned or untrusted DLL loaded from the same folder as a signed executable | Sysmon 7, EDR image-load events | T1574.002 |
| Signed executable running from AppData, ProgramData, Temp or Users\Public | Sysmon 1, process creation | T1574.002 |
| DLL with a Windows system name (version.dll, wtsapi32.dll) loaded outside System32 | Sysmon 7 | T1574.001 |
| Legitimate binary copied to a new path shortly before first run | Sysmon 11 + 1 | T1036.005 |
| Run key or task pointing at a signed vendor binary in a user directory | Sysmon 13, 4698 | T1547.001 |
| Phantom DLL loads that fail and later succeed after a file drop | Sysmon 7, ProcMon baseline | T1574.001 |
Image Loads and Signature Mismatch
The core logic is a signature mismatch between a process and the module it loads from its own directory. Image-load telemetry is voluminous, so scope it: restrict to user-writable paths and join against certificate data to isolate unsigned modules. In Defender Advanced Hunting that looks like this:
// KQL: unsigned DLL loaded by a process running from a user-writable folder
let unsigned = DeviceFileCertificateInfo
| where IsSigned == 0 or IsTrusted == 0
| project SHA1;
DeviceImageLoadEvents
| where FolderPath matches regex @"(?i)\\(AppData|ProgramData|Temp|Users\\Public)\\"
| where InitiatingProcessFolderPath matches regex @"(?i)\\(AppData|ProgramData|Temp|Users\\Public)\\"
| extend HostDir = tolower(substring(InitiatingProcessFolderPath, 0, strlen(InitiatingProcessFolderPath) - strlen(InitiatingProcessFileName)))
| where tolower(FolderPath) startswith HostDir
| join kind=inner unsigned on SHA1
| summarize loads=count(), firstSeen=min(Timestamp) by DeviceName, InitiatingProcessFileName,
InitiatingProcessFolderPath, FileName, SHA1
| order by firstSeen desc
// tune/validate: Electron apps and per-user installers load many local DLLs; allowlist by publisher.
For environments with Sysmon, a Sigma rule on Event 7 catches the most blatant cases, a Windows-named DLL that is not in a Windows directory:
title: System-Named DLL Loaded From Non-System Path
logsource:
product: windows
category: image_load
detection:
selection:
ImageLoaded|endswith:
- '\version.dll'
- '\wtsapi32.dll'
- '\winhttp.dll'
- '\cryptbase.dll'
- '\dbghelp.dll'
filter_system:
ImageLoaded|startswith:
- 'C:\Windows\System32\'
- 'C:\Windows\SysWOW64\'
- 'C:\Windows\WinSxS\'
condition: selection and not filter_system
level: medium
# tune/validate: some applications ship their own copy of dbghelp.dll and similar libraries.
Hunting the Pair
- Look at the pair, not only the DLL. A signed binary running from a location it was never installed to, such as an updater or security-product component in ProgramData, is the strongest persistence indicator.
- Compare the executable’s original filename (PE version info) against its on-disk name and path; a mismatch with a user-writable directory is a useful hunt.
- Check how the pair is launched. A sideloaded persistence chain almost always has a Run key, scheduled task or service pointing at the signed host, so pivot from those artifacts.
- Reduce your exposure with application control. WDAC or AppLocker rules that require signed DLLs from trusted publishers in user-writable paths remove most of this technique.
- Rank by prevalence. A DLL hash seen on one host, loaded by a binary that is common elsewhere, stands out in fleet-wide stacking.
Use the SigmaHQ image-load and DLL-sideloading rules, Elastic’s DLL side-loading detections, Splunk ESCU content, MITRE CAR analytics, Atomic Red Team T1574 tests and the HijackLibs project for catalogued vulnerable executables. Baseline your own environment first, because many legitimate applications load local DLLs from their folder.
Build Detections That Fire
Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.
- Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
- Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
- 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts