DLL search order
Windows DLL loading sequence: (1) Known DLLs registry, (2) application directory, (3) system directory, (4) Windows directory, (5) current directory: sideloading exploits step 2
Event ID 7
Sysmon Image Load event: logs every DLL loaded by any process with the DLL path and signature status; the primary detection source for sideloading
APT10/Lazarus
APT groups known for DLL sideloading: APT10 used legitimate AV software, APT3 used Office binaries, Lazarus Group used legitimate game clients as sideload carriers
SafeDllSearchMode
Windows registry key that moves the current directory search to after system directories: reduces DLL hijacking risk but does not prevent sideloading from the application directory

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Windows application code trusts DLLs in the same directory as the executable by default: this is by design, allowing applications to ship with their own versions of shared libraries. Attackers exploit this trust by dropping a malicious DLL with the right name next to a legitimate signed binary, which then loads the malicious code automatically on execution.

The technique is especially effective against security tools because: (1) the process that loads the malicious DLL is signed by a legitimate vendor, making it appear trusted to AV/EDR; (2) many signed binaries from software vendors are commonly deployed, making them reliable carriers; and (3) it does not require exploiting a vulnerability: only write access to a directory where the carrier binary resides.

DLL Sideloading Mechanics

How DLL search order creates the vulnerability:

Windows DLL search order (SafeDllSearchMode ON):
1. Directories listed in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
2. The directory from which the application loaded
3. The system directory (C:\Windows\System32)
4. The 16-bit system directory
5. The Windows directory (C:\Windows)
6. The current directory
7. Directories listed in PATH environment variable

Step 2 (application directory) is the attack surface:
- If malware places malicious.dll in the same directory as legitapp.exe,
  and legitapp.exe calls LoadLibrary("malicious.dll"),
  Windows loads the malicious version from step 2 before finding the real one in step 3

Common vulnerable scenarios:

Scenario 1: Missing dependency:
  legitapp.exe expects DWrite.dll from System32
  Attacker creates C:\Users\Public\App\DWrite.dll (malicious)
  Attacker also places legitapp.exe in C:\Users\Public\App\\n  legitapp.exe loads malicious DWrite.dll from its own directory

Scenario 2: DLL phantom loading:
  Some applications call LoadLibrary() for DLLs that don't exist on the system
  The DLL load fails silently, but an attacker can create the DLL at the expected path
  Process Monitor can identify phantom DLL loads (NAME NOT FOUND results for DLL lookups)

Scenario 3: PATH hijacking:
  Application expects a DLL in a PATH directory
  Attacker places malicious DLL earlier in PATH (writable directory)

# Identify vulnerable signed binaries:
# Use Process Monitor (Sysinternals) filtered on "NAME NOT FOUND" for .dll files
# These are candidates for phantom DLL hijacking

Detection: Sysmon Image Load Events

Sysmon Event ID 7 (Image Loaded) is the primary detection source: it logs every DLL load with the DLL path and signature status.

Enable Event ID 7 in Sysmon config:

<EventFiltering>
  <ImageLoad onmatch="exclude">
    <!-- Exclude known-good DLL load paths to reduce volume -->
    <ImageLoaded condition="begin with">C:\Windows\System32\</ImageLoaded>
    <ImageLoaded condition="begin with">C:\Windows\SysWOW64\</ImageLoaded>
    <ImageLoaded condition="begin with">C:\Program Files\</ImageLoaded>
    <ImageLoaded condition="begin with">C:\Program Files (x86)\</ImageLoaded>
    <!-- Exclude signed Microsoft DLLs -->
    <Signed condition="is">true</Signed>  <!-- Caution: may miss signed-but-sideloaded DLLs -->
  </ImageLoad>
</EventFiltering>
<!-- Note: Event ID 7 is high volume: tune exclusions carefully -->

Better approach: include only anomalous loads:

<ImageLoad onmatch="include">
  <!-- Unsigned DLLs loaded from non-standard locations -->
  <ImageLoaded condition="contains">\.dll</ImageLoaded>
  <!-- The Signed field helps: unsigned DLL loaded by signed process = suspicious -->
</ImageLoad>

Sentinel KQL: unsigned DLL loaded by signed process:

