GBHackers

SindriKit 1.3.0 Abuses Call Stack Spoofing to Bypass EDR Detection


SindriKit 1.3.0 introduces a significant advancement in evading Endpoint Detection and Response (EDR) systems by exploiting dynamic call stack spoofing. This method defeats telemetry that inspects kernel-transition call chains, going beyond just user-mode hooks.

Previously, SindriKit 1.2.0 had already separated syscall invocations via indirect syscalls, redirecting to legitimate syscall return instructions in ntdll.dll to evade traditional user-mode API hooking.

However, modern EDR engines now combine Event Tracing for Windows (ETW) with thread suspension to analyze the call stack and verify return addresses against expected module layouts.

Even when the instruction pointer originates from a trusted NTDLL gadget, the return address on the stack usually points back to unverified payload memory, creating a noticeable anomaly for virtual unwinders like RtlVirtualUnwind.

SindriKit 1.3.0 Abuses Call Stack Spoofing

According to Sibouzitoun, SindriKit 1.3.0 closes this gap by adding native call stack spoofing through a C‑based engine, snd_syscall_find_spoof_scan, that parses the Exception Directory (.pdata) of kernel32.dll and inspects RUNTIME_FUNCTION and UNWIND_INFO structures to calculate exact stack allocations for every function.

The engine then hunts for “Fat Frames” – legitimate functions that allocate at least 120 bytes of stack space – providing sufficient shadow space for syscall arguments and a trampoline gadget without corrupting adjacent frames or desynchronizing the unwinder.

To avoid deterministic telemetry, SindriKit applies entropy and randomization using an SSN hash, a static counter, and ASLR‑dependent base addresses to skip valid Fat Frames at random, ensuring the spoofed call stack shifts across executions.

A concise view of the technique can be captured in a data table that analysts may embed alongside reporting:

ElementRole in spoofing
Fat Frame (≥120 bytes)Provides shadow stack space for args and trampoline
Trampoline Gadget (RET)Legitimate RET inside Fat Frame, first return target
SyscallCleanup addressTrue payload return point hidden in spoofed frame
Original caller return addrBaseline anchor for EDR’s reconstructed call chain

Within each syscall, SindriKit’s MASM stub builds a JMP‑Trampoline that satisfies both the physical CPU and the EDR’s virtual unwinder, arranging the stack as follows. This logic can be presented to readers in a compact, article‑friendly code block:

; Top-of-stack spoofing layout
mov [rsp+0], r8 ; Trampoline Gadget (RET in Fat Frame)
lea rax, SyscallCleanup
mov [rsp+8], rax ; True return address (payload cleanup)
mov rax, [rbp+16] ; Original caller return address
mov [rsp+r12+8], rax ; r12 = spoof_frame_size

When the syscall gadget returns, the CPU first lands in the Trampoline Gadget, which immediately executes RET and transfers control to SyscallCleanup inside the payload.

At the same time, RtlVirtualUnwind consults .pdata, adds the Fat Frame size to its virtual stack pointer, and reads the original caller’s return address at [RSP + 8 + spoof_frame_size], reconstructing a clean, legitimate call chain.

On x64 this dynamic approach fully decouples resolution, invocation, and spoofing; on x86, where .pdata is absent and SEH chains and EBP frames dominate, SindriKit falls back to known functions like BaseThreadInitThunk and nearby RET gadgets as a pragmatic, hardcoded compromise.

Interact with Cyber Threats in Windows, Linux, macOS VMs to Trigger Full Attack Chain - Analyse Malware & Phishing with ANY RUN



Source link