NtCompareSigningLevels
Vergleicht zwei SE_SIGNING_LEVEL-Werte gemäß der Code-Integrity-Policy-Ordnung und liefert, ob der erste den zweiten dominiert.
Prototyp
NTSTATUS NtCompareSigningLevels( SE_SIGNING_LEVEL FirstSigningLevel, SE_SIGNING_LEVEL SecondSigningLevel );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| FirstSigningLevel | SE_SIGNING_LEVEL | in | Erstes zu vergleichendes Signaturlevel (0 Unchecked, 4 Authenticode, 6 Store, 8 Antimalware, 12 Microsoft, 14 Windows). |
| SecondSigningLevel | SE_SIGNING_LEVEL | in | Zweites Signaturlevel, das mit dem ersten verglichen wird. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1703 | 0x98 | win10-1703 |
| Win10 1709 | 0x99 | win10-1709 |
| Win10 1803 | 0x9A | win10-1803 |
| Win10 1809 | 0x9A | win10-1809 |
| Win10 1903 | 0x9A | win10-1903 |
| Win10 1909 | 0x9A | win10-1909 |
| Win10 2004 | 0x9C | win10-2004 |
| Win10 20H2 | 0x9C | win10-20h2 |
| Win10 21H1 | 0x9C | win10-21h1 |
| Win10 21H2 | 0x9C | win10-21h2 |
| Win10 22H2 | 0x9C | win10-22h2 |
| Win11 21H2 | 0x9E | win11-21h2 |
| Win11 22H2 | 0x9E | win11-22h2 |
| Win11 23H2 | 0x9E | win11-23h2 |
| Win11 24H2 | 0xA0 | win11-24h2 |
| Server 2019 | 0x9A | winserver-2019 |
| Server 2022 | 0x9E | winserver-2022 |
| Server 2025 | 0xA0 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 A0 00 00 00 mov eax, 0xA0 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
Ein reiner Vergleichs-Helper, der nur deshalb als Syscall exponiert ist, damit die Ordnungs-Policy von Code Integrity an *einem* Ort lebt — dem Kernel — statt in jedem User-Mode-Komponenten neu implementiert zu werden. Liefert `STATUS_SUCCESS` (0), wenn `FirstSigningLevel` im CI-Verband größer oder gleich `SecondSigningLevel` ist, sonst `STATUS_NOT_FOUND` (0xC0000225). Wichtig: die Ordnung ist *nicht* numerisch: obwohl die Konstanten zufällig monoton sind (`0 < 4 < 6 < 8 < 12 < 14`), läuft der Kernel über `CiCompareSigningLevels` in `ci.dll`, das policy-definierte Äquivalenzen anwendet (zum Beispiel können `SE_SIGNING_LEVEL_STORE` und `SE_SIGNING_LEVEL_ANTIMALWARE` unter bestimmten WHQL-Policy-Flags als äquivalent gelten). Daher der Syscall — um diese Policy zu zentralisieren. Eingeführt in Windows 10 1703 zusammen mit dem Rest der modernen Code-Integrity-API-Oberfläche; nicht vorhanden auf Windows 10 1507 / 1607.
Häufige Malware-Nutzung
Nahezu null offensiver Wert. Es ist eine *reine* Funktion (keine Seiteneffekte, keine Privilegien, kein Ressourcenzugriff), die zwei Integer nimmt und einen Status liefert — es gibt nichts zu missbrauchen. Der einzige reale Grund, warum ein Angreifer sie aufruft, ist Buchhaltung: Red-Team-Loader, die eine CIG-Bypass-Primitive gebaut haben, rufen sie vor dem Commit zur Injection auf, um sicherzustellen, dass das gefälschte Level das vom Ziel geforderte dominiert. Sonst ist keine Malware-Familie als Nutzerin dokumentiert, und EDRs ignorieren ihn.
Erkennungsmöglichkeiten
Kein sinnvoller Detection-Punkt. Die Funktion hat keinen beobachtbaren Seiteneffekt, ETW loggt keine Per-Call-Events, und das Volumen aus legitimer `ci.dll`-Selbstnutzung ist so hoch, dass ratio-basiertes Hunting unpraktisch ist. Detection-Aufwand ist besser bei den *Aufrufern* angelegt — jeder Aufruf von `NtCompareSigningLevels` außerhalb von `ci.dll`, `wldp.dll`, `lsass.exe` und einer Handvoll Defender-Komponenten ist ungewöhnlich, aber nicht zwangsläufig bösartig. Mit User-Mode-Syscall-Telemetrie ist das Verknüpfen von `NtCompareSigningLevels`-Aufrufen mit benachbarten `NtSetCachedSigningLevel`- / `NtGetCachedSigningLevel`-Aufrufen aus demselben Thread ein wesentlich stärkeres Signal als dieser Aufruf isoliert.
Direkte Syscall-Beispiele
cDoes the cached level satisfy the target's CIG requirement?
// Used internally by ci.dll and by some EDRs to short-circuit policy decisions.
// Returns STATUS_SUCCESS if `have` dominates `need`, STATUS_NOT_FOUND otherwise.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI* pNtCompareSigningLevels)(UCHAR, UCHAR);
BOOL satisfies(UCHAR have, UCHAR need) {
pNtCompareSigningLevels f = (pNtCompareSigningLevels)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtCompareSigningLevels");
return NT_SUCCESS(f(have, need));
}
// Example: do we meet ProcessSignaturePolicy.MicrosoftSignedOnly = 1?
// satisfies(SE_SIGNING_LEVEL_MICROSOFT, SE_SIGNING_LEVEL_MICROSOFT) == TRUE
// satisfies(SE_SIGNING_LEVEL_AUTHENTICODE, SE_SIGNING_LEVEL_MICROSOFT) == FALSEasmx64 direct stub (Win11 24H2 / Server 2025, SSN 0xA0)
NtCompareSigningLevels PROC
mov r10, rcx
mov eax, 0A0h
syscall
ret
NtCompareSigningLevels ENDPMITRE ATT&CK-Mappings
Last verified: 2026-05-20