// Detect sideloading: signed process loading unsigned DLL from unusual path
Event
| where Source == "Microsoft-Windows-Sysmon" and EventID == 7
| extend EventData = parse_xml(EventData)
| extend
    Image = tostring(EventData.DataItem.EventData.Data[4]["#text"]),  // Loading process
    ImageLoaded = tostring(EventData.DataItem.EventData.Data[6]["#text"]),  // DLL path
    Signed = tostring(EventData.DataItem.EventData.Data[10]["#text"]),
    SignatureStatus = tostring(EventData.DataItem.EventData.Data[12]["#text"])
| where Signed == "false"
// Exclude known-safe paths
| where ImageLoaded !startswith @"C:\Windows\\"
    and ImageLoaded !startswith @"C:\Program Files\\"
// Flag unsigned DLLs loaded from user-writable locations
| where ImageLoaded matches regex @"(?i)(\\temp\\|\\appdata\\|\\users\\|\\downloads\\|\\public\\)"
| summarize
    count(),
    make_set(ImageLoaded)
    by Image, Computer, bin(TimeGenerated, 1h)
| sort by count_ desc

Detect DLL loaded from same directory as suspicious executable:

Event
| where Source == "Microsoft-Windows-Sysmon" and EventID == 7
| extend EventData = parse_xml(EventData)
| extend
    Image = tostring(EventData.DataItem.EventData.Data[4]["#text"]),
    ImageLoaded = tostring(EventData.DataItem.EventData.Data[6]["#text"]),
    Signed = tostring(EventData.DataItem.EventData.Data[10]["#text"])
// Extract directory of loading process
| extend ProcessDir = tostring(split(Image, "\\")[0..array_length(split(Image, "\\"))-2])
// Extract directory of loaded DLL
| extend DLLDir = tostring(split(ImageLoaded, "\\")[0..array_length(split(ImageLoaded, "\\"))-2])
// DLL is in same directory as the loading executable (sideloading pattern)
| where ProcessDir == DLLDir
    and Signed == "false"
    and ProcessDir !startswith @"C:\Windows"
    and ProcessDir !startswith @"C:\Program Files"
| project TimeGenerated, Computer, Image, ImageLoaded, ProcessDir
Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Finding Vulnerable Binaries and Hardening

Find sideloadable binaries in your environment:

# Use SigCheck (Sysinternals) to find signed executables that load unsigned DLLs:
SigCheck64.exe -accepteula -c -h C:\Tools\AppDirectory\
# Look for: signed executables that reference unsigned DLLs in the same directory

# Use Process Monitor during application testing:
# Filter: Result = NAME NOT FOUND; Path ends with .dll
# These are phantom DLL load attempts: if an attacker places a DLL with that name
# in the application directory, it will be loaded

# Tools for finding hijackable DLLs:
# DLLSpy: https://github.com/cyberark/DLLSpy
# RobbinHood (deprecated): scans for vulnerable DLL search paths

# PowerShell: find directories in PATH that are user-writable
$env:PATH -split ';' | ForEach-Object {
    $dir = $_
    try {
        $acl = Get-Acl $dir -ErrorAction Stop
        $writable = $acl.Access | Where-Object {
            $_.FileSystemRights -match 'Write|FullControl|Modify' -and
            $_.IdentityReference -match 'Users|Authenticated Users|Everyone'
        }
        if ($writable) { "WRITABLE: $dir" }
    } catch { "NOT FOUND: $dir" }
}
# Writable PATH directories are DLL hijacking candidates

Hardening against DLL sideloading:

  1. Application directory permissions: Do not allow non-admin users to write to application installation directories. Use icacls to verify:
icacls "C:\Program Files\VendorApp" | \
  Select-String "Users|Everyone" | \
  Where-Object { $_ -match 'W|F|M' }
# Any write permission for Users/Everyone = DLL sideloading risk
  1. Enable SafeDllSearchMode: The registry value HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDllSearchMode = 1 (default in modern Windows) moves the current directory search to after system directories: reduces hijacking risk but not sideloading from application directories.

  2. WDAC or AppLocker DLL rules: Configure Windows Defender Application Control to only allow signed DLLs from approved publishers. Note: DLL rules have high performance overhead and require thorough testing.

  3. Vendor notification: If you identify a vendor application that sideloads vulnerable DLLs, notify the vendor: this is a vulnerability in their product that they should fix by using fully qualified paths or manifest-based loading.

The bottom line

DLL sideloading exploits Windows DLL search order: the application directory is searched before system directories, so attackers place malicious DLLs alongside legitimate signed executables. Detection requires Sysmon Event 7 (Image Load) monitoring for unsigned DLLs loaded from user-writable directories or loaded from the same directory as suspicious executables. Use Process Monitor filtered on "NAME NOT FOUND" for .dll files to proactively identify phantom DLL load opportunities in your deployed software. Harden by verifying application directory permissions (no user write access), enabling SafeDllSearchMode, and considering WDAC DLL rules for high-sensitivity environments.

