> Windows Syscalls
ntoskrnl.exeT1553T1574T1106

NtSetCachedSigningLevel

Schreibt ein von Code Integrity gecachetes Signaturlevel-Ergebnis in ein NTFS-Extended-Attribute der Zieldatei.

Prototyp

NTSTATUS NtSetCachedSigningLevel(
  ULONG              Flags,
  SE_SIGNING_LEVEL   InputSigningLevel,
  PHANDLE            SourceFiles,
  ULONG              SourceFileCount,
  HANDLE             TargetFile
);

Argumente

NameTypeDirDescription
FlagsULONGinBitmaske zur Cache-Steuerung; 0x4 erzwingt Neubewertung, 0x8 überspringt die Vertrauensprüfung.
InputSigningLevelSE_SIGNING_LEVELinAngefordertes Signaturlevel zum Stempeln: 0=Unchecked, 4=Authenticode, 6=Store, 8=Antimalware, 12=Microsoft, 14=Windows.
SourceFilesPHANDLEinArray von Datei-Handles, deren gecachetes Signaturlevel geerbt werden soll; meist NULL.
SourceFileCountULONGinAnzahl der Einträge in SourceFiles; 0, wenn SourceFiles NULL ist.
TargetFileHANDLEinHandle auf die Datei, deren Extended-Attribute $Kernel.Purge.ESBCache geschrieben wird.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x16Ewin10-1507
Win10 16070x176win10-1607
Win10 17030x17Cwin10-1703
Win10 17090x17Fwin10-1709
Win10 18030x181win10-1803
Win10 18090x182win10-1809
Win10 19030x183win10-1903
Win10 19090x183win10-1909
Win10 20040x189win10-2004
Win10 20H20x189win10-20h2
Win10 21H10x189win10-21h1
Win10 21H20x18Bwin10-21h2
Win10 22H20x18Bwin10-22h2
Win11 21H20x193win11-21h2
Win11 22H20x196win11-22h2
Win11 23H20x196win11-23h2
Win11 24H20x198win11-24h2
Server 20160x176winserver-2016
Server 20190x182winserver-2019
Server 20220x191winserver-2022
Server 20250x198winserver-2025

Kernel-Modul

ntoskrnl.exeNtSetCachedSigningLevel

Verwandte APIs

NtGetCachedSigningLevelWldpQueryDynamicCodeTrustSetProcessMitigationPolicy (ProcessSignaturePolicy)GetProcessMitigationPolicy

Syscall-Stub

4C 8B D1            mov r10, rcx
B8 98 01 00 00      mov eax, 0x198
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

Teil der **Code-Integrity (CI)**-Infrastruktur, eingeführt mit Windows 10. CI hält ein EA-gecachtes Signaturverdikt auf jeder ausführbaren Datei, damit nachfolgende Image-Loads den teuren Authenticode-Hash-Walk vermeiden. Der Cache lebt im NTFS-Extended-Attribute `$Kernel.Purge.ESBCache` (das EA ist versteckt — `fsutil file queryea` zeigt es standardmäßig nicht; CI nutzt ein privates FSCTL). `NtSetCachedSigningLevel` ist der *Writer* — er bittet CI (CI-Modul aus `ci.dll` innerhalb von ntoskrnl), ein Signaturlevel zu berechnen oder zu akzeptieren und ins EA zu stempeln. Das Pendant `NtGetCachedSigningLevel` ist der *Reader*. Die privilegierten Levels (8 Antimalware, 12 Microsoft, 14 Windows) erfordern `SeTcbPrivilege` *und* dass der aufrufende Prozess selbst auf gleichem oder höherem CI-Level läuft — ein normaler User-Mode-Prozess kann also nicht einfach `SE_SIGNING_LEVEL_WINDOWS` stempeln. Der Aufruf wurde für Forscher attraktiv, weil *ein Teil* seiner Parameter-Validierung in der CI-Policy lebt, nicht in `Nt*` selbst, und historische Policy-Resolution-Bugs genutzt wurden, um CI zur Annahme unsignierter Dateien zu zwingen.

Häufige Malware-Nutzung

