Windows application branching DLL search path

DLL Hijacking Explained: How Windows Can Load the Wrong DLL and How Hackers Abuse It

spyboy's avatarPosted by

You click an application.

It launches normally.

You see the familiar interface.

But behind the scenes, Windows may be searching through multiple locations to find the libraries that application needs.

Those libraries are often:

.dll

files.

And here’s where Windows security gets interesting.

What happens if an application expects:

example.dll

but the DLL it loads isn’t the one the developer intended?

What if an attacker can place a malicious or modified DLL somewhere Windows searches first?

The application may load it.

The application may still appear completely normal.

And the unexpected code may execute inside the application’s process.

This class of attack is commonly known as:

DLL Hijacking

It’s one of the most interesting Windows security concepts because it combines:

  • Windows internals
  • File-system behavior
  • Application security
  • Process execution
  • Privilege boundaries
  • Malware analysis
  • Reverse engineering
  • Defensive monitoring

And unlike some vulnerabilities that require exploiting a complicated memory corruption bug, DLL hijacking can arise from something much simpler:

An application doesn’t specify exactly where a required DLL should come from.

Let’s break down how it works.


⚠️ Important: Use This Only in Your Own Lab

DLL loading is a legitimate Windows mechanism.

The same mechanism can be abused to execute unauthorized code.

For this reason, the practical examples below focus on:

  • Understanding DLL search behavior
  • Identifying vulnerable applications
  • Defensive analysis
  • Benign test DLLs in a VM
  • Process monitoring
  • Secure application development

Do not replace DLLs inside software you don’t own or don’t have permission to test.

For experimentation, use a Windows virtual machine.


What Is a DLL?

DLL stands for:

Dynamic Link Library

A DLL is a Windows library containing code and/or resources that applications can use.

Instead of putting everything inside one executable:

application.exe

a program can use:

application.exe
↓
example.dll
↓
additional functionality

This allows multiple applications or components to share functionality.

Windows itself relies heavily on DLLs.

You’ll find them throughout:

C:\Windows\System32\

and other application directories.


Why Do Applications Use DLLs?

Imagine a program needs functionality for:

Networking
Graphics
Encryption
Audio
Database access
User interface
File handling

Instead of implementing everything inside one executable, developers can use libraries.

Conceptually:

                  application.exe
                        │
          ┌─────────────┼─────────────┐
          │             │             │
          ▼             ▼             ▼
      graphics.dll   network.dll   crypto.dll

This makes software modular.

But it also creates a security boundary:

How does Windows find each DLL?


The Problem: DLL Search Order

Suppose an application requests:

example.dll

The application doesn’t necessarily specify:

C:\Program Files\Company\App\example.dll

It might simply request:

example.dll

Windows then has to determine where that DLL should be loaded from.

The exact DLL resolution behavior depends on the application, APIs used, Safe DLL Search Mode, packaging, manifests, loader configuration, and other factors.

But conceptually, the process looks like:

Application
↓
Requests example.dll
↓
Windows searches eligible locations
↓
Finds a matching DLL
↓
Loads it

If an attacker can influence where the DLL is found first, the application may load the wrong library.


What Is DLL Hijacking?

DLL hijacking occurs when an application loads an unintended DLL because of how DLL resolution is configured or because an attacker can influence a searched location.

A simplified scenario:

Legitimate application
↓
Needs example.dll
↓
Windows searches for it
↓
Unexpected DLL found first
↓
DLL loaded

If the unexpected DLL contains attacker-controlled code, that code may execute with the privileges of the process loading it.

That’s the core idea.


A Simple Mental Model

Think about a restaurant.

The application says:

“Bring me example.dll.”

Windows asks:

“Where is it?”

If the application doesn’t clearly specify the trusted source, Windows may search according to its DLL resolution rules.

An attacker who can place a file in an earlier search location may try to make Windows load that file.

So:

Weak DLL resolution
+
Attacker-controlled search location
↓
Unexpected DLL loaded

DLL Hijacking vs DLL Side-Loading

These terms are often mixed together.

They’re related, but not identical.

DLL Hijacking

The attacker takes advantage of DLL resolution behavior so an application loads an unintended library.

DLL Side-Loading

A legitimate application loads a malicious DLL because the application is tricked or designed into loading a DLL from an attacker-controlled location.

A common side-loading scenario conceptually looks like:

Legitimate EXE
+
Malicious DLL
↓
Legitimate process loads unexpected DLL

The distinction isn’t always used consistently across security literature, so focus on the underlying behavior rather than arguing over terminology.


Why Attackers Like DLL Hijacking

There are several reasons this technique is interesting.

