NtGetNextThread
Liefert ein Handle auf den nächsten Thread eines Zielprozesses durch Durchlaufen der Kernel-Thread-Liste.
Prototyp
NTSTATUS NtGetNextThread( HANDLE ProcessHandle, HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, ULONG Flags, PHANDLE NewThreadHandle );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle auf den Prozess, dessen Threads aufgezählt werden. Erfordert PROCESS_QUERY_INFORMATION. |
| ThreadHandle | HANDLE | in | Handle auf den zuvor zurückgegebenen Thread. NULL startet die Aufzählung. |
| DesiredAccess | ACCESS_MASK | in | Zugriffsmaske für das neue Thread-Handle, z. B. THREAD_GET_CONTEXT | THREAD_SET_CONTEXT. |
| HandleAttributes | ULONG | in | Handle-Attributflags. Üblicherweise 0. |
| Flags | ULONG | in | Reserviert. 0 übergeben. |
| NewThreadHandle | PHANDLE | out | Empfängt das neue Thread-Handle. STATUS_NO_MORE_ENTRIES markiert das Listenende. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0xE9 | win10-1507 |
| Win10 1607 | 0xEC | win10-1607 |
| Win10 1703 | 0xEF | win10-1703 |
| Win10 1709 | 0xF0 | win10-1709 |
| Win10 1803 | 0xF1 | win10-1803 |
| Win10 1809 | 0xF2 | win10-1809 |
| Win10 1903 | 0xF3 | win10-1903 |
| Win10 1909 | 0xF3 | win10-1909 |
| Win10 2004 | 0xF8 | win10-2004 |
| Win10 20H2 | 0xF8 | win10-20h2 |
| Win10 21H1 | 0xF8 | win10-21h1 |
| Win10 21H2 | 0xF9 | win10-21h2 |
| Win10 22H2 | 0xF9 | win10-22h2 |
| Win11 21H2 | 0xFE | win11-21h2 |
| Win11 22H2 | 0xFF | win11-22h2 |
| Win11 23H2 | 0xFF | win11-23h2 |
| Win11 24H2 | 0x101 | win11-24h2 |
| Server 2016 | 0xEC | winserver-2016 |
| Server 2019 | 0xF2 | winserver-2019 |
| Server 2022 | 0xFD | winserver-2022 |
| Server 2025 | 0x101 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 01 01 00 00 mov eax, 0x101 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
NtGetNextThread iteriert das ThreadListHead des in ProcessHandle geöffneten EPROCESS. Sie ist das Thread-Pendant zu NtGetNextProcess und hat ebenfalls keinen dokumentierten Win32-Wrapper — `Thread32First`/`Thread32Next` laufen über die Toolhelp-Snapshot-Mechanik. Jeder Aufruf liefert ein neues Kernel-Handle, das der Aufrufer schließen muss (außer wenn STATUS_NO_MORE_ENTRIES den Lauf beendet). Die Funktion akzeptiert `PROCESS_QUERY_LIMITED_INFORMATION`, wenn der Aufrufer keine stärkeren Rechte am Prozess braucht, doch der gewünschte *Thread*-Zugriff muss von Anfang an angefordert werden — das Handle ist nicht ohne Weiteres aufrüstbar.
Häufige Malware-Nutzung
Wird zusammen mit NtGetNextProcess verwendet, um jeden Thread im System ohne Toolhelp32 zu enumerieren. Die PoolParty-Injection-Familie (die Thread-Pool-Internals missbraucht) iteriert die Worker-Threads des Pools mit genau diesem API-Paar, um einen Ziel-TP_WORKER-Thread zum Hijack zu finden. Auch von verdeckten Thread-Hijacking-Implants genutzt, die einen Opfer-Thread auswählen, dessen Kontext mit NtGetContextThread schnappen, RIP modifizieren und fortsetzen — alles ohne OpenThread per TID. `Thread32First/Next` zu meiden ist relevant, weil Toolhelp eine `_THSnapshot`-Section anlegt, die für Handle-Table-Inspektoren sichtbar ist.
Erkennungsmöglichkeiten
Wie NtGetNextProcess hat dieser Syscall geringes Hintergrundrauschen — die meisten legitimen Prozessenumeratoren nutzen PSAPI oder Toolhelp. Eine Häufung von NtGetNextThread-Aufrufen aus einem einzelnen Nicht-Systemprozess ist verdächtig. Threat-Hunting-Queries, die ETW Microsoft-Windows-Kernel-Process (Thread-Erzeugung) mit dem *Fehlen* erwarteter Toolhelp-Section-Erzeugungen kombinieren, können dieses Muster aufdecken. Sysmon Event ID 8 (CreateRemoteThread) feuert beim nachfolgenden Hijack nur, wenn ein neuer Thread erzeugt wird, nicht bei Kontextwechsel-Hijacks — das hochwertige Signal ist daher NtSetContextThread gegen einen fremden Thread unmittelbar nach der Enumeration.
Direkte Syscall-Beispiele
cStealth thread enumeration of a target process
// Walk every thread of a given process without Toolhelp32.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI *PNT_GET_NEXT_THREAD)(HANDLE, HANDLE, ACCESS_MASK, ULONG, ULONG, PHANDLE);
void EnumerateThreads(HANDLE hProcess) {
HMODULE nt = GetModuleHandleA("ntdll.dll");
PNT_GET_NEXT_THREAD pNtGetNextThread = (PNT_GET_NEXT_THREAD)GetProcAddress(nt, "NtGetNextThread");
HANDLE hThread = NULL;
HANDLE hNext = NULL;
while (pNtGetNextThread(hProcess, hThread, THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME,
0, 0, &hNext) == 0) {
if (hThread) CloseHandle(hThread);
hThread = hNext;
// ... inspect TEB / GetThreadContext / hijack candidate ...
}
if (hThread) CloseHandle(hThread);
}asmx64 direct stub (Win11 24H2, SSN 0x101)
NtGetNextThread PROC
mov r10, rcx
mov eax, 101h
syscall
ret
NtGetNextThread ENDPMITRE ATT&CK-Mappings
Last verified: 2026-05-20