Skip to main content

Overview

Havoc implements indirect syscalls to evade user-mode hooks placed by EDRs and security products. Instead of calling syscall instructions directly from hooked NTDLL functions, Havoc extracts the syscall instruction address from a clean function and invokes it indirectly.
Indirect syscalls bypass user-mode hooks by avoiding hooked function prologues while still using legitimate syscall instructions from NTDLL.

How It Works

Syscall Extraction

During initialization, Havoc extracts two critical pieces of information from NTDLL:
  1. System Service Number (SSN): The syscall number for each NT function
  2. Syscall Instruction Address: Location of a clean syscall instruction
Source: payloads/Demon/src/core/Syscalls.c:12

SSN Extraction Process

The SysExtract function parses NTDLL function stubs to extract SSNs: Source: payloads/Demon/src/core/Syscalls.c:90

Hook Detection & Evasion

If a function is hooked, Havoc uses neighboring syscalls to calculate the correct SSN: Source: payloads/Demon/src/core/Syscalls.c:201
This technique assumes syscall numbers are incremental. On older Windows versions or with significant NTDLL modifications, this may fail.

Assembly Implementation

The actual syscall invocation is performed in assembly: Source: payloads/Demon/src/asm/Syscall.x64.asm

Execution Flow

  1. Configuration: SysSetConfig stores the syscall configuration (SSN + instruction address)
  2. Invocation: SysInvoke loads the SSN and jumps to the clean syscall instruction
  3. Execution: The CPU executes the syscall using the correct SSN
  4. Return: Execution returns to Havoc code

Supported Syscalls

Havoc extracts SSNs for the following NT functions during initialization: Source: payloads/Demon/src/core/Syscalls.c:43

EDR Evasion Benefits

Bypasses User-Mode Hooks

EDRs typically hook NTDLL functions by modifying the first few bytes:
Havoc’s indirect syscalls skip the hooked prologue entirely.

Kernel Callback Visibility

While indirect syscalls bypass user-mode hooks, they do NOT evade kernel-mode callbacks. EDRs using kernel drivers can still detect these syscalls via:
  • PsSetCreateProcessNotifyRoutine
  • PsSetCreateThreadNotifyRoutine
  • ObRegisterCallbacks
  • Kernel ETW providers

OPSEC Considerations

  1. Memory Scanning: The syscall configuration stored in memory may be detected
  2. Call Stack Analysis: Stack traces will show unusual call patterns
  3. Telemetry: Kernel callbacks still fire for all operations
  4. Thread Context: Some EDRs inspect thread start addresses and call stacks
  • Token Management - Uses indirect syscalls for token operations
  • .NET Execution - Combines with AMSI bypass
  • Stack spoofing for return address manipulation

References

  • Syscall extraction: payloads/Demon/src/core/Syscalls.c
  • Assembly stubs: payloads/Demon/src/asm/Syscall.x64.asm
  • Configuration: payloads/Demon/include/core/Syscalls.h