The malicious code may execute:

Inside a legitimate process

rather than as an obviously suspicious standalone executable.

Depending on the scenario, the process may also inherit:

  • User privileges
  • Network access
  • Environment
  • Application trust relationships

This can make investigation more complicated.

But don’t make the common mistake of assuming:

“A legitimate executable loaded a DLL, therefore the DLL is malicious.”

Legitimate applications load DLLs constantly.

The important question is:

Which DLL was loaded, from where, and was that location expected?


What Does a Normal DLL Load Look Like?

Suppose:

C:\Program Files\Example\App.exe

expects:

example.dll

and the intended DLL is:

C:\Program Files\Example\example.dll

That’s normal.

The suspicious situation might be:

C:\Users\Public\example.dll

or another unexpected writable directory being selected instead.

Again, the exact security significance depends on the application’s loading behavior and permissions.


Why Writable Directories Matter

Imagine an application searches:

C:\SomeDirectory\

for a DLL.

Now imagine a normal user can write files there.

If the application runs with higher privileges and loads DLLs from that directory, you potentially have a privilege-boundary problem.

Conceptually:

Low-privileged user
↓
Can write DLL
↓
Privileged application
↓
Loads DLL
↓
Code executes with application privileges

That’s where DLL hijacking can become much more serious.


DLL Hijacking Isn’t Automatically Privilege Escalation

This distinction is critical.

Suppose a normal user runs:

application.exe

and a hijacked DLL executes.

If the application is also running as the same normal user, you haven’t necessarily achieved privilege escalation.

You may have demonstrated code execution in the application’s context.

For privilege escalation, you need something like:

Low privilege
↓
DLL placement/control
↓
Privileged process loads DLL
↓
Higher privilege execution

The actual privileges of the target process matter.


The Interesting Question

When researching DLL hijacking, don’t simply ask:

“Can I get a DLL loaded?”

Ask:

“Who loads it, from where, and with what privileges?”

That is the security question.


How to Find Potential DLL Hijacking

If you’re performing authorized research, one useful methodology is:

Application
↓
Observe DLL loads
↓
Identify missing/unresolved DLLs
↓
Determine search locations
↓
Check directory permissions
↓
Determine whether a controlled DLL can be loaded
↓
Assess process privileges

The safest way to study this is inside a VM.


Process Monitor Is Your Friend

Microsoft Sysinternals Process Monitor (Procmon) is extremely useful for studying Windows file and process activity.

It can show file-system operations such as:

CreateFile
QueryOpen
Load Image

among many other events.

For DLL research, Procmon can help you see the application’s attempts to locate libraries.

Conceptually:

App.exe
↓
Looks for example.dll
↓
Path A → NOT FOUND
↓
Path B → NOT FOUND
↓
Path C → FOUND
↓
DLL loaded

That sequence is incredibly useful.


A Typical Procmon Investigation

Suppose you start:

example.exe

and filter Procmon for:

Process Name = example.exe

Then look for operations involving:

.dll

You may discover something like:

NAME NOT FOUND
C:\Example\example.dll
NAME NOT FOUND
C:\Windows\example.dll
SUCCESS
C:\Example\example.dll

The exact paths depend on the application and Windows configuration.

The important thing is learning to observe the resolution process.


What Does “NAME NOT FOUND” Mean?

In Procmon, a:

NAME NOT FOUND

result generally means that an attempted file-system lookup did not find an object at that location.

That’s not automatically a vulnerability.

Applications frequently look for optional files.

The interesting pattern is:

Missing DLL
↓
Search continues
↓
Writable location
↓
Unexpected DLL successfully loaded

That combination can indicate a security-relevant loading weakness.


Don’t Confuse DLL Search With a Vulnerability

This is one of the biggest mistakes beginners make.

Suppose you see:

example.dll
NAME NOT FOUND

That does not mean:

“DLL hijacking found!”

It simply means Windows or the application attempted to access something that wasn’t found.

You need to establish:

  1. The application actually loads the library.
  2. A user-controlled location can influence the result.
  3. The loaded DLL can be controlled.
  4. The behavior is reproducible.
  5. There is meaningful security impact.

A Safe DLL Lab

The safest way to learn DLL hijacking is to build your own intentionally vulnerable program.

You can create a simple Windows application that requests:

lab.dll

without specifying an absolute trusted path.

Then observe the loading process.

For example:

C:\DLL-Lab\
lab.exe

and:

C:\DLL-Lab\
lab.dll

You can use Procmon to observe how the application locates the library.

This teaches the fundamental behavior without modifying third-party software.


A Simple Conceptual Lab

Your lab structure can be:

DLL-Lab
│
├── lab.exe
└── lab.dll

The executable loads:

lab.dll

When you launch it:

lab.exe
↓
Requests lab.dll
↓
Windows resolves DLL
↓
lab.dll loaded

Now change the experiment by placing the application and library in different controlled directories.

Observe what happens with Procmon.


Why Building Your Own Lab Is Better

You might find tutorials online telling you:

“Download this old vulnerable application.”

Don’t blindly download random executables.

You don’t know:

  • Whether the software is actually vulnerable
  • Whether the download is trustworthy
  • Whether the sample has been modified
  • Whether the tutorial is outdated
  • Whether the technique works on current Windows

A small local lab gives you complete control.


DLL Search Order Is More Complicated Than One List

You will often find articles online showing a simple sequence like:

Application directory
System directory
Windows directory
PATH
...

But don’t memorize a single universal list.

DLL resolution behavior can vary depending on:

  • API used
  • Safe DLL Search Mode
  • Application manifest
  • Known DLLs
  • Package identity
  • Loader flags
  • Absolute vs relative paths
  • Windows version
  • Application architecture

The important security lesson is:

Never assume every DLL lookup follows exactly the same search order.

Observe the actual application behavior.


Absolute Paths vs Bare DLL Names

Compare these conceptual approaches.

Less specific

LoadLibrary("example.dll")

The loader must resolve the DLL name.

More specific

LoadLibrary("C:\\TrustedApp\\example.dll")

The developer has specified the intended location.

The second approach can reduce ambiguity, although secure DLL loading requires considering more than simply using an absolute path.


DLL Search Path Hardening

Modern Windows applications have multiple ways to control DLL loading behavior.

Developers can use safer loading patterns and APIs that explicitly define trusted directories or restrict search behavior.

The general principle is:

Don't make Windows guess where security-sensitive code should come from.

Specify trusted locations.


Why Current Working Directory Can Matter

Applications sometimes load resources relative to their current working directory.

That can create security problems if the application assumes:

“The current directory is trusted.”

But the current directory can sometimes be influenced by how an application is launched.

This is why secure software should carefully control where it loads executable code from.


The Dangerous Pattern

Conceptually:

Application
↓
Searches broad locations
↓
User-controlled directory
↓
Loads matching DLL

The security problem is the trust boundary.


The Safer Pattern

A better model is:

Application
↓
Known trusted directory
↓
Expected DLL
↓
Signature / integrity validation where appropriate
↓
Load

The exact implementation depends on the application architecture.


DLL Hijacking and Signed Applications

Here’s another interesting security concept.

Imagine:

TrustedApp.exe

is digitally signed.

Does that mean everything it loads is trustworthy?

Not necessarily.

A signed executable can load external libraries.

So defenders shouldn’t only ask:

Is the EXE signed?

They should also ask:

Which DLLs did it load?
Where did they come from?
Are they signed?
Are their paths expected?

This is particularly important in threat hunting.


DLL Side-Loading and Legitimate Applications

Attackers have historically abused legitimate applications as loaders for malicious DLLs.

Conceptually:

Legitimate.exe
+
Unexpected.dll
↓
Legitimate.exe loads DLL

The legitimate executable itself may be completely genuine.

That’s why file reputation alone isn’t enough.

The relationship between:

EXE
+
DLL
+
Path
+
Parent process
+
User

matters.


How Defenders Detect DLL Hijacking

Security teams can monitor:

1. DLL load paths

Was a DLL loaded from:

Temp
Downloads
Public
User profile
Network share
Unusual writable directory

?

2. Signature status

Is the DLL digitally signed?

3. File location

Does the DLL live where the application normally expects it?

4. Process relationships

Which process loaded it?

5. Timing

Was the DLL created immediately before execution?

6. Network behavior

Did the process suddenly communicate externally?


A Simple Defensive Investigation

Suppose you see:

App.exe
↓
loads:
C:\Users\Public\example.dll

Don’t immediately conclude:

Malware!

Instead investigate:

Is this the application's expected directory?
Is the DLL signed?
Who created it?
When was it created?
What software installed it?
Does the application documentation reference it?
Does the DLL match the expected version?

That is proper analysis.


Use PowerShell to Inspect DLLs

You can examine a DLL file’s basic metadata with PowerShell.

For example:

Get-Item "C:\Path\example.dll" |
Select-Object Name, Length, CreationTime, LastWriteTime

You can inspect version information:

(Get-Item "C:\Path\example.dll").VersionInfo |
Select-Object FileDescription, FileVersion, ProductName, CompanyName

You can also calculate a hash:

Get-FileHash "C:\Path\example.dll" -Algorithm SHA256