Frequently asked questions

What is DLL sideloading and how does it differ from DLL hijacking?

DLL sideloading places a malicious DLL alongside a legitimate signed executable that loads DLLs from its own directory: the legitimate process loads the malicious DLL, running attacker code under a trusted process. DLL hijacking is broader: it includes placing DLLs in writable directories in the DLL search path (PATH hijacking) or creating DLLs that an application tries to load but cannot find (phantom DLL hijacking). Both exploit Windows DLL search order; sideloading specifically abuses the application-directory priority.

How do you detect DLL sideloading with Sysmon?

Enable Sysmon Event ID 7 (Image Load) and alert on unsigned DLLs (Signed = false) loaded from user-writable paths like %TEMP%, %APPDATA%, C:\Users\, and C:\Public\. A stronger signal: an unsigned DLL loaded from the same directory as the loading process, when that directory is not C:\Windows or C:\Program Files. Use Microsoft Sentinel KQL or Splunk to correlate Image (loading process path) and ImageLoaded (DLL path) to find cases where both files share the same directory and the DLL is unsigned.

What is DLL search order hijacking and how does it differ from sideloading?

DLL hijacking (search order hijacking) exploits the Windows DLL search order: when an application loads a DLL without a full path, Windows searches in a specific order starting with the application directory. If an attacker places a malicious DLL with the same name as a legitimate DLL in the application directory (which the attacker can write to), Windows loads the malicious DLL instead of the legitimate system DLL. DLL sideloading is a variant where the attacker deliberately places a legitimate application that loads DLLs alongside a malicious DLL of the expected name — the legitimate app becomes the launch vehicle. The difference: hijacking exploits a vulnerability in the application's search order; sideloading uses a legitimate application's expected behavior.

How do attackers use DLL sideloading for persistence?

DLL sideloading provides persistence by embedding malicious code in a DLL that runs every time a trusted application starts. Common technique: place a modified version of a DLL loaded by a legitimate Windows tool (OneDrive, Teams, or other trusted software) in a user-writable directory, then configure the legitimate application to launch at startup. The malicious DLL proxies all legitimate exports to the real DLL while also executing malware. Because the legitimate application is running and signed by a trusted publisher, it bypasses application allowlisting and reduces suspicion. APT groups including APT41, Lazarus Group, and TA505 have used DLL sideloading extensively in their operations.

How do I find DLL hijacking vulnerabilities in my environment?

Use Process Monitor (Procmon) from Sysinternals: filter for 'Result is NAME NOT FOUND' and 'Path ends with .dll' to capture DLL search misses — when an application looks for a DLL that does not exist in a user-writable path, that is a hijacking opportunity. Run Procmon as a standard user (not admin) to see hijacking opportunities available to low-privilege attackers. For automated analysis, the tool 'DLLHijackAudit' by @XPN (MDSec Research) automates this analysis across running processes. For a registry-based approach, check the KnownDLLs registry key: DLLs listed there are loaded from the System32 directory regardless of search order — adding your DLL to KnownDLLs prevents hijacking for that specific DLL.

How do you build a WDAC policy that blocks unsigned DLL loads from user-writable paths without breaking legitimate software?

Start by running WDAC in audit mode: deploy the policy via 'CiTool --merge-policy' with the policy option 'Enabled:Audit Mode Only' and collect CI audit events (Event 3076 and 3077 in the Microsoft-Windows-CodeIntegrity/Operational log) for two to four weeks across representative machines. Use the 'New-CIPolicy -ScanPath' cmdlet against directories containing your approved software to generate a baseline allow list from installed binaries. For the DLL block rule, add a deny rule scoped to unsigned DLLs loaded from paths matching %LOCALAPPDATA%, %TEMP%, and %PUBLIC% using the 'FilePathRule' element in the policy XML. Merge the deny rules with the allow rules using 'Merge-CIPolicy' and test the merged policy in audit mode before switching to Enforced. Monitor Event 3077 (enforcement block) for legitimate software collisions and add specific file hash or publisher allow rules for each blocked file before moving to production enforcement.

Sources & references

  1. MITRE ATT&CK T1574.002: DLL Side-Loading
  2. Microsoft: Dynamic-Link Library Security
  3. Mandiant: DLL Sideloading APT Groups

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.