NtWorkerFactoryWorkerReady
Signals to the kernel that a threadpool worker is ready to receive work — part of the internal ntdll!TppWorkerThread handshake.
Prototype
NTSTATUS NtWorkerFactoryWorkerReady( HANDLE WorkerFactoryHandle );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| WorkerFactoryHandle | HANDLE | in | Handle to the worker factory this worker thread belongs to. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x1 | win10-1507 |
| Win10 1607 | 0x1 | win10-1607 |
| Win10 1703 | 0x1 | win10-1703 |
| Win10 1709 | 0x1 | win10-1709 |
| Win10 1803 | 0x1 | win10-1803 |
| Win10 1809 | 0x1 | win10-1809 |
| Win10 1903 | 0x1 | win10-1903 |
| Win10 1909 | 0x1 | win10-1909 |
| Win10 2004 | 0x1 | win10-2004 |
| Win10 20H2 | 0x1 | win10-20h2 |
| Win10 21H1 | 0x1 | win10-21h1 |
| Win10 21H2 | 0x1 | win10-21h2 |
| Win10 22H2 | 0x1 | win10-22h2 |
| Win11 21H2 | 0x1 | win11-21h2 |
| Win11 22H2 | 0x1 | win11-22h2 |
| Win11 23H2 | 0x1 | win11-23h2 |
| Win11 24H2 | 0x1 | win11-24h2 |
| Server 2016 | 0x1 | winserver-2016 |
| Server 2019 | 0x1 | winserver-2019 |
| Server 2022 | 0x1 | winserver-2022 |
| Server 2025 | 0x1 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 01 00 00 00 mov eax, 0x1 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
Undocumented notes
The most stable syscall number in the entire table — `0x1` from Windows 7 onward. It is called exclusively by `ntdll!TppWorkerThread` (the canonical StartRoutine for any worker factory) and tells the kernel: 'this worker has finished its previous dispatch, decrement my pending count, I'm going back to NtWaitForWorkViaWorkerFactory'. The bookkeeping it performs is what lets the kernel decide whether to spawn more workers, retire idle ones, or keep the count flat.
Common malware usage
Almost never called directly by malware — it is part of the internal threadpool bookkeeping and only makes sense in the context of a real `TppWorkerThread` loop. The exception is PoolParty variants where the shellcode itself emulates the worker handshake to keep the threadpool's bookkeeping consistent (and therefore the parent process responsive) after hijacking a worker. Skipping the ready/wait/release cycle causes the kernel's `PendingWorkerCount` to drift, which in turn can starve the rest of the victim's threadpool — observable as a hung application.
Detection opportunities
Effectively undetectable in isolation — every Windows process with a CRT, .NET runtime, or COM apartment issues thousands of these per second. Detection only becomes possible when it is *missing*: a worker factory whose ready count never increments while its completion port is being drained indicates that something is bypassing the handshake (a PoolParty shellcode that forgot to emulate the loop, or a debugger holding a worker). This is a heuristic, not a primary signal.
Direct syscall examples
cSkeleton of ntdll!TppWorkerThread
// Approximate reverse of the user-mode loop driven by NtCreateWorkerFactory.
// Do NOT call directly — this is what TppWorkerThread does on every worker.
VOID WINAPI TppWorkerThreadLike(PVOID context) {
HANDLE hWf = ((PTHREADPOOL_INTERNAL)context)->WorkerFactoryHandle;
for (;;) {
FILE_IO_COMPLETION_INFORMATION info;
NTSTATUS s = NtWaitForWorkViaWorkerFactory(hWf, &info);
if (!NT_SUCCESS(s)) break;
// Dispatch the callback that info.KeyContext encodes.
DispatchCallback(&info);
// Tell the kernel we're done and ready for the next item.
NtWorkerFactoryWorkerReady(hWf);
}
}asmx64 direct stub (SSN 0x1)
; Stable across every Windows 10/11 build.
NtWorkerFactoryWorkerReady PROC
mov r10, rcx
mov eax, 1
syscall
ret
NtWorkerFactoryWorkerReady ENDPMITRE ATT&CK mappings
Last verified: 2026-05-20