> Windows Syscalls
ntoskrnl.exeT1106T1087

NtAccessCheck

Effectue un contrôle d'accès d'un descripteur de sécurité contre un token d'impersonation, retournant le masque d'accès accordé.

Prototype

NTSTATUS NtAccessCheck(
  PSECURITY_DESCRIPTOR SecurityDescriptor,
  HANDLE               ClientToken,
  ACCESS_MASK          DesiredAccess,
  PGENERIC_MAPPING     GenericMapping,
  PPRIVILEGE_SET       PrivilegeSet,
  PULONG               PrivilegeSetLength,
  PACCESS_MASK         GrantedAccess,
  PNTSTATUS            AccessStatus
);

Arguments

NameTypeDirDescription
SecurityDescriptorPSECURITY_DESCRIPTORinDescripteur de sécurité auto-relatif de la ressource protégée à évaluer.
ClientTokenHANDLEinHandle vers un token d'impersonation (TOKEN_QUERY) — doit être un token d'impersonation, pas un token primaire.
DesiredAccessACCESS_MASKinDroits d'accès demandés par l'appelant (peut inclure des droits génériques — résolus via GenericMapping).
GenericMappingPGENERIC_MAPPINGinMappage spécifique au type d'objet, de GENERIC_READ/WRITE/EXECUTE/ALL vers les bits d'accès concrets.
PrivilegeSetPPRIVILEGE_SEToutReçoit les privilèges effectivement utilisés par le noyau pendant le contrôle (ex. SeSecurityPrivilege pour lire la SACL).
PrivilegeSetLengthPULONGin/outEn entrée : taille en octets du buffer PrivilegeSet. En sortie : taille réellement nécessaire.
GrantedAccessPACCESS_MASKoutReçoit le masque d'accès qui serait effectivement accordé à ClientToken.
AccessStatusPNTSTATUSoutReçoit STATUS_SUCCESS si l'accès serait accordé, STATUS_ACCESS_DENIED sinon. Distinct du NTSTATUS de la fonction elle-même.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070x0win10-1507
Win10 16070x0win10-1607
Win10 17030x0win10-1703
Win10 17090x0win10-1709
Win10 18030x0win10-1803
Win10 18090x0win10-1809
Win10 19030x0win10-1903
Win10 19090x0win10-1909
Win10 20040x0win10-2004
Win10 20H20x0win10-20h2
Win10 21H10x0win10-21h1
Win10 21H20x0win10-21h2
Win10 22H20x0win10-22h2
Win11 21H20x0win11-21h2
Win11 22H20x0win11-22h2
Win11 23H20x0win11-23h2
Win11 24H20x0win11-24h2
Server 20160x0winserver-2016
Server 20190x0winserver-2019
Server 20220x0winserver-2022
Server 20250x0winserver-2025

Module noyau

ntoskrnl.exeNtAccessCheck

APIs liées

AccessCheckAccessCheckByTypeAccessCheckAndAuditAlarmWNtAccessCheckByTypeNtAccessCheckAndAuditAlarmNtPrivilegeCheck

Stub du syscall

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

NtAccessCheck occupe littéralement le premier slot de la SSDT — SSN `0x0` sur toutes les builds Windows depuis NT 4 — ce qui en fait une curiosité amusante mais inutile comme primitive offensive. C'est le point d'entrée user-mode de la logique de contrôle d'accès *manuel* : un service qui vient d'impersonner un client utilise NtAccessCheck (typiquement via le wrapper Win32 AccessCheck) pour décider si le client *serait* autorisé à effectuer une opération sur une ressource contrôlée par le service. Elle n'ouvre rien — c'est une fonction d'évaluation pure sur SECURITY_DESCRIPTOR + token + GENERIC_MAPPING.

Usage courant par les malwares

Presque jamais utilisée directement à des fins offensives. Deux schémas apparaissent : (1) des outils post-exploitation énumérant quels objets DACL'és un token d'impersonation volé pourrait atteindre sans les ouvrir réellement (reconnaissance silencieuse — aucun audit ne se déclenche sauf si des SACL sont configurées) ; (2) du code d'exploit qui sonde si un token forgé ou rejoué accorde bien l'accès souhaité. Évaluation honnête : NtAccessCheck est dominée par l'usage légitime et reste un signal faible de malveillance.

Opportunités de détection

Très peu de télémétrie utile existe. NtAccessCheck ne déclenche pas elle-même l'audit d'accès aux objets (Event ID 4663) — seul l'ouverture qui suit le fait. Les événements de privilege-use d'ETW Microsoft-Windows-Security-Auditing peuvent se déclencher si l'évaluation référence un objet porteur de SACL, mais la couverture est inégale. Utile comme signal de *corrélation* : un processus inhabituel qui enchaîne de nombreux NtAccessCheck sur des descripteurs variés puis n'ouvre sélectivement (NtOpen*) que ceux qui ont réussi est un schéma classique de reconnaissance silencieuse.

Exemples de syscalls directs

asmx64 direct stub (SSN 0x0 — first in the SSDT)

; Direct syscall stub for NtAccessCheck (SSN 0x00 on every Windows build)
NtAccessCheck PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 0            ; SSN
    syscall
    ret
NtAccessCheck ENDP

cService-style: impersonate client and probe access

// After ImpersonateNamedPipeClient / RpcImpersonateClient, the service evaluates
// whether the caller would be allowed FILE_WRITE_DATA on a private resource.
HANDLE hClientToken = NULL;
NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, FALSE, &hClientToken);

GENERIC_MAPPING fileMapping = {
    .GenericRead    = FILE_GENERIC_READ,
    .GenericWrite   = FILE_GENERIC_WRITE,
    .GenericExecute = FILE_GENERIC_EXECUTE,
    .GenericAll     = FILE_ALL_ACCESS,
};

BYTE privBuf[256];
ULONG privLen = sizeof(privBuf);
ACCESS_MASK granted = 0;
NTSTATUS accessStatus = 0;

NtAccessCheck(pResourceSD,
              hClientToken,
              FILE_WRITE_DATA,
              &fileMapping,
              (PPRIVILEGE_SET)privBuf,
              &privLen,
              &granted,
              &accessStatus);

if (NT_SUCCESS(accessStatus) && (granted & FILE_WRITE_DATA)) {
    // proceed under impersonation
}

rustwindows-sys + naked syscall stub

// Cargo: windows-sys = "0.59"  (Win32_Security)
use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_access_check_stub() {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x00",
        "syscall",
        "ret",
        options(noreturn),
    );
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20