NtTraceEvent
Schreibt ein User-Mode-Event über ein registriertes Trace-Handle in eine ETW-Sitzung.
Prototyp
NTSTATUS NtTraceEvent( HANDLE TraceHandle, ULONG Flags, ULONG FieldSize, PVOID Fields );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| TraceHandle | HANDLE | in | Trace-/Registrierungs-Handle, von EtwRegister (oder kernelseitigem EtwRegister) erhalten. |
| Flags | ULONG | in | Event-Flags. ETW_NT_FLAGS_TRACE_HEADER (0x00400000) markiert Fields als komplettes EVENT_HEADER. |
| FieldSize | ULONG | in | Gesamtgröße in Bytes des von Fields adressierten Puffers. |
| Fields | PVOID | in | Zeiger auf einen EVENT_HEADER, gefolgt von EVENT_DATA_DESCRIPTOR für die Event-Nutzlast. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x5E | win10-1507 |
| Win10 1607 | 0x5E | win10-1607 |
| Win10 1703 | 0x5E | win10-1703 |
| Win10 1709 | 0x5E | win10-1709 |
| Win10 1803 | 0x5E | win10-1803 |
| Win10 1809 | 0x5E | win10-1809 |
| Win10 1903 | 0x5E | win10-1903 |
| Win10 1909 | 0x5E | win10-1909 |
| Win10 2004 | 0x5E | win10-2004 |
| Win10 20H2 | 0x5E | win10-20h2 |
| Win10 21H1 | 0x5E | win10-21h1 |
| Win10 21H2 | 0x5E | win10-21h2 |
| Win10 22H2 | 0x5E | win10-22h2 |
| Win11 21H2 | 0x5E | win11-21h2 |
| Win11 22H2 | 0x5E | win11-22h2 |
| Win11 23H2 | 0x5E | win11-23h2 |
| Win11 24H2 | 0x5E | win11-24h2 |
| Server 2016 | 0x5E | winserver-2016 |
| Server 2019 | 0x5E | winserver-2019 |
| Server 2022 | 0x5E | winserver-2022 |
| Server 2025 | 0x5E | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 5E 00 00 00 mov eax, 0x5E F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Undokumentierte Hinweise
Der Kernel-Einstiegspunkt hinter jedem User-Mode-ETW-*Write*. `EventWrite`, `EventWriteEx`, `EventWriteTransfer`, `EtwEventWrite` und die automatisch generierten TraceLogging-Emitter münden alle in `ntdll!EtwEventWriteFull` → `NtTraceEvent`. Das TraceHandle ist *kein* Sitzungs-Handle — es ist das pro Provider von `EtwRegister` zurückgegebene Registrierungs-Handle, und der Kernel läuft die Enable-Mask des Providers durch, um zu entscheiden, welche Sitzungen das Event empfangen. Seine SSN ist von Windows 10 1507 bis Windows 11 24H2 und Server 2025 `0x5E` geblieben — eine der stabilsten Syscall-Nummern im System, vermutlich weil sie auf dem Hot-Path jeder Microsoft-Telemetrie liegt.
Häufige Malware-Nutzung
Direkter offensiver Wert begrenzt — der Aufruf schreibt Events, die Verteidiger *sehen können*. Interessant ist die Umkehrung: Implants, die einen privaten Logging-Kanal wollen, registrieren absichtlich eine Provider-GUID, die niemand sammelt, und rufen `NtTraceEvent`, um Runtime-Debug in eine Sitzung zu kritzeln, die kein SOC abonniert. Manche Loader emittieren so auch Pseudo-`Microsoft-Windows-*`-Events zur Verdünnung von Hunt-Queries. Weit mehr Aufmerksamkeit gilt der *Unterdrückung* von Writes (siehe `NtTraceControl`) als dem direkten Missbrauch dieses Aufrufs. Einige EDR-Evasion-Notizen erwähnen das Überschreiben von `EtwEventWrite` mit `ret` in ntdll, was die User-Mode-Seite genau dieses Pfads zusammenbrechen lässt.
Erkennungsmöglichkeiten
Für sich allein ist `NtTraceEvent` reines Rauschen — jede Office-App, jeder Browser-Tab, jeder Windows-Dienst feuert Tausende pro Sekunde. Entscheidend ist die *Abwesenheit* erwarteter Events aus einem Prozess, dessen ntdll gepatcht wurde (z. B. erstes Byte von `EtwEventWrite` = `0xC3`). Vergleichen Sie In-Memory-ntdll-Bytes gegen die Disk-Version für die vier klassischen ETW-Write-Stubs (`EtwEventWrite`, `EtwEventWriteFull`, `EtwEventWriteEx`, `EtwEventWriteTransfer`); jede Abweichung ist hochrelevant. Auf Sitzungsebene sind Log-Lücken bei den Providern `Microsoft-Windows-Threat-Intelligence` und `Microsoft-Windows-Kernel-Process`, korreliert zu Prozesserzeugungen, das klassische Indiz für einen ETW-Bypass.
Direkte Syscall-Beispiele
cTraceLogging write via EventWriteTransfer
// Standard TraceLogging path — ultimately calls NtTraceEvent.
#include <windows.h>
#include <evntprov.h>
static const GUID kImplantProvider =
{ 0x11111111, 0x2222, 0x3333, { 0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB } };
REGHANDLE hReg = 0;
EventRegister(&kImplantProvider, NULL, NULL, &hReg);
EVENT_DESCRIPTOR ed = { 0 };
ed.Id = 1; ed.Level = 4; // Information
EVENT_DATA_DESCRIPTOR edd;
const wchar_t* msg = L"beacon-checkin";
EventDataDescCreate(&edd, msg, (ULONG)((wcslen(msg) + 1) * sizeof(wchar_t)));
// Funnels through ntdll!EtwEventWriteFull -> NtTraceEvent.
EventWriteTransfer(hReg, &ed, NULL, NULL, 1, &edd);asmx64 direct stub (SSN 0x5E, stable across all builds)
NtTraceEvent PROC
mov r10, rcx
mov eax, 5Eh
syscall
ret
NtTraceEvent ENDPrustStealth provider with windows-sys
// Cargo: windows-sys = { version = "0.59", features = ["Win32_System_Diagnostics_Etw"] }
use windows_sys::Win32::System::Diagnostics::Etw::*;
use windows_sys::core::GUID;
const PROVIDER: GUID = GUID::from_u128(0x11111111_2222_3333_4455_66778899AABB);
unsafe fn beacon_log(msg: &[u8]) {
let mut hreg: u64 = 0;
EventRegister(&PROVIDER, None, std::ptr::null_mut(), &mut hreg);
let ed = EVENT_DESCRIPTOR { Id: 1, Level: 4, ..core::mem::zeroed() };
let mut edd = EVENT_DATA_DESCRIPTOR { Ptr: msg.as_ptr() as u64, Size: msg.len() as u32, Reserved: 0 };
EventWrite(hreg, &ed, 1, &mut edd);
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20