Kernel forensicsHighPublished

Detecting ETW provider tampering patch, disable, and spoof

Event Tracing for Windows is a primary telemetry channel for anti-cheat systems, EDR products, and post-incident forensics. Cheat loaders that silence it — by patching EtwEventWrite, disabling providers via NtTraceControl, or re-routing session buffers — cannot erase the structural metadata left in kernel-managed ETW tables. We document four tamper techniques observed in the wild and the detection signals each one leaves behind.

CR
Clubhouse AC Research
March 5, 2026 11 min read Defensive use only

Summary

  • Four ETW tampering techniques catalogued; each leaves kernel-side structural evidence that survives even when the event stream is silenced.
  • 94.7% detection rate across 283 tampered sessions in our corpus with 0.9% false-positive rate on clean game sessions.
  • Detection path does not rely on reading the event stream — it reads ETW metadata structures from kernel memory, making it resilient to all four tamper classes.

Background

Event Tracing for Windows (ETW) is the kernel-level logging and tracing infrastructure that underpins Windows diagnostic telemetry, security event logging, and — increasingly — anti-cheat and EDR product telemetry. It was designed primarily for performance and reliability, not adversarial resilience. The design assumption is that the consumer of trace data (the controller session) and the producer (the instrumented process) trust each other.

In the cheat ecosystem, that trust is absent. Since 2020 we have observed progressively more sophisticated ETW tampering — moving from blunt EtwEventWrite patches in loaded DLLs to kernel-mode provider disablement that targets specific provider GUIDs used by anti-cheat products. The goal in each case is the same: prevent the anti-cheat from receiving image-load, memory-allocation, and process-creation events that would signal cheat activity.

The key insight of our detection approach is that ETW tampering attacks the data path — the flow of event records from provider to consumer — without modifying the metadata path: the kernel's registration tables, session descriptors, and provider-enable bitmask arrays. These structures persist in non-paged pool and are readable from a kernel-mode scanner independently of the event stream.

ETW architecture

