Skip to main content

Overview

Call Stack Spoofing is a technique that manipulates the visible call stack to make syscalls appear to originate from legitimate Windows code (e.g., ntdll.dll), defeating EDR stack-walking heuristics. By replacing the real return address with a synthetic pointer into ntdll before executing a syscall, we hide the fact that execution came from suspicious code.
Target audience: Advanced users familiar with x64 calling conventions, stack frames, and return address chains.

The Problem: Stack Walking EDRs

How EDRs Analyze Call Stacks

Modern EDRs inspect the call stack when suspicious operations occur:
EDR heuristic: If the return address points into:
  • Non-module memory (shellcode)
  • Unbacked memory regions (reflectively loaded DLLs)
  • Executable heaps (JIT code)
  • Known malicious modules
Alert/Block the operation

Stack-Walking APIs

EDRs use these techniques to walk the stack:
  1. RtlCaptureStackBackTrace (Windows API)
  2. Manual RBP chain walking (read [rbp], [rbp+8], etc.)
  3. Exception context analysis (CONTEXT.Rsp, unwind info)
  4. ETW stack traces (kernel-mode Microsoft-Windows-Threat-Intelligence)

How Stack Spoofing Works

Core Idea

Replace the return address on the stack with a pointer into a legitimate module (ntdll.dll) before the syscall:
When EDR walks the stack, it sees:
Result: Stack appears to originate from ntdll, not suspicious code.

Implementation Approaches

Use a small assembly trampoline that swaps return addresses:

Approach 2: Inline Stack Manipulation

Manually manipulate the stack in C with inline assembly:

Approach 3: Gadget-Based (Advanced)

Find ROP gadgets in ntdll to perform the swap:
Flow:
  1. Push spoof address
  2. Push real return address
  3. Use gadgets to rearrange stack
  4. Jump to target

Choosing a Spoof Address

Requirements

  1. Inside ntdll.dll: Must be a legitimate module (EDR whitelist)
  2. Executable: Must point to valid code (prevents AVs)
  3. Innocuous context: Avoid suspicious functions like RtlUserThreadStart (common in thread injection)

Good Candidates

Finding Spoof Addresses Dynamically

Full Implementation

MASM Assembly (x64)

C Wrapper

Usage

Enable Stack Spoofing in Generation

Integration Example

Advantages

Defeats Stack Walking

EDR stack traces show legitimate ntdll → ntdll call chains

Low Overhead

Minimal performance cost (few extra instructions per call)

Transparent

Drop-in replacement for regular syscalls

Flexible

Can randomize spoof addresses per call for diversity

Limitations

1. Deep Stack Inspection

Sophisticated EDRs may walk beyond the first frame:
Mitigation: Stack spoofing only hides the immediate caller. For full obfuscation, use multi-layer spoofing (replace multiple frames).

2. Return Address Validation

Some EDRs validate that return addresses point to valid CALL sites:
Mitigation: Use return address gadgets:

3. Kernel-Mode ETW

ETW-Ti (Threat Intelligence) stack traces are captured in the kernel before user-mode spoofing occurs. No user-mode technique can hide from ETW-Ti.

4. Complexity

Stack manipulation is error-prone:
  • Wrong offsets → crashes
  • Misaligned stacks → access violations
  • Calling convention mismatches → corrupted arguments

Detection Vectors

Observable Behaviors

  1. Stack anomalies: Return addresses that don’t match CALL sites
  2. Performance: Extra stack operations may be visible via timing
  3. Memory patterns: Trampoline code in .text section

EDR Telemetry

Mitigation Strategies

1

Use CALL-site gadgets

Ensure spoof addresses are valid return sites:
2

Randomize spoof addresses

Different address per call:
3

Combine with indirect invocation

Keep RIP inside ntdll during syscall:

Comparison with Alternatives

Further Reading

WithSecure Research

Original call stack spoofing research

Indirect Invocation

Combine with indirect syscalls for layered evasion

RecycledGate

SSN resolution technique for maximum hook resistance

Sleep Encryption

Complement with memory obfuscation during idle