> Windows Syscalls
ntoskrnl.exeT1106T1553

NtCompareSigningLevels

Compare deux valeurs SE_SIGNING_LEVEL selon l'ordre de policy Code Integrity et indique si la première domine la seconde.

Prototype

NTSTATUS NtCompareSigningLevels(
  SE_SIGNING_LEVEL FirstSigningLevel,
  SE_SIGNING_LEVEL SecondSigningLevel
);

Arguments

NameTypeDirDescription
FirstSigningLevelSE_SIGNING_LEVELinPremier niveau de signature à comparer (0 Unchecked, 4 Authenticode, 6 Store, 8 Antimalware, 12 Microsoft, 14 Windows).
SecondSigningLevelSE_SIGNING_LEVELinSecond niveau de signature à comparer au premier.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 17030x98win10-1703
Win10 17090x99win10-1709
Win10 18030x9Awin10-1803
Win10 18090x9Awin10-1809
Win10 19030x9Awin10-1903
Win10 19090x9Awin10-1909
Win10 20040x9Cwin10-2004
Win10 20H20x9Cwin10-20h2
Win10 21H10x9Cwin10-21h1
Win10 21H20x9Cwin10-21h2
Win10 22H20x9Cwin10-22h2
Win11 21H20x9Ewin11-21h2
Win11 22H20x9Ewin11-22h2
Win11 23H20x9Ewin11-23h2
Win11 24H20xA0win11-24h2
Server 20190x9Awinserver-2019
Server 20220x9Ewinserver-2022
Server 20250xA0winserver-2025

Module noyau

ntoskrnl.exeNtCompareSigningLevels

APIs liées

NtGetCachedSigningLevelNtSetCachedSigningLevelWldpQueryDynamicCodeTrustCiCompareSigningLevels

Stub du syscall

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

Notes non documentées

Un helper de comparaison pure exposé comme syscall purement pour que la policy d'ordre de Code Integrity vive en *un* seul endroit — le noyau — plutôt que d'être ré-implémentée dans chaque composant user-mode qui en a besoin. Renvoie `STATUS_SUCCESS` (0) quand `FirstSigningLevel` est supérieur ou égal à `SecondSigningLevel` dans le treillis CI, et `STATUS_NOT_FOUND` (0xC0000225) sinon. Important : l'ordre n'est *pas* numérique : bien que les constantes soient par hasard monotones (`0 < 4 < 6 < 8 < 12 < 14`), le noyau passe par `CiCompareSigningLevels` dans `ci.dll`, qui applique des équivalences définies par policy (par exemple `SE_SIGNING_LEVEL_STORE` et `SE_SIGNING_LEVEL_ANTIMALWARE` peuvent être traités comme équivalents sous certains drapeaux de policy WHQL). D'où le syscall — pour centraliser cette policy. Introduit dans Windows 10 1703 avec le reste de la surface API Code Integrity moderne ; non présent sur Windows 10 1507 / 1607.

Usage courant par les malwares

Valeur offensive quasi nulle. C'est une fonction *pure* (sans effet de bord, sans privilège, sans accès à des ressources) qui prend deux entiers et renvoie un status — il n'y a rien à abuser. La seule raison réelle pour qu'un attaquant l'appelle est la bookkeeping : les loaders red-team ayant construit une primitive CIG-bypass peuvent l'appeler pour revérifier que le niveau qu'ils ont forgé domine le niveau requis par la cible, avant de s'engager dans l'injection. Sinon aucune famille de malware n'est documentée comme l'utilisant, et les EDR l'ignorent.

Opportunités de détection

Pas un point de détection significatif. La fonction n'a aucun effet de bord observable, l'ETW ne logge pas d'évènement par appel pour elle, et le volume issu de l'auto-usage légitime de `ci.dll` est suffisamment élevé pour que le hunt basé ratio soit impraticable. L'effort de détection est mieux dépensé sur ses *appelants* — toute personne appelant `NtCompareSigningLevels` depuis l'extérieur de `ci.dll`, `wldp.dll`, `lsass.exe` et une poignée de composants Defender est inhabituel mais pas nécessairement malicieux. Avec de la télémétrie syscall user-mode, joindre les appels `NtCompareSigningLevels` avec les appels adjacents `NtSetCachedSigningLevel` / `NtGetCachedSigningLevel` depuis le même thread est un signal bien plus fort que cet appel isolé.

Exemples de syscalls directs

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) == FALSE

asmx64 direct stub (Win11 24H2 / Server 2025, SSN 0xA0)

NtCompareSigningLevels PROC
    mov  r10, rcx
    mov  eax, 0A0h
    syscall
    ret
NtCompareSigningLevels ENDP

Mappings MITRE ATT&CK

Last verified: 2026-05-20