DLL Search Order Hijacking and Side-Loading
A program loads most DLLs by name. Unless that name is already loaded or is one of Windows' Known DLLs, Windows searches a fixed order of folders, the program's own folder before System32. Windows' own DLLs come from System32, SysWOW64 or the side-by-side store, signed by Microsoft. A Windows DLL name loaded from the program's folder, unsigned or signed by someone else, usually means code placed where the search finds it first. It often sits beside a copy of a signed program in a folder a user can write to, so check each module's folder and signer against its name first.
What It Is
Before, a genuine program loads each Windows DLL from System32, SysWOW64 or the side-by-side store, and its vendor's DLLs from its install folder. After, it loads a DLL of the same name from its own folder or another folder a user can write to.
The program is unchanged and often signed, so only the module gives it away, unsigned or signed by someone its name does not suggest. A name on the Known DLLs list always loads from the system's own copy, so a stray copy of one is not the module that loaded.
Sysmon event 7 in the Sysmon Operational log and DeviceImageLoadEvents in Defender XDR record each load with the module's path, and a memory image's loader list holds it too. MITRE ATT&CK's detection for T1574.001 pairs the load with the DLL's file creation. T1574.008 is the same state for a program named like a system utility, running from an application's own folder.
What Changes Inside the Process
The process is shown before and after, and the pointer marks what changed.
Before
A clean Windows 11 install
| Name | Path | Signed By |
|---|---|---|
version.dll | C:\ | Microsoft Windows |
After
srv-app-01,
| Name | Path | Signed By |
|---|---|---|
version.dll | C:\ | Not signed |
| PathFound in the Program's Own Folder Before System32: Windows' version.dll Lives in System32 DLL Search Order Hijacking and Side-Loading | ||
Look Inside
What It Leaves Behind
A trusted program, often signed and often run from a copy in a user-writable folder, loads a DLL with a familiar name from its own folder instead of System32. The DLL is often unsigned or signed by someone its name does not suggest, and written to disk shortly before it loads. A proxy DLL also forwards its exports to the real DLL of the same name. Sysmon event 7 and DeviceImageLoadEvents record the load with its path, and Sysmon event 11 or DeviceFileEvents record the write.
Why It Matters
The process is genuine and often signed, so a process listing passes it, but the code is in one of its modules. Only the module's folder, signer and age give it away.
Which Evidence Can See It
Each tile says whether that kind of evidence can see it, and what it shows.
Memory
Sees it
windows.dlllist shows each module's path while its process runs, so a Windows name from the wrong folder stands out.
EDR Telemetry
Sees it
Defender XDR's image load table records each load with its folder, its SHA1 and the process that loaded it. Its certificate table gives the signer.
Disk
Partly
The DLL sits in the folder it loaded from unless it was removed, with its signer and version information to compare with the genuine file.
Logs
Partly
Sysmon event 7 in the Sysmon Operational log records each load with its path, hashes and signature. It is off by default and logs only what its configuration keeps.
How to Confirm It
Work through these in order. Each step names the page that shows how.
- List the process's modules with their folders (ListDLLs, Process Explorer, windows.dlllist). A Windows DLL name outside System32, SysWOW64 or WinSxS stands out.Loaded DLLs
- Check the DLL's signature against its name. The pattern is a DLL that is unsigned, or signed by someone other than Microsoft for a Windows name, beside a program in a user-writable folder.Loaded DLLs
- Find what starts the trusted program from that folder. A task, a service or a Run key that points at a copy outside its install folder brings the DLL back at every start.Process Trees and Call Chains
- Look for proxy DLLs that forward their exports to a DLL of the same name. Velociraptor's Windows.Detection.ForwardedImports lists them once its file glob covers the program's folder, as by default it reads only C:\Windows.Loaded DLLs
- Collect the DLL and the program, or extract them from a memory image with windows.dumpfiles, and analyse them away from the machine.Dumping a Process and Memory
Investigation Steps With Named Tools
Each question has the tools that answer it on a running machine, and in a memory image, a copy of its memory saved to a file.
Where did each module load from, and who signed it?
On a Running Machine
Device(documentation, opens in a new tab)Logs and Records A Defender XDR table. It holds the records Defender for Endpoint keeps of what happened on each machine, and you search it with KQL. Each load's FileName, FolderPath and SHA1 with the process that loaded it. Join DeviceFileCertificateInfo on SHA1 for the signer.Image Load Events Windows.(documentation, opens in a new tab)Live Machine A Velociraptor artifact. It is a ready-made question Velociraptor asks of running machines, named from general to specific. A built-in artifact listing the DLLs of running processes with their paths, and signer details when CertificateInfo is on.System.DLLs
In a Memory Image
windows.dlllist(documentation, opens in a new tab)Memory Image A Volatility 3 plugin. It is one check run on a saved copy of a Windows machine's memory. dlllist means DLL list. Each module's path from the process's loader list, so a Windows name outside the system folders stands out.windows.(documentation, opens in a new tab)Memory Image A Volatility 3 plugin from its malware group. It checks a memory image for code that hides, or code put into a process. ldrmodules means loader modules. Each region that starts with an MZ header, with the file the kernel recorded for it, to set beside the loader list.malware. ldrmodules
Is the DLL the genuine file of that name?
On a Running Machine
Windows.(documentation, opens in a new tab)Live Machine A Velociraptor artifact. It is a ready-made question Velociraptor asks of running machines, named from general to specific. A built-in artifact that finds DLLs forwarding to a DLL of the same name, a proxy's mark. Its default glob reads only C:\Windows.Detection. Forwarded Imports - Defender for Endpoint live response (documentation, opens in a new tab)Live Machine Part of Defender for Endpoint. It opens a command console on one machine from the Defender portal, so you can list its processes from your desk.
processesIts processes command shows whether the program runs, findfile and fileinfo locate and describe each copy of a DLL name, and getfile collects one. No command lists modules.
In a Memory Image
windows.verinfo(documentation, opens in a new tab)Memory Image A Volatility 3 plugin. It is one check run on a saved copy of a Windows machine's memory. The version information of each loaded DLL, to compare with the genuine file of that name.
What Defenders See
Each record names its log and what must be switched on to get it.
| Record and Where It Lands | What to Read | How to Turn It On |
|---|---|---|
7 Image loaded (opens in a new tab)Microsoft-Windows-Sysmon/OperationalIt is written on any Windows computer running Sysmon. | ImageLoaded, Signed and SignatureStatus for each module show a Windows DLL name outside System32 that is unsigned or carries an unexpected signer.Loaded DLLs shows how to read it. | Run Sysmon with ImageLoad events in its configuration. They are off by default. |
| Device | FileName and FolderPath of the module and the process that loaded it. Join Device | The Defender for Endpoint sensor on the device |
| Device | IsSigned, Signer and IsTrusted for the DLL's SHA1 show whether it is unsigned, untrusted, or has a signer its name does not suggest. | The Defender for Endpoint sensor on the device |
11 FileCreate (opens in a new tab)Microsoft-Windows-Sysmon/OperationalIt is written on any Windows computer running Sysmon. | TargetFilename of a new DLL beside a trusted program, written shortly before it loaded. | Run Sysmon with FileCreate events in its configuration. |
| DeviceFileEvents (opens in a new tab)Each row is a file creation, modification or other file system event, so it shows when a binary landed and which process wrote it.Defender XDR, advanced hunting | FileName, FolderPath and Initiating | The Defender for Endpoint sensor on the device |
What It Looks Like
This record is decoded field by field, with what each value means.
| Field, as the Record Writes It | What It Tells You |
|---|---|
ImageC:\ | The program that loaded it: a signed vendor tool, run from ProgramData. A copy outside its install folder is the first oddity. |
ImageLoadedC:\ | A Windows DLL name, loaded from the program's own folder. The real one lives in System32. |
Signedfalse | No signature at all. The genuine DLL of that name is signed by Microsoft, so this copy is not it. |
CompanyMicrosoft Corporation | Its version information claims Microsoft, yet it carries no signature. Splunk's unsigned Microsoft DLL rule looks for exactly that, in its program's own folder. |
HashesSHA256=(SHA-256 of the file) | Search the hash in threat intelligence and across the estate. The same DLL elsewhere widens the incident. |
- False Positives
Some vendors ship their own copies of common DLLs beside their programs, and portable apps load DLLs from their own folders by design. Check the signer, and whether the vendor ships that file.
Installers and updaters stage signed programs and their DLLs in temporary folders and run them there.
- Blind Spots
Sysmon event 7 is off by default and heavy when on, so a configuration that filters loads can drop the one that matters. Check yours before you trust a miss.
A DLL signed with a stolen or bought certificate passes a signature check, so judge the folder and the signer's name together.
Hunt It
The same hunt is written for four tools, so pick the one you use. Defender XDR and Sentinel queries are in KQL, which you paste into Advanced hunting in the Defender portal or into Sentinel's Logs page. Splunk queries are in SPL, for its Search page, and Velociraptor queries are in VQL, which you run as a hunt.
Needs Defender for Endpoint. DeviceImageLoadEvents has no signer, so the join adds it where Defender has seen the file's certificate. An empty Signer means no data, not proof of no signature.
// DLLs named like a System32 DLL, loaded from outside the system folders and not validly signed by Microsoftlet SystemDllNames = DeviceImageLoadEvents | where Timestamp > ago( 7d) | where FolderPath startswith @"C:\ Windows\ System32\ " | distinct FileName;DeviceImageLoadEvents| where Timestamp > ago( 30d)| where FileName in~ ( SystemDllNames)| where not( FolderPath startswith @"C:\ Windows\ System32\ " or FolderPath startswith @"C:\ Windows\ SysWOW64\ " or FolderPath startswith @"C:\ Windows\ WinSxS\ ")| join kind= leftouter ( DeviceFileCertificateInfo | summarize arg_max( Timestamp, IsSigned, IsTrusted, Signer) by SHA1) on SHA1| where isnull( IsSigned) or not( IsSigned) or not( IsTrusted) or not( Signer startswith "Microsoft")| summarize Loads = count( ), Devices = dcount( DeviceId), FirstSeen = min( Timestamp) by FileName, FolderPath, Signer, IsTrusted, InitiatingProcessFileName, InitiatingProcessFolderPath| order by Devices asc, Loads ascIn a Memory Image
Volatility 3 reads a memory image, and each of its plugins below shows part of this sign.
windows.dlllist(documentation, opens in a new tab)Memory Image A Volatility 3 plugin. It is one check run on a saved copy of a Windows machine's memory. dlllist means DLL list. Each module's path as the loader recorded it, so a Windows DLL name from the program's own folder stands out. Its dump option extracts it.windows.(documentation, opens in a new tab)Memory Image A Volatility 3 plugin from its malware group. It checks a memory image for code that hides, or code put into a process. ldrmodules means loader modules. Every region that starts with an MZ header, with the file the kernel records for it, and whether each of the loader's three lists names it.malware. ldrmodules windows.verinfo(documentation, opens in a new tab)Memory Image A Volatility 3 plugin. It is one check run on a saved copy of a Windows machine's memory. The version numbers of each DLL in the loader's list, to compare with the genuine file of that name.windows.(documentation, opens in a new tab)Memory Image A Volatility 3 plugin. It is one check run on a saved copy of a Windows machine's memory. The DLL and the program as cached in memory, extracted for analysis away from the machine.dumpfiles
Rules to Compare With
Security vendors publish detection rules anyone can read. These look for the same thing, so compare your own with them.
Show the 6 Public Rules
- Potential System DLL Sideloading From Non System Locations (opens in a new tab) SigmaHQ: Flags Windows DLL names loaded from outside System32, SysWOW64 or WinSxS.
- Unsigned DLL Side-Loading from a Suspicious Folder (opens in a new tab) Elastic: Flags a trusted program, run from a folder often used for masquerading, that loads a recently written, unsigned DLL.
- Potential Masquerading as System32 DLL (opens in a new tab) Elastic: Flags DLLs with default System32 names that are unsigned or signed by someone other than Microsoft.
- Windows Unsigned DLL Side-Loading (opens in a new tab) Splunk: Flags unsigned DLLs loaded from System32 or SysWOW64, from Sysmon event 7.
- Windows Unsigned MS DLL Side-Loading (opens in a new tab) Splunk: Flags unsigned DLLs mimicking Microsoft ones that a program outside the system folders loads, from Sysmon event 7.
- T1574.002 - Hijack Execution Flow: DLL Side-Loading (opens in a new tab) FalconForce: Flags DLLs loaded by high integrity processes that a medium integrity process wrote or changed, from DeviceImageLoadEvents and DeviceFileEvents.
How to Prevent It
Each control helps prevent it, and its line says what it does here.
- KnownDLLs (opens in a new tab) Keep KnownDLLs as Windows sets it, so the core DLLs on it always load from the system's own copy. Check it in the Registry: KnownDLLs
- App Control for Business (opens in a new tab) Let only code a policy trusts load, so an unsigned DLL is refused wherever it lands.
- ASR: Block executable files from running unless they meet a prevalence, age, or trusted list criterion (opens in a new tab) Block executable files that are new, rare or untrusted, which Microsoft says covers DLLs as well as programs.
- Secure Boot, which turns AppInit_DLLs off (opens in a new tab) Keep Secure Boot on, so AppInit_DLLs, another way to put a DLL into processes, stays off. Check it in the Registry: AppInit_DLLs
Sources
- Microsoft Learn: Dynamic-link library search order (opens in a new tab)
- Microsoft Learn: Dynamic-Link Library Security (opens in a new tab)
- Microsoft Learn: Sysmon, event ID 7 Image loaded (opens in a new tab)
- Microsoft Defender XDR: DeviceImageLoadEvents table (opens in a new tab)
- Microsoft Defender XDR: DeviceFileCertificateInfo table (opens in a new tab)
- Microsoft Learn: Live response in Defender for Endpoint (opens in a new tab)
- HijackLibs (opens in a new tab)
- Velociraptor: Windows.Detection.ForwardedImports (opens in a new tab)
- SigmaHQ: Potential System DLL Sideloading From Non System Locations (opens in a new tab)
- Elastic: Unsigned DLL Side-Loading from a Suspicious Folder (opens in a new tab)
MITRE ATT&CK is a free public catalogue of the techniques attackers use. Each technique has an ID, such as T1055 for Process Injection, so defenders can name the same behaviour the same way. This page covers these techniques.
- T1574.001 (opens in a new tab) Hijack Execution Flow: DLL
- T1574.008 (opens in a new tab) Hijack Execution Flow: Path Interception by Search Order Hijacking