NtOpenProcessTokenEx
Ouvre le jeton d'accès d'un processus en permettant à l'appelant de spécifier des attributs de handle tels que OBJ_INHERIT.
Prototype
NTSTATUS NtOpenProcessTokenEx( HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, PHANDLE TokenHandle );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle vers le processus dont le jeton est ouvert. Nécessite PROCESS_QUERY_(LIMITED_)INFORMATION. |
| DesiredAccess | ACCESS_MASK | in | Droits d'accès sur le jeton — combinaisons de TOKEN_QUERY, TOKEN_DUPLICATE, TOKEN_ADJUST_PRIVILEGES, TOKEN_IMPERSONATE, etc. |
| HandleAttributes | ULONG | in | Drapeaux OBJECT_ATTRIBUTES tels qu'OBJ_INHERIT (0x2) ou OBJ_KERNEL_HANDLE (0x200). Souvent 0. |
| TokenHandle | PHANDLE | out | Reçoit le handle vers le jeton ouvert en cas de succès. À fermer avec NtClose. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x30 | win10-1507 |
| Win10 1607 | 0x30 | win10-1607 |
| Win10 1703 | 0x30 | win10-1703 |
| Win10 1709 | 0x30 | win10-1709 |
| Win10 1803 | 0x30 | win10-1803 |
| Win10 1809 | 0x30 | win10-1809 |
| Win10 1903 | 0x30 | win10-1903 |
| Win10 1909 | 0x30 | win10-1909 |
| Win10 2004 | 0x30 | win10-2004 |
| Win10 20H2 | 0x30 | win10-20h2 |
| Win10 21H1 | 0x30 | win10-21h1 |
| Win10 21H2 | 0x30 | win10-21h2 |
| Win10 22H2 | 0x30 | win10-22h2 |
| Win11 21H2 | 0x30 | win11-21h2 |
| Win11 22H2 | 0x30 | win11-22h2 |
| Win11 23H2 | 0x30 | win11-23h2 |
| Win11 24H2 | 0x30 | win11-24h2 |
| Server 2016 | 0x30 | winserver-2016 |
| Server 2019 | 0x30 | winserver-2019 |
| Server 2022 | 0x30 | winserver-2022 |
| Server 2025 | 0x30 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 30 00 00 00 mov eax, 0x30 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
NtOpenProcessTokenEx est la primitive canonique réellement invoquée par `kernel32!OpenProcessToken` — `NtOpenProcessToken` n'est qu'un wrapper conservé pour la compatibilité source avec NT 3.x. Contrairement à la forme héritée, son SSN est **resté stable à `0x30`** de Windows 10 1507 à Windows 11 24H2, ce qui en fait une cible privilégiée pour les loaders à SSN codés en dur et les stubs SysWhispers. Le paramètre supplémentaire `HandleAttributes` permet de demander des handles héritables (`OBJ_INHERIT`) — utile pour des processus enfants à parent PID spoofé qui doivent hériter du jeton.
Usage courant par les malwares
Même rôle que NtOpenProcessToken dans les chaînes de vol de jeton, mais préféré des loaders modernes pour son SSN stable. Le BOF `steal_token` de Cobalt Strike et le module `getsystem` de Sliver y passent. JuicyPotato / RoguePotato / PrintSpoofer négocient d'abord un jeton SYSTEM via la coercition RPC, puis appellent NtOpenProcessTokenEx sur le processus engendré pour obtenir un handle duplicable, puis NtDuplicateToken + CreateProcessWithTokenW pour lancer un cmd.exe en contexte SYSTEM. La famille de bypass UAC Make-Me-Admin l'utilise pour cloner le jumeau élevé du jeton IL moyen.
Opportunités de détection
Surface de détection identique à NtOpenProcessToken : 4672 (Special Privileges Assigned, SeDebugPrivilege), 4663 (object access sur Token), 4673 (Sensitive Privilege Use). Spécifiquement pour LSASS, RunAsPPL force l'appel à échouer avec STATUS_ACCESS_DENIED à moins que l'appelant soit lui aussi PPL — un événement d'échec à fort signal. L'ETW `Microsoft-Windows-Kernel-Audit-API-Calls` émet `PsOpenProcessToken` quelle que soit la variante Nt appelée. Les EDR hookent couramment cette fonction dans ntdll ; les syscalls directs contournent ce hook mais l'audit object-access côté noyau subsiste.
Exemples de syscalls directs
asmx64 direct stub (stable SSN 0x30)
; SSN 0x30 stable across Win10 1507 -> Win11 24H2.
NtOpenProcessTokenEx PROC
mov r10, rcx ; ProcessHandle
mov eax, 30h ; SSN
syscall
ret
NtOpenProcessTokenEx ENDPcOpen elevated token for cross-session UAC clone (Make-Me-Admin)
// Locate the elevated split-token sibling of the current medium-IL process
// and ask for TOKEN_DUPLICATE so we can spawn a high-IL process with it.
HANDLE hElev = NULL, hTok = NULL;
// hElev = handle to a high-IL svchost / consent.exe we previously opened
NTSTATUS s = NtOpenProcessTokenEx(
hElev,
TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY,
0, // HandleAttributes
&hTok);
if (NT_SUCCESS(s)) {
// Next: NtDuplicateToken(... TokenPrimary ...) -> CreateProcessWithTokenW
}rustwindows-sys wrapper with naked-asm direct syscall
use std::arch::asm;
use windows_sys::Win32::Foundation::HANDLE;
#[unsafe(naked)]
pub unsafe extern "system" fn nt_open_process_token_ex(
_process: HANDLE,
_desired: u32,
_handle_attrs: u32,
_token_out: *mut HANDLE,
) -> i32 {
asm!(
"mov r10, rcx",
"mov eax, 0x30",
"syscall",
"ret",
options(noreturn),
);
}Mappings MITRE ATT&CK
Last verified: 2026-05-20