Skip to content
Code Injectionintermediate

DLL Search Order Hijacking

Malware places a trojan DLL in a directory searched before the legitimate library location, causing Windows to load the malicious version when the target application starts.

Windows resolves DLL names using a fixed search order. By default (with SafeDllSearchMode enabled), the order is:

  1. The directory containing the loading executable
  2. The system directory (System32)
  3. The 16-bit system directory
  4. The Windows directory
  5. The current working directory
  6. Directories listed in the PATH environment variable

If an application tries to load a DLL that does not exist in System32 (or loads it by relative name), any DLL with the correct name placed in the application's own directory — or anywhere earlier in the search path — will be loaded instead.

Attackers use this to achieve persistence (the trojan DLL runs every time the application starts) or privilege escalation (when the vulnerable application runs as a higher-privilege account).

How it works

A trojan DNSAPI.dll placed alongside a target binary that dynamically loads DNSAPI.dll by relative name:

c
// trojan_dnsapi.c — compiled as DNSAPI.dll
#include <windows.h>

// Forward all real exports to the legitimate DLL (DLL proxying)
#pragma comment(linker, "/export:DnsQuery_A=C:\\Windows\\System32\\DNSAPI.DnsQuery_A,@1")
// ... additional exports ...

BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH) {
        // Malicious payload — runs with the privileges of the loading application
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)payload, NULL, 0, NULL);
    }
    return TRUE;
}

Discovery tools such as DLLirant and Procmon (filter on NAME NOT FOUND + *.dll) automate identification of vulnerable load paths.

text
Procmon filter:
  Operation  is  CreateFile
  Path       ends with  .dll
  Result     is  NAME NOT FOUND

Detection & analysis

During analysis:

  • Run the target application under Procmon/API Monitor: a LoadLibrary call that results in NAME NOT FOUND in System32 but SUCCESS in the application directory is proof of a hijack opportunity.
  • Check the target binary's import table for DLLs absent from System32; also check LoadLibrary/LoadLibraryEx calls with relative paths.

Static / automated detection:

  • YARA rule: DLL with DLL_PROCESS_ATTACH handler + CreateThread + an exported name matching a known system DLL export — especially when the DLL is not signed.
  • MITRE ATT&CK T1574.001; Unprotect code snippet U1574.
  • Application control (WDAC/AppLocker): restrict DLL loading to trusted, signed binaries; enforce PreferSystem32Images in the process mitigation policy.
Votes

Comments(0)