Skip to main content

Overview

Once the System Service Number (SSN) is resolved, SysWhispers4 needs to actually invoke the syscall. The invocation method determines how the syscall instruction is executed and where the instruction pointer (RIP) appears to be during the call. Different invocation methods offer tradeoffs between:
  • Stealth - Avoiding detection by EDR/AV call stack analysis
  • Simplicity - Code complexity and maintainability
  • Performance - Execution overhead
  • Flexibility - Runtime adaptability
Use the --method flag to select an invocation method.

Method Comparison

Recommended: Use embedded for simplicity, indirect for better stealth, or randomized for maximum call stack evasion.

Embedded (Default)

Description

The embedded method (also called direct syscall) places the syscall instruction directly in your generated stub code. This is the most straightforward approach.

How It Works

  1. Generated assembly includes the syscall instruction
  2. When you call SW4_NtAllocateVirtualMemory(), execution flows:
    • Load SSN into EAX
    • Move arguments into registers
    • Execute syscall instruction in your stub
    • Kernel handles the syscall
    • Return to your code

Usage

This is the default if you don’t specify --method.

Generated Code (x64)

Call Stack

When EDR inspects the call stack during the syscall:

Advantages

Simplest implementation - Just execute the instruction
No runtime initialization - No need to call SW4Initialize()
Fastest - No indirection overhead
No ntdll dependency - Doesn’t need to find gadgets in ntdll

Disadvantages

Obvious to EDR - RIP is in your module during syscall, not ntdll
Easy to detect - Stack trace shows non-ntdll address
Signature-prone - Syscall instruction in your binary is suspicious

When to Use

  • You need maximum performance
  • You’re not concerned about call stack analysis
  • You want the simplest implementation
  • You’re testing or prototyping

Detection Risk

EDRs can detect direct syscalls by:
  1. Call stack analysis - RIP not in ntdll during syscall
  2. Binary scanning - syscall instruction found in non-ntdll module
  3. Behavioral analysis - Non-ntdll code calling kernel

Indirect

Description

The indirect method jumps to a syscall; ret gadget inside ntdll.dll. This makes the instruction pointer (RIP) appear to be in ntdll during the syscall, mimicking normal behavior.

How It Works

  1. At initialization (SW4Initialize()), scan ntdll.dll for a syscall; ret gadget (opcodes: 0F 05 C3)
  2. Store the address of this gadget
  3. When calling a syscall:
    • Load SSN into EAX
    • Move arguments into registers
    • Jump to the gadget in ntdll
    • ntdll executes syscall; ret
    • Return to your code

Usage

Generated Code (x64)

Call Stack

When EDR inspects the call stack during the syscall:

Advantages

Better stealth - RIP appears in ntdll, mimicking normal calls
Evades basic call stack checks - Looks like normal ntdll behavior
No syscall instruction in your binary - Harder to detect via scanning
Still fast - Single indirect jump

Disadvantages

⚠️ Requires initialization - Must call SW4Initialize() to find gadget
⚠️ Scanning ntdll - Finding the gadget may trigger EDR heuristics
⚠️ Predictable RIP - Always the same gadget address (can be fingerprinted)

When to Use

  • You need better stealth than embedded
  • You’re okay with runtime initialization
  • You want a good balance of stealth and performance
  • Recommended for most red team engagements

Finding the Gadget


Randomized

Description

The randomized method is an enhancement of indirect that uses a different random syscall gadget for each call. This prevents EDRs from fingerprinting your syscalls by gadget address.

How It Works

  1. At initialization (SW4Initialize()), scan ntdll.dll and collect multiple syscall; ret gadgets
  2. Store all gadget addresses in an array
  3. When calling a syscall:
    • Load SSN into EAX
    • Move arguments into registers
    • Select a random gadget from the array
    • Jump to the random gadget
    • Return to your code

Usage

Generated Code (x64)

Call Stack

When EDR inspects the call stack during the syscall:

Advantages

✅✅ Maximum call stack evasion - RIP location varies, hard to fingerprint
Anti-profiling - EDR can’t build a consistent signature
Still appears in ntdll - Maintains the illusion of normal behavior
Harder to detect - No consistent pattern

Disadvantages

⚠️ More complex - Needs gadget management and random selection
⚠️ Slightly slower - Additional function call to get random gadget
⚠️ More initialization overhead - Must collect multiple gadgets

When to Use

  • You need maximum stealth
  • You’re evading advanced EDR with call stack profiling
  • You want to prevent signature-based detection
  • Recommended for stealth configurations

Example Configuration

Gadget Collection


Egg

Description

The egg method embeds an 8-byte “egg” marker (e.g., 0x4141414141414141) in place of the syscall instruction at generation time. At runtime, your code searches for these eggs and patches them with the actual syscall instruction.

How It Works

  1. Generated stubs contain an egg marker instead of syscall:
  2. At runtime, call SW4HatchEggs():
    • Scan your module’s .text section for egg markers
    • Replace each egg with 0x0F05C3 (syscall; ret; nop; nop; nop…)
    • Change memory protection as needed
  3. After hatching, syscalls work like embedded method

Usage

Generated Code (x64)

Runtime Initialization

Advantages

✅✅ No static syscall instruction - Binary doesn’t contain 0x0F05 at rest
Evades static scanning - AV/EDR can’t find syscall bytes in your binary
Dynamic patching - Syscalls only “appear” at runtime
Good for obfuscation - Combined with other techniques, very stealthy

Disadvantages

Complex initialization - Must scan and patch memory
Memory protection changes - VirtualProtect() may trigger EDR
Slower startup - Scanning and patching takes time
RIP still in your module - Same call stack detection risk as embedded

When to Use

  • You need to evade static binary analysis
  • You’re combining with other obfuscation techniques
  • You’re willing to trade initialization complexity for static stealth
  • Your threat model includes AV signature scanning

Egg Hatching Implementation

Custom Egg Marker

You can customize the egg marker in generated code to avoid signature detection:

Combining Invocation and Resolution

Compatibility Matrix

All combinations are supported! Choose based on your requirements. General Use:
Better Stealth:
Maximum Stealth:
Evade Static Analysis:

Performance Comparison

Benchmark (1000 syscalls)

*Egg method has a one-time patching overhead (~200ms) but then performs like embedded.

Detection Evasion Summary

Call Stack Analysis

Binary Scanning


Choosing the Right Method

Decision Tree

Quick Recommendations


Example Configurations

Development/Testing

Production Red Team

Maximum Evasion

Evade AV Scanning

See Also