Kein Commodity-Malware-Syscall, aber ein **wiederkehrender Forschungsvektor für Sandbox-Escapes und CIG-(Code-Integrity-Guard)-Bypasses**. James Forshaw (Project Zero) dokumentierte mehrere Pfade, auf denen `NtSetCachedSigningLevel` dazu gezwungen werden konnte, eine angreiferkontrollierte DLL mit einem Cache-Eintrag auf `Microsoft`-Level zu stempeln — ausreichend, um die DLL an einem Prozess vorbeizuschmuggeln, der mit `ProcessSignaturePolicy = MicrosoftSignedOnly` geschützt ist. Edge-/Chrome-Sandbox-Escape-PoCs (Ära CVE-2020-0938 und Folgen) nutzten dies, um nach RCE im Renderer Angreifercode in den Browser-Broker zu laden. Die Print-Spooler-/`Win32k`-Bugklassen, die App Container kreuzen, berühren ebenfalls diesen Pfad. **Echte Malware ruft dies praktisch nie auf** — Missbrauch erscheint in Red-Team-/Research-Code, **PPLFault** (Gabriel Landau, 2022) und Process-Mitigation-Policy-Bypasses. Sieht man einen nicht-Microsoft-signierten Prozess, der `NtSetCachedSigningLevel(SE_SIGNING_LEVEL_WINDOWS)` aufruft, beobachtet man Exploitation, kein normales Verhalten.

Erkennungs­möglichkeiten

Der ETW-Provider `Microsoft-Windows-CodeIntegrity` (GUID `{4ee76bd8-3cf4-44a0-a0ac-3937643e37a3}`) emittiert Event 3023 / 3033 bei Cache-Schreibvorgängen, inklusive angefordertem Signaturlevel und Image-Pfad des aufrufenden Prozesses. CI loggt zudem in den Application-&-Services-Kanal `CodeIntegrity-Operational` — Events 3033 (Datei blockiert) und 3089 (Signaturinfo) referenzieren Cache-Lookups. Das stärkste Signal: jeder Prozess, dessen eigenes Image nicht auf `SE_SIGNING_LEVEL_MICROSOFT` oder höher signiert ist, ruft `NtSetCachedSigningLevel` überhaupt — und besonders mit `InputSigningLevel >= 8`. Die Defender-ASR-Regel `Block credential stealing from the Windows local security authority subsystem` erwischt indirekt einige Missbrauchspfade, weil der Post-Exploitation-Schritt meist in einen geschützten Prozess injiziert.

Direkte Syscall-Beispiele

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtSetCachedSigningLevel (SSN 0x198 on Win11 24H2 / Server 2025)
NtSetCachedSigningLevel PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 198h         ; SSN — drifts; resolve dynamically for portability
    syscall
    ret
NtSetCachedSigningLevel ENDP

cCIG-bypass research pattern

// Forshaw-style CI cache stamping. Requires the calling process to already
// run at SE_SIGNING_LEVEL_MICROSOFT or above — the abuse vector is *getting
// that level* via a policy resolution bug, not this call itself.
#define SE_SIGNING_LEVEL_UNCHECKED   0
#define SE_SIGNING_LEVEL_AUTHENTICODE 4
#define SE_SIGNING_LEVEL_STORE       6
#define SE_SIGNING_LEVEL_ANTIMALWARE 8
#define SE_SIGNING_LEVEL_MICROSOFT   12
#define SE_SIGNING_LEVEL_WINDOWS     14

HANDLE hFile = /* opened with FILE_READ_DATA | FILE_WRITE_EA */;
NTSTATUS st = NtSetCachedSigningLevel(
    /* Flags */              0x4,           // force recompute
    /* InputSigningLevel */  SE_SIGNING_LEVEL_MICROSOFT,
    /* SourceFiles */        NULL,
    /* SourceFileCount */    0,
    /* TargetFile */         hFile);

cRead the resulting EA with NtGetCachedSigningLevel

// Verify the cache stamp succeeded by reading it back.
ULONG  flags = 0, level = 0, thumbAlg = 0, thumbSize = 32;
BYTE   thumb[32];
LARGE_INTEGER lastBlackList = { 0 }, lastTimeStamp = { 0 };
NTSTATUS st = NtGetCachedSigningLevel(
    hFile, &flags, (PSE_SIGNING_LEVEL)&level,
    thumb, &thumbSize, &thumbAlg,
    &lastBlackList, &lastTimeStamp);
// level should now equal what NtSetCachedSigningLevel stamped, e.g. 12 (Microsoft).

MITRE ATT&CK-Mappings

Last verified: 2026-05-20