A hash doesn’t prove a file is malicious.

But it gives you a stable identifier for comparison and investigation.


Check a DLL’s Digital Signature

PowerShell can also inspect Authenticode signatures:

Get-AuthenticodeSignature "C:\Path\example.dll"

You may see a status such as:

Valid

or:

NotSigned

or another status.

Again:

Unsigned does not automatically mean malicious.

Many legitimate DLLs may not have a signature.

Signature status is one piece of evidence.


Build a DLL Investigation Script

Create:

dll-check.ps1
param(
[Parameter(Mandatory=$true)]
[string]$Path
)
if (-not (Test-Path $Path)) {
Write-Host "File not found: $Path"
exit
}
$file = Get-Item $Path
Write-Host "================================="
Write-Host " DLL SECURITY CHECK"
Write-Host "================================="
Write-Host "`n[File]"
Write-Host "Name: $($file.Name)"
Write-Host "Path: $($file.FullName)"
Write-Host "Size: $($file.Length)"
Write-Host "`n[Hashes]"
Get-FileHash $file.FullName -Algorithm SHA256
Write-Host "`n[Version Information]"
$file.VersionInfo |
Select-Object FileDescription,
FileVersion,
ProductName,
CompanyName
Write-Host "`n[Digital Signature]"
Get-AuthenticodeSignature $file.FullName |
Select-Object Status, StatusMessage, SignerCertificate

Run:

.\dll-check.ps1 -Path "C:\Path\example.dll"

Now you have a basic DLL triage tool.


DLL Hijacking and Privilege Escalation

This is where researchers become particularly interested.

Suppose:

Normal User
↓
Can write DLL
↓
Privileged Service
↓
Loads DLL

If the privileged service loads that attacker-controlled DLL, the attacker may gain code execution under the service’s account.

That can potentially become a privilege-escalation vulnerability.

But it needs to be demonstrated.


A Security Researcher’s Checklist

If you think you’ve discovered a DLL hijacking issue in software you’re authorized to test, verify:

1. Missing DLL

Does the application genuinely attempt to load the DLL?

2. Search path

Where does it look?

3. Write access

Can the relevant lower-privileged user actually place a file there?

4. Load

Does the application load the controlled library?

5. Privileges

What account runs the application?

6. Reliability

Does it happen consistently?

7. Impact

Does it result in code execution, privilege escalation, or another security consequence?


Don’t Use a Real Malware DLL for Testing

You don’t need malware to demonstrate a DLL-loading problem.

For authorized testing, a harmless proof-of-concept DLL can simply:

Display a message
Write a benign test marker
Record a timestamp in a lab directory

The goal is to demonstrate:

Controlled DLL
↓
Loaded by target application

not to deploy malware.


Why “Proof of Execution” Matters

Imagine your application:

test.exe

attempts to load:

missing.dll

You place a controlled test DLL where the application can find it.

If your harmless DLL produces an obvious lab-only marker:

DLL_TEST_SUCCESS

you’ve demonstrated that the application loaded your library.

That’s enough to establish the core behavior.

You don’t need destructive actions.


DLL Hijacking in Bug Bounties

If you’re testing desktop software under a legitimate vulnerability disclosure program, reports should clearly explain:

Affected application
Affected version
DLL name
Expected DLL path
Observed search behavior
Attacker-controlled location
Required permissions
Proof of loading
Security impact
Recommended remediation

A good report doesn’t say:

“I can hack this application.”

Instead:

“The application loads a DLL from a user-writable search location, allowing a lower-privileged user to execute code in the application’s security context.”

That is much more precise.


Common DLL Hijacking Mistakes

❌ Mistake 1: “Any missing DLL is vulnerable.”

No.

A missing DLL may simply indicate optional functionality.


❌ Mistake 2: “Unsigned DLL = malware.”

No.

Signature status is only one signal.


❌ Mistake 3: “DLL hijacking always means SYSTEM.”

Absolutely not.

The privileges depend on the process that loads the DLL.


❌ Mistake 4: “A signed EXE is automatically safe.”

Not necessarily.

It can load external libraries.


❌ Mistake 5: “The search order is always identical.”

No.

Windows DLL resolution depends on the API and configuration.


❌ Mistake 6: Testing on random third-party software.

Don’t.

Use software you own or an authorized security program.


DLL Hijacking vs Other Windows Attacks

TechniqueCore Problem
DLL HijackingApplication loads unintended DLL
DLL Side-LoadingLegitimate application loads attacker-controlled DLL
DLL Search Order HijackingSearch resolution favors attacker-controlled location
DLL ProxyingMalicious/replacement DLL forwards functionality while adding behavior
Process InjectionCode is inserted into another process
Registry PersistenceStartup/configuration mechanism abused
WMI PersistenceWMI event mechanism abused for persistence