The ETW subsystem maintains its state in a set of kernel data structures rooted at the EtwpRegistrationTable hash table and the global EtwpActiveLoggers array (both unexported; located via pattern scan or PDB-assisted offset). Key structures:

  • _ETW_REG_ENTRY — one per registered provider. Fields include ProviderId (GUID), EnableInfo array (one entry per logger that has enabled this provider), RegIndex, and Callback (the provider's enable callback address).
  • _ETW_LOGGER_CONTEXT — one per active trace session. Contains LoggerId, BufferSize, LogFileName, BuffersWritten, and the per-provider FilterDesc list.
  • The EtwpHostSiloState structure (Windows 10 1903+) manages per-silo provider isolation. In the host silo, it points to the canonical registration table used for kernel and usermode providers alike.

Provider registrations from usermode go through EtwRegisterClassicProvider (legacy) or EtwEventRegister (manifest-based), both of which ultimately call NtTraceEvent to create the kernel-side _ETW_REG_ENTRY. The entry persists in the hash table for the lifetime of the registration handle.

Tampering techniques

We catalogued four distinct ETW tampering classes in our corpus of 283 cheat loader samples (November 2024 – February 2026):

T1

EtwEventWrite inline patch

52% of tampered corpus

The simplest technique: overwrite the first bytes of ntdll!EtwEventWrite in the target process with a RET instruction (0xC3). All provider calls from that process return immediately without queuing an event. Detected by: comparing the in-memory bytes of EtwEventWrite in the target process against the on-disk ntdll image. Also leaves a tell-tale VAD entry with PAGE_EXECUTE_READWRITE on a region that should be PAGE_EXECUTE_READ.

T2

Provider GUID disable via NtTraceControl

28% of tampered corpus

Calls NtTraceControl(EtwpDisableProviderRequest, ...) from kernel mode (via BYOVD or an exploit) to disable specific provider GUIDs — typically Microsoft-Windows-Threat-Intelligence (which supplies image-load and process-creation events to anti-cheat). Detected by: reading the EnableInfo array in the target _ETW_REG_ENTRY and comparing the EnableBitmap against expected values for the active logger set.

T3

Logger session buffer hijack

14% of tampered corpus

Redirects the buffer pointer in a target _ETW_LOGGER_CONTEXT to a kernel-mode buffer the attacker controls, then never flushes it. The logger continues operating (BuffersWritten increments) but events accumulate in unreachable memory. Detected by: comparing the buffer pointer against the expected pool allocation range and validating the buffer header signature (0x42554645 'BUFE').

T4

Callback pointer replacement

6% of tampered corpus

Replaces the Callback field in _ETW_REG_ENTRY with a trampoline that silently drops enable/disable notifications. The provider's EnableInfo remains stale — it believes it is still enabled by the anti-cheat session but silently drops all events. Detected by: walking the callback chain and verifying each address falls within a known, signed module's executable range.

Detection signals

Each tampering class leaves one or more of the following kernel-side signals. The signals are readable from a kernel-mode scanner without relying on the event stream that is being silenced:

  • EtwEventWrite byte-pattern check — compare first 16 bytes of ntdll!EtwEventWrite in the target process address space against the image on disk. A RET prefix (0xC3) or jmp to a non-ntdll address is a direct T1 indicator.
  • EnableBitmap consistency — for each active logger session L, provider P should have a bit set in P.EnableInfo[L].EnableBitmap if L has subscribed to P. A zero bitmap for a provider that L nominally subscribes to is a T2 indicator.
  • Buffer pointer validation — walk each _ETW_LOGGER_CONTEXT.BufferListHead and verify each buffer's pool header and the magic 0x42554645 signature. A buffer pointer outside the session pool allocation range is a T3 indicator.
  • Callback address integrity — resolve each _ETW_REG_ENTRY.Callback to a module. An unmapped or unsigned-module address is a T4 indicator.

Detection rule

rules/etw_tampering.rulePseudocode
rule ETW_Tamper_Detection
{
  meta:
    severity    = "high"
    category    = "kernel"
    confidence  = 0.92

  inputs:
    for each process in running_processes():
      ntdll_ondisk  := read_file(process.ntdll_path, "EtwEventWrite", 16)
      ntdll_inmem   := read_process_mem(process, "EtwEventWrite", 16)

    reg_table  := walk_etw_registration_table()
    loggers    := walk_etw_active_loggers()

  match:
    // T1: EtwEventWrite patched to RET or JMP-elsewhere
    any proc where
      ntdll_inmem[proc].bytes != ntdll_ondisk.bytes
      or ntdll_inmem[proc][0] == 0xC3   // bare RET

    // T2: EnableBitmap zeroed for a provider a logger should own
    or any (logger, provider) in (loggers x reg_table) where
      logger subscribes_to provider.guid
      and provider.enable_info[logger.id].enable_bitmap == 0

    // T3: Buffer pointer outside pool allocation
    or any buf in flatten(loggers.buffer_lists) where
      buf.magic != 0x42554645
      or not in_pool_range(buf.address)

    // T4: Callback in unsigned / unmapped memory
    or any entry in reg_table where
      entry.callback != null
      and not is_signed_module(entry.callback)

  emit:
    artifact {
      process       = proc.name,
      tamper_type   = matched_class,    // T1 / T2 / T3 / T4
      provider_guid = provider.guid,
      logger_id     = logger.id,
      detail        = tamper_detail
    }
}

Validation

283

Tampered ETW sessions in corpus

94.7%

Detection rate across all tamper classes

0.9%

False-positive rate on clean game corpus

4

Tamper techniques covered

The 5.3% non-detection cases were exclusively T2 events where the attacker had re-enabled the provider between the tamper event and the scan — a temporal gap our per-scan cadence does not close. Continuous monitoring (rather than snapshot scans) would catch these; we are evaluating a kernel-mode ETW self-instrumentation approach for a future release.

False positives on the clean corpus were all legitimate software that explicitly suppresses ETW for performance reasons (a database engine that patches EtwEventWrite on startup, and a video encoder that calls NtTraceControl to disable latency-sensitive providers). Both are suppressible by path and signing allowlist.

Limitations

  • The detection structs (_ETW_REG_ENTRY, _ETW_LOGGER_CONTEXT) are undocumented and their offsets change between major Windows versions. The scanner maintains a version-keyed offset table updated on each Windows release; an unknown OS version falls back to pattern-scan discovery.
  • A T2 tamper that re-enables the provider before the next scan will not be caught by a snapshot-based scanner. The only reliable answer to this is a short-cadence monitoring loop, which we do not currently ship due to performance constraints.
  • Hypervisor-based tampering that intercepts the VMREAD/VMWRITE path for kernel memory is out of scope for this detection note. That threat model requires hypervisor attestation techniques (VBS/HVCI).

Defensive material

Kernel structure offsets and pattern-scan signatures for the undocumented ETW tables are withheld from this note. The detection rule ships in the Clubhouse AC scanner in compiled form. Vendors seeking the offset tables can reach the team at security@clubhouseac.shop.