DLL Hijacking
A Windows program almost never contains all of its code: it loads functions from DLLs at runtime. DLL hijacking means placing a malicious DLL where the program will look for it before the legitimate one, so that our code loads inside its process. If that process runs with privileges (a service as SYSTEM, an admin app), we inherit its privilege level; if another user launches it, we run code in their context.
Mechanism
When an application requests a DLL by name (without an absolute path), Windows looks for it following a fixed order (the search order): the executable's directory, System32, System, the Windows directory, the current directory and, last, the PATH directories. Hijacking exploits two gaps in that order:
- Missing DLL: the program tries to load a DLL that does not exist on the system (an optional dependency, a plugin, a leftover from an old version). Dropping a DLL with that name in a directory searched earlier makes the program load it.
- Writable directory before the good one: if a directory searched before the legitimate DLL's is writable by our user, a DLL with the same name is planted there.
The malicious DLL only needs to export the DllMain entry point and run the payload on load:
// x86_64-w64-mingw32-gcc hijack.c -shared -o legit.dll
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, LPVOID r) {
if (reason == DLL_PROCESS_ATTACH)
system("cmd.exe /c net localgroup administrators <user> /add");
return TRUE;
}How to detect it
The clean way to find candidates is with Procmon (Sysinternals): filter by Result is NAME NOT FOUND and Path ends with .dll, and you get every DLL a privileged process looks for and fails to find, with the exact path where it expects it. Then check whether any of those directories is writable:
icacls "C:\Program Files\Vuln App"Tools like PowerUp (Find-ProcessDLLHijack) and winPEAS automate part of the search. Not to be confused with Linux's LD_LIBRARY_PATH hijack (same idea, different OS) or with the DnsAdmins abuse (a specific case where the DNS service itself loads a DLL on demand).
Defence. Developers should load DLLs with an absolute path and call SetDefaultDllDirectories to harden the search order; administrators should avoid writable application directories and keep software updated (ghost DLLs are usually leftovers of old versions). Related to insecure service permissions and unquoted service path.