These techniques can overlap in real-world malware, but they are conceptually different.


Why This Matters for Malware Analysis

When analyzing a suspicious Windows executable, don’t just inspect:

.exe

Also inspect:

.dll

dependencies.

Ask:

Which libraries does it load?
Where are they loaded from?
Are they expected?
Are they signed?
Were they created recently?
Are they located in unusual directories?

A suspicious DLL alongside a legitimate executable can be a major clue.


Your Windows Security Learning Path Is Getting Interesting

You’ve now covered several pieces:

BAT
↓
CMD
↓
Registry
↓
Event Viewer
↓
WMI
↓
NTFS ADS
↓
DLL Loading

These aren’t random Windows tricks.

They’re pieces of the operating system’s security model.

Next, you can move toward:

PowerShell
Windows Services
Task Scheduler
Active Directory
Windows Authentication
Sysinternals
EDR
Malware Analysis
Threat Hunting

10-Minute DLL Investigation Lab

You can start learning immediately.

Step 1

Install a legitimate test application in a Windows VM.

Step 2

Start Process Monitor.

Step 3

Filter:

Process Name
is
your-test-application.exe

Step 4

Observe .dll file activity.

Step 5

Look for:

NAME NOT FOUND

and:

SUCCESS

events involving DLLs.

Step 6

Record:

DLL name
Path
Result
Process
Timestamp

Step 7

Determine whether the loaded DLL came from the expected application directory.

That’s a legitimate Windows security investigation.


A Simple DLL Hunting Workflow

Use this mental model:

        APPLICATION
             │
             ▼
       DLL REQUEST
             │
             ▼
       DLL RESOLUTION
             │
       ┌─────┴─────┐
       │           │
    Expected    Unexpected
       │           │
       ▼           ▼
    Trusted     Investigate
       │           │
       └─────┬─────┘
             ▼
        DLL LOADED
             │
             ▼
       PROCESS CONTEXT
             │
             ▼
          IMPACT

This is the real security workflow.


Frequently Asked Questions

What is DLL hijacking?

DLL hijacking is a class of Windows vulnerabilities where an application loads an unintended DLL because of how DLL resolution is configured or because an attacker can influence a location from which the application searches.

What is DLL side-loading?

DLL side-loading generally describes situations where a legitimate executable loads an attacker-controlled or otherwise unintended DLL, often because of how the executable resolves its dependencies.

Is DLL hijacking a Windows vulnerability?

Not necessarily. It can result from application design, deployment configuration, writable directories, or insecure DLL-loading behavior.

Does DLL hijacking always give administrator access?

No. The resulting code executes with the privileges of the process that loads the DLL.

How can I detect DLL hijacking?

Tools such as Microsoft Sysinternals Process Monitor can help observe DLL lookup and loading behavior. Security teams can also inspect DLL paths, signatures, hashes, process relationships, and file creation activity.

Is an unsigned DLL malicious?

No. Many legitimate libraries may be unsigned. Signature status is only one piece of evidence.

Can DLL hijacking be used for persistence?

It can potentially be involved in persistence depending on the application and execution conditions, but DLL hijacking and persistence are separate concepts.

Can I learn DLL hijacking without malware?

Absolutely. A controlled Windows VM and a small test application are enough to understand the fundamentals.


Final Takeaway

A Windows application might appear to be:

application.exe

But underneath it may depend on:

application.exe
│
├── library1.dll
├── library2.dll
├── library3.dll
└── library4.dll

The application has to find those libraries somehow.

And when developers don’t properly control that process, the DLL-loading mechanism can become a security boundary.

That’s the fundamental idea behind DLL hijacking.

For hackers and vulnerability researchers, the interesting questions are:

Which DLL is being requested?

Where does Windows look for it?

Can an unauthorized user influence one of those locations?

Who runs the application?

What happens when the DLL is loaded?

For defenders, the questions become:

Which DLLs did this process load?

Were they expected?

Where did they come from?

Are they signed?

Who created them?

What happened immediately afterward?

That’s why DLL hijacking is much more than a “hacking trick.”

It teaches one of the most important principles in Windows security:

Never trust a file simply because a trusted application loaded it.

Understand the loader.

Understand the search path.

Understand the process.

Understand the privileges.

And always investigate the complete chain.

Think Like an Attacker. Investigate Like a Defender. Secure Like a Pro.


Discover more from Spyboy blog

Subscribe to get the latest posts sent to your email.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.