> Windows Syscalls
ntoskrnl.exeT1106T1087

NtAccessCheck

Führt eine Access Check gegen einen Security Descriptor mit einem Impersonation-Token durch und liefert die gewährte Zugriffsmaske zurück.

Prototyp

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

Argumente

NameTypeDirDescription
SecurityDescriptorPSECURITY_DESCRIPTORinSelf-relative Security Descriptor der zu prüfenden geschützten Ressource.
ClientTokenHANDLEinHandle auf ein Impersonation-Token (TOKEN_QUERY) — muss ein Impersonation-Token sein, kein Primary-Token.
DesiredAccessACCESS_MASKinVom Aufrufer angeforderte Zugriffsrechte (kann generische Rechte enthalten — via GenericMapping aufgelöst).
GenericMappingPGENERIC_MAPPINGinObjekttypspezifisches Mapping von GENERIC_READ/WRITE/EXECUTE/ALL auf konkrete Zugriffsbits.
PrivilegeSetPPRIVILEGE_SEToutErhält die Privilegien, die der Kernel beim Check tatsächlich genutzt hat (z. B. SeSecurityPrivilege beim Lesen von SACLs).
PrivilegeSetLengthPULONGin/outEingabe: Größe des PrivilegeSet-Puffers in Bytes. Ausgabe: tatsächlich benötigte Größe.
GrantedAccessPACCESS_MASKoutErhält die Zugriffsmaske, die ClientToken tatsächlich gewährt würde.
AccessStatusPNTSTATUSoutErhält STATUS_SUCCESS, falls Zugriff gewährt würde, sonst STATUS_ACCESS_DENIED. Vom NTSTATUS der Funktion selbst unabhängig.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
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

Kernel-Modul

ntoskrnl.exeNtAccessCheck

Verwandte APIs

AccessCheckAccessCheckByTypeAccessCheckAndAuditAlarmWNtAccessCheckByTypeNtAccessCheckAndAuditAlarmNtPrivilegeCheck

Syscall-Stub

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

Undokumentierte Hinweise

NtAccessCheck belegt buchstäblich den ersten Slot der SSDT — SSN `0x0` auf jeder Windows-Build seit NT 4 — was sie zu einer netten Kuriosität macht, aber als Offensiv-Primitive nutzlos. Sie ist der User-Mode-Einstiegspunkt für *manuelle* Access-Check-Logik: ein Dienst, der gerade einen Client imitiert, nutzt NtAccessCheck (üblicherweise über den Win32-AccessCheck-Wrapper), um zu entscheiden, ob der Client eine Operation auf einer vom Dienst kontrollierten Ressource ausführen *dürfte*. Sie öffnet selbst nichts — sie ist eine reine Auswertungsfunktion über SECURITY_DESCRIPTOR + Token + GENERIC_MAPPING.

Häufige Malware-Nutzung

Wird fast nie direkt offensiv eingesetzt. Die zwei Muster, die vorkommen: (1) Post-Exploitation-Tools, die enumerieren, welche DACL-geschützten Objekte ein gestohlenes Impersonation-Token erreichen kann, ohne sie tatsächlich zu öffnen (lautlose Aufklärung — kein Audit feuert, sofern nicht SACLs konfiguriert sind); (2) Exploit-Code, der prüft, ob ein gefälschtes oder wiedereingespieltes Token den gewünschten Zugriff gewährt. Ehrliche Einschätzung: NtAccessCheck wird von legitimer Nutzung dominiert und ist ein schwaches Malware-Signal.

Erkennungs­möglichkeiten

Kaum nutzbare Telemetrie vorhanden. NtAccessCheck löst selbst kein Object-Access-Auditing aus (Event ID 4663) — nur ein nachfolgendes Open tut das. Privilege-Use-Events in ETW Microsoft-Windows-Security-Auditing können feuern, falls die Auswertung ein Objekt mit SACL berührt, doch die Abdeckung ist dünn. Brauchbar als *Korrelations*-Signal: ein ungewöhnlicher Prozess, der viele NtAccessCheck-Aufrufe über verschiedene Security Descriptors hintereinander absetzt und anschließend selektiv nur die erfolgreichen mit NtOpen* öffnet, ist ein klassisches lautloses Aufklärungsmuster.

Direkte Syscall-Beispiele

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

MITRE ATT&CK-Mappings

Last verified: 2026-05-20