> Windows Syscalls
ntoskrnl.exeT1106

NtCreateProfile

Crée un objet de profileur d'échantillonnage en mode noyau qui range le compteur de programme dans un histogramme.

Prototype

NTSTATUS NtCreateProfile(
  PHANDLE        ProfileHandle,
  HANDLE         Process,
  PVOID          ProfileBase,
  SIZE_T         ProfileSize,
  ULONG          BucketSize,
  PULONG         Buffer,
  ULONG          BufferSize,
  KPROFILE_SOURCE ProfileSource,
  KAFFINITY      Affinity
);

Arguments

NameTypeDirDescription
ProfileHandlePHANDLEoutReçoit un handle vers le nouvel objet profil.
ProcessHANDLEinHandle du processus profilé, ou NULL pour profiler tout le système.
ProfileBasePVOIDinDébut de la plage d'adresses virtuelles dont les échantillons RIP seront comptés.
ProfileSizeSIZE_TinLongueur en octets de la plage d'adresses profilée.
BucketSizeULONGinlog2 de la taille de bucket en octets, ex. 2 pour des buckets de 4 octets.
BufferPULONGinTampon fourni par l'appelant qui recevra les comptages d'échantillons par bucket.
BufferSizeULONGinTaille de Buffer en octets ; doit contenir ProfileSize >> BucketSize entrées ULONG.
ProfileSourceKPROFILE_SOURCEinSource d'échantillonnage (ProfileTime, ProfileTotalIssues, ProfileBranchMispredictions, etc.).
AffinityKAFFINITYinMasque de bits des CPU auxquels le profil s'applique. 0 sélectionne tous les CPU disponibles.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070xAEwin10-1507
Win10 16070xB0win10-1607
Win10 17030xB3win10-1703
Win10 17090xB4win10-1709
Win10 18030xB5win10-1803
Win10 18090xB5win10-1809
Win10 19030xB6win10-1903
Win10 19090xB6win10-1909
Win10 20040xBAwin10-2004
Win10 20H20xBAwin10-20h2
Win10 21H10xBAwin10-21h1
Win10 21H20xBBwin10-21h2
Win10 22H20xBBwin10-22h2
Win11 21H20xBFwin11-21h2
Win11 22H20xC0win11-22h2
Win11 23H20xC0win11-23h2
Win11 24H20xC2win11-24h2
Server 20160xB0winserver-2016
Server 20190xB5winserver-2019
Server 20220xBEwinserver-2022
Server 20250xC2winserver-2025

Module noyau

ntoskrnl.exeNtCreateProfile

APIs liées

NtStartProfileNtStopProfileNtSetIntervalProfileNtQueryIntervalProfileNtCreateProfileEx

Stub du syscall

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

NtCreateProfile, avec NtStartProfile / NtStopProfile / NtSetIntervalProfile / NtQueryIntervalProfile, pilote le profileur d'échantillonnage classique du noyau — le même backend qui propulsait KernRate il y a des décennies et qui aujourd'hui est encore utilisé par certains scénarios PerfView et WPR. Le profileur s'attache au timer haute résolution (ou à une source PMU matérielle sur les CPU compatibles) et à chaque tick incrémente le bucket d'histogramme correspondant au RIP interrompu, à condition que RIP tombe dans [ProfileBase, ProfileBase + ProfileSize). Le pointeur Buffer est fourni par l'user-mode mais le noyau y écrit directement depuis le contexte ISR, c'est pourquoi le tampon doit rester résident (en pratique l'appelant devrait le VirtualLock). Nécessite SeSystemProfilePrivilege pour le profilage à l'échelle système.

Usage courant par les malwares

Signal offensif réellement faible. Les abus historiques sont étroits : (1) des travaux académiques de canal auxiliaire qui utilisaient des profileurs d'échantillonnage pour empreinter le comportement de l'ordonnanceur noyau et inférer des secrets de threads victimes sur cœurs partagés ; (2) des PoC d'attaque de timing de niche qui abusaient de `ProfileTotalIssues` pour compter les instructions retirées dans des chemins de code étrangers. Aucun ne s'est traduit en malware grand public — l'exigence de SeSystemProfilePrivilege et l'empreinte syscall inhabituelle rendent l'opération plus pénible que rentable comparée à QueryPerformanceCounter pour le timing ou à l'accès PMU-MSR pour des canaux auxiliaires fins. Territoire majoritairement défensif.

Opportunités de détection

Usage de fond très faible dans le malware user-mode. Un processus non-système appelant NtCreateProfile, surtout avec `Process == NULL` (system-wide) et `ProfileSource != ProfileTime`, n'est essentiellement jamais bénin. Auditez les attributions de `SeSystemProfilePrivilege` comme vous auditeriez SeDebugPrivilege. L'objet profil lui-même est visible sous `\KernelObjects` et les handles de profil nommés peuvent être énumérés via NtQueryObject. La couverture EDR est faible — c'est l'un des rares syscalls natifs que presque rien ne hooke parce que presque rien ne l'appelle.

Exemples de syscalls directs

cProfile the current process's main module

// Minimal NtCreateProfile + NtStartProfile sequence — defensive perf use.
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *PNTCREATEPROFILE)(PHANDLE, HANDLE, PVOID, SIZE_T, ULONG,
                                           PULONG, ULONG, ULONG, ULONG_PTR);
typedef NTSTATUS (NTAPI *PNTSTARTPROFILE)(HANDLE);

void profile_self(PVOID base, SIZE_T size) {
    ULONG bucketShift = 2;                 // 4-byte buckets
    ULONG entries     = (ULONG)(size >> bucketShift);
    ULONG *buf        = (ULONG*)VirtualAlloc(NULL, entries * sizeof(ULONG),
                                             MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    VirtualLock(buf, entries * sizeof(ULONG));

    HMODULE nt = GetModuleHandleA("ntdll.dll");
    PNTCREATEPROFILE pNtCreateProfile = (PNTCREATEPROFILE)GetProcAddress(nt, "NtCreateProfile");
    PNTSTARTPROFILE  pNtStartProfile  = (PNTSTARTPROFILE) GetProcAddress(nt, "NtStartProfile");

    HANDLE hProf = NULL;
    pNtCreateProfile(&hProf, GetCurrentProcess(), base, size, bucketShift,
                     buf, entries * sizeof(ULONG), 0 /* ProfileTime */, 0);
    pNtStartProfile(hProf);
}

asmx64 direct stub (Win11 24H2, SSN 0xC2)

NtCreateProfile PROC
    mov  r10, rcx
    mov  eax, 0C2h
    syscall
    ret
NtCreateProfile ENDP

Mappings MITRE ATT&CK

Last verified: 2026-05-20