Map file to process memory utilizing NtCreateSection and NtMapViewOfSection
In order to bypass Endpoint Detection and Response (EDR) as well as Anti-Virus (AV) software that hook Windows APIs on the user-mode level, a technique commonly utilized is to go a level deeper and make system calls (syscalls) directly. This post is an attempt to document some of the steps required to dynamically resolve system calls from ntdll.dll.
Act 1
The following code maps a file - that exists on the system - into the memory of the calling process. The file is mapped in a shareable memory section utilizing NtCreateSection and NtMapViewOfSection Windows APIs. That means that any process that maps this memory region into its address space will get access to this memory region.
#include <windows.h>
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT, *PSECTION_INHERIT;
typedef NTSTATUS (*fnNtCreateSection)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE);
typedef NTSTATUS (*fnNtMapViewOfSection)(HANDLE, HANDLE, PVOID*, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, ULONG, ULONG);
INT ModuleMapper(CHAR* modpath)
{
OFSTRUCT fstruct = { 0 };
HFILE hFile = ::OpenFile(modpath, &fstruct, OF_READ);
if (hFile == 0)
{
::wprintf(L"[-] OpenFile has failed: %d\n", ::GetLastError());
return 0;
}
DWORD FileSize = ::GetFileSize((HANDLE)hFile, NULL);
if (FileSize == 0)
{
::wprintf(L"[-] GetFileSize has failed: %x\n", FileSize);
return 0;
}
HMODULE hModule = GetModuleHandleWrapper(modpath);
fnNtCreateSection NtCreateSection = (fnNtCreateSection)GetProcAddress(hModule, "NtCreateSection");
if (hModule == NULL)
{
::wprintf(L"[-] GetProcAddress for NtCreateSection has failed\n");
return 0;
}
HANDLE SectionHandle = 0;
LARGE_INTEGER MaxSize = { 0, 0 };
MaxSize.LowPart = FileSize;
NTSTATUS CreateSectionStatus = NtCreateSection(&SectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, &MaxSize, PAGE_READWRITE, SEC_COMMIT, NULL);
if (CreateSectionStatus != 0)
{
::wprintf(L"[-] NtCreateSection has failed: %x\n", CreateSectionStatus);
return 0;
}
fnNtMapViewOfSection NtMapViewOfSection = (fnNtMapViewOfSection)GetProcAddress(hModule, "NtMapViewOfSection");
if (hModule == NULL)
{
::wprintf(L"[-] GetProcAddress for NtMapViewOfSection has failed\n");
return 0;
}
PVOID Address = NULL;
SIZE_T SectionSize = 0;
NTSTATUS MapViewOfSectionStatus = NtMapViewOfSection(
SectionHandle,
GetCurrentProcess(),
&Address,
NULL,
NULL,
NULL,
&SectionSize,
ViewUnmap,
NULL,
PAGE_READWRITE
);
if (MapViewOfSectionStatus != 0)
{
::wprintf(L"[-] NtMapViewOfSection has failed: %x\n", MapViewOfSectionStatus);
return 0;
}
// copy file to the allocated shared memory
BOOL ReadStatus = ::ReadFile((HANDLE)hFile, Address, FileSize, NULL, NULL);
if (ReadStatus == FALSE) {
::wprintf(L"[-] ReadFile has failed: %d\n", ::GetLastError());
return 0;
}
return 1;
}
tags: #Windows API