NtCreateProfile
Erzeugt ein Kernel-Mode-Sampling-Profiler-Objekt, das den Program Counter in ein Histogramm einsortiert.
Prototyp
NTSTATUS NtCreateProfile( PHANDLE ProfileHandle, HANDLE Process, PVOID ProfileBase, SIZE_T ProfileSize, ULONG BucketSize, PULONG Buffer, ULONG BufferSize, KPROFILE_SOURCE ProfileSource, KAFFINITY Affinity );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ProfileHandle | PHANDLE | out | Empfängt ein Handle auf das neu erzeugte Profil-Objekt. |
| Process | HANDLE | in | Handle des zu profilierenden Prozesses oder NULL für das gesamte System. |
| ProfileBase | PVOID | in | Start des virtuellen Adressbereichs, dessen RIP-Samples gezählt werden. |
| ProfileSize | SIZE_T | in | Länge des profilierten Adressbereichs in Bytes. |
| BucketSize | ULONG | in | log2 der Bucket-Größe in Bytes, z. B. 2 für 4-Byte-Buckets. |
| Buffer | PULONG | in | Vom Aufrufer bereitgestellter Buffer, der die Sample-Zähler pro Bucket aufnimmt. |
| BufferSize | ULONG | in | Größe von Buffer in Bytes; muss ProfileSize >> BucketSize ULONG-Einträge fassen. |
| ProfileSource | KPROFILE_SOURCE | in | Sampling-Quelle (ProfileTime, ProfileTotalIssues, ProfileBranchMispredictions usw.). |
| Affinity | KAFFINITY | in | Bitmaske der CPUs, auf die das Profil angewendet wird. 0 wählt alle verfügbaren CPUs. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0xAE | win10-1507 |
| Win10 1607 | 0xB0 | win10-1607 |
| Win10 1703 | 0xB3 | win10-1703 |
| Win10 1709 | 0xB4 | win10-1709 |
| Win10 1803 | 0xB5 | win10-1803 |
| Win10 1809 | 0xB5 | win10-1809 |
| Win10 1903 | 0xB6 | win10-1903 |
| Win10 1909 | 0xB6 | win10-1909 |
| Win10 2004 | 0xBA | win10-2004 |
| Win10 20H2 | 0xBA | win10-20h2 |
| Win10 21H1 | 0xBA | win10-21h1 |
| Win10 21H2 | 0xBB | win10-21h2 |
| Win10 22H2 | 0xBB | win10-22h2 |
| Win11 21H2 | 0xBF | win11-21h2 |
| Win11 22H2 | 0xC0 | win11-22h2 |
| Win11 23H2 | 0xC0 | win11-23h2 |
| Win11 24H2 | 0xC2 | win11-24h2 |
| Server 2016 | 0xB0 | winserver-2016 |
| Server 2019 | 0xB5 | winserver-2019 |
| Server 2022 | 0xBE | winserver-2022 |
| Server 2025 | 0xC2 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
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
Undokumentierte Hinweise
NtCreateProfile treibt zusammen mit NtStartProfile / NtStopProfile / NtSetIntervalProfile / NtQueryIntervalProfile den klassischen Sampling-Profiler des Kernels — dasselbe Backend, das vor Jahrzehnten KernRate antrieb und das heute noch von einigen PerfView- und WPR-Szenarien genutzt wird. Der Profiler hängt sich an den High-Resolution-Timer (oder eine Hardware-PMU-Quelle auf unterstützten CPUs) und inkrementiert bei jedem Tick den Histogramm-Bucket, der dem unterbrochenen RIP entspricht, sofern RIP innerhalb von [ProfileBase, ProfileBase + ProfileSize) liegt. Der Buffer-Zeiger kommt aus dem User-Mode, der Kernel schreibt aber direkt aus dem ISR-Kontext hinein — daher muss der Buffer resident bleiben (praktisch sollte der Aufrufer ihn VirtualLocken). Erfordert SeSystemProfilePrivilege für systemweites Profiling.
Häufige Malware-Nutzung
Echt schwaches offensives Signal. Die historischen Missbräuche sind eng: (1) akademische Side-Channel-Arbeiten, die Sampling-Profiler nutzten, um Kernel-Scheduler-Verhalten zu fingerprinten und Geheimnisse aus Opfer-Threads auf geteilten Kernen abzuleiten; (2) Nischen-Timing-Attack-PoCs, die `ProfileTotalIssues` missbrauchten, um Retired Instructions in fremden Code-Pfaden zu zählen. Keines davon hat in Commodity-Malware Einzug gehalten — die SeSystemProfilePrivilege-Anforderung und der ungewöhnliche Syscall-Footprint machen es unrentabler als QueryPerformanceCounter fürs Timing oder PMU-MSR-Zugriffe für feinkörnige Seitenkanäle. Überwiegend defensives Tooling-Terrain.
Erkennungsmöglichkeiten
Sehr geringe Hintergrundnutzung in User-Mode-Malware. Ein Nicht-Systemprozess, der NtCreateProfile aufruft, besonders mit `Process == NULL` (systemweit) und `ProfileSource != ProfileTime`, ist im Grunde nie gutartig. `SeSystemProfilePrivilege`-Vergaben so auditieren wie SeDebugPrivilege. Das Profilobjekt selbst ist unter `\KernelObjects` sichtbar und benannte Profile-Handles lassen sich via NtQueryObject aufzählen. EDR-Abdeckung ist dürftig — es ist einer der seltenen nativen Syscalls, die fast nichts hookt, weil fast nichts ihn aufruft.
Direkte Syscall-Beispiele
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 ENDPMITRE ATT&CK-Mappings
Last verified: 2026-05-20