Skeleton Code to Create PoC DLL
In this page, you can find skeleton code that can be used to generate a DLL that creates a file in user’s temp directory. It can be compiled in Visual Studio. The generated DLL can be used as proof of concept. For example, if you want to test DLL hijacking, DLL side-loading, reflective DLL injection and similar techniques.
In this page:
DLL skeleton code
The code listed below can be compiled with Microsoft Visual Studio to generate a DLL. As soon as the DLL is loaded, it creates an empty file in user’s temp directory.
#include <windows.h>
#include <stdio.h>
INT TestFunction(WCHAR* fname)
{
// create a logfile in user's temp
// this file will be used as proof of execution
WCHAR* lpBuffer = new WCHAR[MAX_PATH];
lpBuffer[MAX_PATH - 1] = '\0';
DWORD len = ::GetTempPathW(MAX_PATH, lpBuffer);
if (!len)
{
WCHAR msgbuf[50];
swprintf_s(msgbuf, 50, L"[-] GetTempPathW has failed: %d", GetLastError());
::OutputDebugString(msgbuf);
return 1;
}
size_t numberofelements = wcslen(lpBuffer) + wcslen(fname) + 1;
WCHAR* logfilepath = new WCHAR[numberofelements];
wcscpy_s(logfilepath, numberofelements, lpBuffer);
wcscat_s(logfilepath, numberofelements, fname);
HANDLE hFile = ::CreateFileW(
logfilepath,
GENERIC_ALL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
WCHAR msgbuf[50];
swprintf_s(msgbuf, 50, L"[-] CreateFileW has failed: %d", GetLastError());
::OutputDebugString(msgbuf);
return 1;
}
::CloseHandle(hFile);
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
WCHAR fname[] = L"filetest.tmp";
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
TestFunction(fname);
break;
case DLL_THREAD_ATTACH:
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
break;
}
return 1;
}
In general, you can execute a DLL using rundll32.exe on a Windows system:
rundll32.exe <DLL_name>,<exported_function_name>
To view the exported functions, dumpbin.exe - a tool that is part of Visual Studio - can be used:
dumpbin.exe /EXPORTS <name of the dll>
We can also call the exported function using the ordinal name. In this case, the ordinal of the exported function is 1 and thus the call would be:
rundll32.exe calc.dll,#1
Build and use your own DLL launcher
When you execute the DLL with rundll32.exe, you are not able to view any output messages. For example, if you are using printf() in the DLL there is no output. We can deal with this by building our own launcher. The code listed below once compiled, creates an executable that gets as input a DLL, loads it and executes it.
#include <windows.h>
#include <stdio.h>
#include <iostream>
int main(int argc, char** argv)
{
printf("[+] Loading DLL...\n");
CHAR* dllname = argv[1];
HMODULE hLibrary = LoadLibraryA(dllname);
if (hLibrary == NULL)
{
printf("[-] LoadLibraryA has failed: %d\n", GetLastError());
return 1;
}
printf("[+] Handle of the loaded DLL: 0x%p\n", hLibrary);
FARPROC gpa = GetProcAddress(hLibrary, MAKEINTRESOURCEA(1));
if (gpa)
{
printf("[+] Module Address: 0x%p\n", gpa);
}
else
{
printf("[-] Last Error: %d\n", GetLastError());
return 1;
}
if (FreeLibrary(hLibrary))
{
printf("[+] Library has been unloaded successfuly!\n");
}
return 0;
}
Tools used
The tools used for this post are:
- Visual Studio
- CFF Explorer
- rundll32.exe
- dumpbin.exe