Overview
The allocator::section policy allocates memory for syscall stubs using NtCreateSection with the SEC_NO_CHANGE flag. This creates an immutable memory region that cannot be modified after initial mapping, providing strong protection against runtime patching.
Method Signatures
Allocates an immutable section for syscall stubs static bool allocate (
size_t uRegionSize ,
const std :: span < const uint8_t > vecBuffer ,
void*& pOutRegion ,
HANDLE & unused
)
Size of the region to allocate in bytes
vecBuffer
const std::span<const uint8_t>
required
Buffer containing the syscall stubs to copy into the section
Output parameter receiving the base address of the executable mapping
Unused for this policy (section handle is closed before return)
Returns true on successful allocation, false on failure
Releases the section mapping static void release ( void* pRegion , HANDLE /*hHeapHandle*/ )
Base address of the region to unmap
Implementation Details
The allocation process involves multiple steps:
Create a section object with SEC_NO_CHANGE | SEC_COMMIT attributes
Map the section with PAGE_READWRITE permissions
Copy the syscall stubs into the writable mapping
Unmap the writable view
Remap the section with PAGE_EXECUTE_READ permissions
Close the section handle
The SEC_NO_CHANGE flag is the key security feature—it prevents any further modifications to the section, even from kernel mode.
Source Code
From syscall.hpp:115-165:
struct section
{
static bool allocate ( size_t uRegionSize , const std :: span < const uint8_t > vecBuffer ,
void*& pOutRegion , HANDLE & /*unused*/ )
{
HMODULE hNtDll = native :: getModuleBase ( hashing :: calculateHash ( "ntdll.dll" ));
auto fNtCreateSection = reinterpret_cast < native :: NtCreateSection_t > (
native :: getExportAddress (hNtDll, SYSCALL_ID ( "NtCreateSection" )));
auto fNtMapView = reinterpret_cast < native :: NtMapViewOfSection_t > (
native :: getExportAddress (hNtDll, SYSCALL_ID ( "NtMapViewOfSection" )));
auto fNtUnmapView = reinterpret_cast < native :: NtUnmapViewOfSection_t > (
native :: getExportAddress (hNtDll, SYSCALL_ID ( "NtUnmapViewOfSection" )));
auto fNtClose = reinterpret_cast < native :: NtClose_t > (
native :: getExportAddress (hNtDll, SYSCALL_ID ( "NtClose" )));
if ( ! fNtCreateSection || ! fNtMapView || ! fNtUnmapView || ! fNtClose)
return false ;
HANDLE hSectionHandle = nullptr ;
LARGE_INTEGER sectionSize;
sectionSize . QuadPart = uRegionSize;
NTSTATUS status = fNtCreateSection (
& hSectionHandle, SECTION_ALL_ACCESS, nullptr , & sectionSize,
PAGE_EXECUTE_READWRITE,
SEC_COMMIT | static_cast < ULONG > (SECTION_NO_CHANGE),
nullptr
);
if ( ! NT_SUCCESS (status))
return false ;
// Map as writable, copy data, remap as executable
void * pTempView = nullptr ;
SIZE_T uViewSize = uRegionSize;
status = fNtMapView (hSectionHandle, native :: getCurrentProcess (),
& pTempView, 0 , 0 , nullptr , & uViewSize,
VIEW_SHARE, 0 , PAGE_READWRITE);
if ( ! NT_SUCCESS (status)) {
fNtClose (hSectionHandle);
return false ;
}
std :: copy_n ( vecBuffer . data (), uRegionSize, static_cast < uint8_t *> (pTempView));
fNtUnmapView ( native :: getCurrentProcess (), pTempView);
uViewSize = uRegionSize;
status = fNtMapView (hSectionHandle, native :: getCurrentProcess (),
& pOutRegion, 0 , 0 , nullptr , & uViewSize,
VIEW_SHARE, 0 , PAGE_EXECUTE_READ);
fNtClose (hSectionHandle);
return NT_SUCCESS (status) && pOutRegion;
}
static void release ( void* pRegion , HANDLE /*hHeapHandle*/ )
{
if (pRegion) {
HMODULE hNtDll = native :: getModuleBase ( hashing :: calculateHash ( "ntdll.dll" ));
auto fNtUnmapView = reinterpret_cast < native :: NtUnmapViewOfSection_t > (
native :: getExportAddress (hNtDll, SYSCALL_ID ( "NtUnmapViewOfSection" )));
if (fNtUnmapView)
fNtUnmapView ( native :: getCurrentProcess (), pRegion);
}
}
};
Usage Example
#include <syscalls-cpp/syscall.hpp>
// Use the pre-defined type alias
SyscallSectionDirect syscallManager;
if ( ! syscallManager . initialize ()) {
std ::cerr << "Failed to initialize with section allocator \n " ;
return 1 ;
}
// Or compose manually
using CustomManager = syscall ::Manager <
syscall :: policies :: allocator ::section,
syscall :: policies :: generator ::direct
> ;
CustomManager manager;
manager . initialize ();
Security Properties
Immutability Once mapped as executable, the section cannot be modified—not even by kernel-mode code. This prevents runtime patching of syscall stubs.
Protection Demo Attempts to patch syscalls in SEC_NO_CHANGE sections fail, as demonstrated in the library’s protection demo.
Trade-offs
Aspect Description Security Highest—immutable after mapping Performance Slightly slower allocation (multiple map operations) Complexity Most complex allocation process Compatibility Requires Windows NT 6.0+
See Also
allocator::heap Heap-based allocation alternative
allocator::memory Virtual memory allocation alternative
Policy Composition Learn how to combine policies