What is a DLL?

DLLs are shared libraries of executable functions or data that can be used by multiple applications simultaneously. DLL files cannot execute code on their own.

// dllmain.cpp : Defines the entry point for the DLL application.
#include <Windows.h>

// Exported Function
extern "C" __declspec(dllexport) void HelloWorld() {
    MessageBoxA(NULL, "Hello, World!", "DLL Message", MB_ICONINFORMATION);
}
// extern for C... extern "C" for C++
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

Dynamic Linking

It’s possible to use the LoadLibrary, GetModuleHandle & GetProcAddress WinAPIs to import a function from a DLL. This is referred as Dynamic Linking. This is a method of loading and linking code (DLLs) at runtime rather than linking them at compile time using the linker and import address table.

Loading The DLL

Let’s create a loader.

Step 1 - Loading a DLL

#include <Windows.h>

int main() {

	// Load the DLL
	HMODULE hModule = LoadLibraryA("C:\\\\Users\\\\coe_c\\\\OneDrive\\\\Desktop\\\\Malware_Development\\\\Visual_Studio\\\\DLL\\\\x64\\\\Release\\\\DLL.dll");

	return 0;
}

Step 2 - Retrieving a DLL’s Handle

#include <Windows.h>

int main() {

	// Attempt to get the handle of the DLL that's already in memory

	HMODULE hModule = GetModuleHandleA("DLL.dll");

	if (hModule == NULL) {
		// Load the DLL if it's not in the memory.
		HMODULE hModule = LoadLibraryA("C:\\\\Users\\\\coe_c\\\\OneDrive\\\\Desktop\\\\Malware_Development\\\\Visual_Studio\\\\DLL\\\\x64\\\\Release\\\\DLL.dll");
	}

	return 0;
}

Step 3 - Retrieving a Function’s Address

Once the DLL is loaded into memory and the handle is retrieved, the next step is to retrieve the function’s address using GetProcAddress WinAPI, which takes the handle of the DLL that exports the function and the function name.

#include <Windows.h>
#include <stdio.h>

int main() {

	// Attempt to get the handle of the DLL that's already in memory

	HMODULE hModule = GetModuleHandleA("DLL.dll");

	if (hModule == NULL) {
		// Load the DLL if it's not in the memory.
		HMODULE hModule = LoadLibraryA("C:\\\\Users\\\\coe_c\\\\OneDrive\\\\Desktop\\\\Malware_Development\\\\Visual_Studio\\\\DLL\\\\x64\\\\Release\\\\DLL.dll");
	}

	PVOID pHelloWorld = GetProcAddress(hModule,"HelloWorld");
	printf("Address of HelloWorld: %p\\n", pHelloWorld);

	getchar();
	return 0;
}

Step 4 - Type-casting the function’s address

Now, we need to type-cast on this address to HelloWorld’s function pointer.

#include <Windows.h>
#include <stdio.h>

int main() {

	typedef void (WINAPI* HelloWorldFunctionPointer)();

	// Attempt to get the handle of the DLL that's already in memory

	HMODULE hModule = GetModuleHandleA("DLL.dll");

	if (hModule == NULL) {
		// Load the DLL if it's not in the memory.
		HMODULE hModule = LoadLibraryA("DLL.dll");
	}

	PVOID pHelloWorld = GetProcAddress(hModule,"HelloWorld");

	HelloWorldFunctionPointer HelloWorld = (HelloWorldFunctionPointer)pHelloWorld;
	printf("Address of HelloWorld: %p\\n", pHelloWorld);

	getchar();
	return 0;
}

Step 5 - Invoking HelloWorld

#include <Windows.h>
#include <stdio.h>

void call() {
	typedef void (WINAPI* HelloWorldFunctionPointer)();

	// Attempt to get the handle of the DLL that's already in memory

	HMODULE hModule = GetModuleHandleA("DLL.dll");

	if (hModule == NULL) {
		// Load the DLL if it's not in the memory.
		HMODULE hModule = LoadLibraryA("DLL.dll");
	}

	PVOID pHelloWorld = GetProcAddress(hModule, "HelloWorld");

	HelloWorldFunctionPointer HelloWorld = (HelloWorldFunctionPointer)pHelloWorld;
	printf("Address of HelloWorld: %p\\n", pHelloWorld);

	HelloWorld();
}

int main() {

	call();
	getchar();
	return 0;
}

Function Pointers