← All posts

Phantom DLL Hijacking: Auditing the DLLs Windows Searches For But Never Ships

Windows processes routinely try to load DLLs that do not exist on disk. Here's how phantom DLL hijacking works, why it's a stealthy persistence and privilege-escalation path, and how to audit for it.

Open Process Monitor on a freshly booted Windows machine, filter for Result is NAME NOT FOUND and Path ends with .dll, and you will see something that unsettles most engineers the first time: dozens of trusted, signed processes — including services running as SYSTEM — repeatedly asking the OS to load DLLs that simply are not there. The loader walks its search path, fails to find the file, shrugs, and carries on. These are ghost or phantom DLLs, and the gap between "a process will load this file" and "this file does not exist" is a privilege-escalation and persistence primitive hiding in plain sight.

Why Windows looks for DLLs that aren't there

A phantom DLL reference is almost always a benign side effect of modular code. An application links against an import library for an optional feature, probes for a plugin that was never installed, or carries a dependency that only ships in a different SKU. When LoadLibrary is called with a bare filename rather than a fully qualified path, the loader consults the standard DLL search order:

  1. The directory the executable was launched from
  2. The system directory (C:\Windows\System32)
  3. The 16-bit system directory, then the Windows directory
  4. The current working directory (when safe search is off)
  5. Each directory listed in the PATH environment variable

If none of those locations hold the named DLL, the import fails quietly. The danger is the first and last entries: if an attacker can drop a malicious DLL with the phantom's exact name into a directory that appears earlier in the search order than where the real file would have lived — or into any writable PATH directory — their code loads instead, inside the host process, with the host's token.

Why this is worse than classic DLL search-order hijacking

Traditional DLL hijacking competes with a real, on-disk DLL and relies on winning the search-order race. Phantom hijacking has no competition at all: the file genuinely does not exist, so the attacker's DLL is the only candidate. That removes the timing fragility and the risk of breaking the host application by shadowing a legitimate dependency. It also evades a surprising amount of tooling — integrity checks that verify "every DLL on disk is signed" never fire, because the malicious DLL is a brand-new file, not a modification of something Microsoft shipped.

The payoff scales with the host:

Hunting phantom DLLs with Process Monitor

The canonical discovery technique is a Procmon capture across a boot and a few minutes of normal use, filtered to surface the misses:

Operation  is  Load Image        -> Exclude
Path       ends with  .dll        -> Include
Result     is  NAME NOT FOUND     -> Include

For each hit, the question is simple: is the directory where the DLL was expected writable by a non-admin? A phantom under System32 is uninteresting because only admins can write there. A phantom probed from an application folder under C:\Program Files\Vendor\ whose ACLs grant Authenticated Users: Modify — or from a PATH entry pointing at a user-writable directory — is an exploitable finding.

Validating writability

PowerShell makes the ACL check scriptable so you can triage dozens of hits quickly:

Get-Acl 'C:\Program Files\Vendor' |
  Select-Object -ExpandProperty Access |
  Where-Object {
    $_.FileSystemRights -match 'Write|Modify|FullControl' -and
    $_.IdentityReference -match 'Users|Authenticated|Everyone'
  }

Pair that with an audit of every directory on the machine and service PATH — a single user-writable PATH entry turns every phantom reference on the box into a hijack opportunity.

Hardening against phantom loads

Where WinSentinel fits

Phantom DLL hijacking is invisible to signature-based tools precisely because there is nothing malicious on disk until the moment of attack. WinSentinel approaches it structurally: its auditing engine enumerates writable directories that sit on service and process search paths, flags Program Files subtrees and PATH entries with weak ACLs, and surfaces the exact misconfiguration — a SYSTEM service searching a user-writable folder — as a prioritized finding with remediation guidance. Every WinSentinel install runs the full set of 64 audit modules with no feature gating, so a single engineer hardening one workstation gets the same depth of search-path analysis as a managed endpoint.

For organizations, WinSentinel Pro rolls those findings up across the fleet: the central node aggregates writable-path and DLL-search-order risk from every agent, alerts when a new deployment or a vendor update re-introduces a weak ACL (drift), and lets you confirm the whole estate is clean rather than auditing machines one at a time.

The files that aren't there are as dangerous as the ones that are. Audit the search path, lock down the writable directories, and a whole class of signed-process code execution closes before an attacker can use it.