22 August 2025

DLL injection is a programming technique that allows code, contained within a Dynamic Link Library (DLL), to be loaded and executed inside the address space of another process. This means the injected DLL can run with the same permissions and context as the target application.
placing code into another process often referred as process injection can be used for both good and bad, the difference lies in why it's being done and who is doing it.
On the legitimate side, many antivirus programs, security tools, and monitoring tools rely on code injection techniques to keep your system safe. For example, a security product might inject a small piece of code into every running application so it can watch what each program is doing in real time. This allows it to intercept important actions — a practice known as hooking such as when a program tries to create a new process, access sensitive data, or read/write a file, so the security tool can inspect and monitor that activity.
The reason they inject into each process instead of just a single DLL like ntdll.dll is because malicious behavior doesn’t always go through one predictable path. If they only hooked NTDLL, attackers could bypass detection by:
By injecting into each process, the security tool gains:
Take file access as an example. In normal use, a word processor like Microsoft Word mainly reads and writes document files. If security software detects that Word is suddenly trying to access system password files or make changes to the Windows registry, that’s unusual behavior. It could indicate that a malicious macro or exploit is running inside the program. In this situation, the injected monitoring code acts like a silent security guard, positioned inside the application to watch every move and stop anything suspicious before it causes harm.
Of course, the very same mechanism can be abused by attackers. Malicious actors can inject their own code into trusted programs to hide their activity, steal data, or execute harmful commands often without being detected. This dual nature is why DLL injection is considered both a powerful development tool and a potential security threat.
On Windows, user-mode processes are isolated from one another each process has its own private memory space that other processes normally can’t access. This isolation is a core security feature, preventing programs from tampering with each other’s memory directly.
Every process executes code through threads, and a process needs at least one running thread to do anything.
When you want to inject code or a DLL into another process, the problem is twofold:
The simplest and most common method uses Windows API functions:
This sequence is the classic approach to process injection. There are more advanced methods (like APC injection, thread hijacking, or reflective DLL loading), but this one is the most straightforward and widely used. in our example in github we will use undocumented functions to avoid detection.
In this step, you can inject shellcode or a DLL, but in our example, we will create a DLL that will be loaded into the target process. First, to create a custom DLL, read the official Windows documentation.
In our example, the DLL code simply shows a message box with different messages depending on the callback.
in our example in GitHub, we used undocumented function. first we need to create function that dynamically load GetModuleHandle. this will allow us to use this function without showing in the Import Address Table (IAT). also some EDR hooks kernel32.dll Dynamic loading allows you to get the function pointer from ntdll.dll directly, or even resolve syscalls, bypassing those hooks. the function does the following:
If no match is found, it returns NULL.
after getting the GetModuleHandle, which allow us to get handler for a module, we need a function that take a module handler, and function name. and parse the PE header of the module and search for the function we want and return the address of the function.
Check PE headers → Make sure the DLL at hModule is valid (MZ DOS header + PE NT header)
.Find Export Directory → Use the PE header’s data directory to locate where the list of exported functions is stored
.Read Export Tables:
Search for the target function name.Return its absolute address (base address + RVA).
after all that, in the main function we need the target PID, and the path of the DLL that we be injected in the target process. the main function does the following:
Check input arguments
The program expects exactly 2 arguments:
Parse inputs
Open target process handle
Allocate memory in target process
Write DLL path to allocated memory
Get address of LoadLibraryA
Create remote thread
Cleanup and finish
let's test the code and targeting notepad.exe

if everything is fine, first callback should be triggered in the dll which is DLL_PROCESS_ATTACH, and it simply will show message like the following

and let's try to trigger the DLL_THREAD_ATTACH, this callback will run when process spawn a new thread, so let's open a new tab in notepad that should trigger this event

You got the idea every action we make, the DLL will show a message. You can change the DLL code to make it run any code you want, or you can run shellcode instead of the DLL.
There are many ways to perform DLL injection. For example, instead of using LoadLibrary, we can manually map the DLL into the target process’s memory this method is called reflective DLL injection. Another method is using LoadLibrary combined with QueueUserAPC, which injects a DLL without creating new threads in the target process.
Windows also provides some built-in methods for DLL injection that are used for various legitimate purposes. One simple way is through specific registry keys:
On 64-bit systems, there are separate registry keys for 32-bit applications:
By adding a DLL filename to the AppInit_DLLs value, that DLL will automatically be loaded into every process that loads User32.dll — which includes most Windows applications. This only works if the LoadAppInit_DLLs value is set to 0x00000001.
DLL injection can be achieved through various techniques depending on the use case and level of stealth required. While common methods like using LoadLibrary or reflective DLL injection are widely used, there are also advanced approaches such as unhooking direct syscalls, indirect syscalls, API hashing, and others that offer greater evasion from detection and hooking by security software.