> Windows Syscalls
ntoskrnl.exeT1106T1087

NtAccessCheck

Realiza un chequeo de acceso de un descriptor de seguridad contra un token de impersonación, devolviendo la máscara de acceso concedida.

Prototipo

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

Argumentos

NameTypeDirDescription
SecurityDescriptorPSECURITY_DESCRIPTORinDescriptor de seguridad auto-relativo del recurso protegido a evaluar.
ClientTokenHANDLEinHandle a un token de impersonación (TOKEN_QUERY) — debe ser un token de impersonación, no un token primario.
DesiredAccessACCESS_MASKinDerechos de acceso solicitados (puede incluir derechos genéricos — se resuelven con GenericMapping).
GenericMappingPGENERIC_MAPPINGinMapeo específico del tipo de objeto, de GENERIC_READ/WRITE/EXECUTE/ALL a los bits de acceso concretos.
PrivilegeSetPPRIVILEGE_SEToutRecibe los privilegios que el kernel usó realmente durante el chequeo (p. ej. SeSecurityPrivilege al leer SACLs).
PrivilegeSetLengthPULONGin/outEntrada: tamaño en bytes del buffer PrivilegeSet. Salida: tamaño realmente necesario.
GrantedAccessPACCESS_MASKoutRecibe la máscara de acceso que realmente se concedería a ClientToken.
AccessStatusPNTSTATUSoutRecibe STATUS_SUCCESS si se concedería el acceso, STATUS_ACCESS_DENIED en caso contrario. Distinto del propio NTSTATUS de la función.

IDs de syscalls por versión de Windows

Versión 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

Módulo del kernel

ntoskrnl.exeNtAccessCheck

APIs relacionadas

AccessCheckAccessCheckByTypeAccessCheckAndAuditAlarmWNtAccessCheckByTypeNtAccessCheckAndAuditAlarmNtPrivilegeCheck

Stub del 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

Notas no documentadas

NtAccessCheck ocupa literalmente la primera ranura del SSDT — SSN `0x0` en todas las builds de Windows desde NT 4 — lo cual la convierte en una curiosidad simpática pero inútil como primitiva ofensiva. Es el punto de entrada de user-mode para la lógica de chequeo de acceso *manual*: un servicio que acaba de impersonar a un cliente usa NtAccessCheck (típicamente vía el wrapper Win32 AccessCheck) para decidir si al cliente *se le permitiría* realizar una operación contra un recurso controlado por el servicio. No abre nada por sí misma — es una función de evaluación pura sobre SECURITY_DESCRIPTOR + token + GENERIC_MAPPING.

Uso común por malware

Casi nunca se usa de forma ofensiva directa. Los dos patrones que sí aparecen: (1) herramientas post-explotación que enumeran qué objetos con DACL puede alcanzar un token de impersonación robado sin abrirlos (reconocimiento silencioso — no se dispara auditoría salvo que haya SACLs configuradas); (2) código de exploit que prueba si un token forjado o reenviado concede el acceso pretendido. Evaluación honesta: NtAccessCheck está dominada por usos legítimos y es una señal débil de malware.

Oportunidades de detección

Apenas hay telemetría útil. NtAccessCheck no dispara por sí misma la auditoría de acceso a objetos (Event ID 4663) — solo lo hace el open posterior. Los eventos de privilege-use de ETW Microsoft-Windows-Security-Auditing pueden activarse si la evaluación toca un objeto con SACL, pero la cobertura es escasa. Útil como señal de *correlación*: un proceso inusual encadenando muchos NtAccessCheck contra descriptores variados y abriendo selectivamente solo los que tuvieron éxito es un patrón clásico de reconocimiento silencioso.

Ejemplos de syscalls directos

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),
    );
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20