NtSetInformationWorkerFactory
Définit une classe de configuration sur une worker factory — y compris, dans certaines variantes PoolParty, la StartRoutine exécutée par les threads de travail.
Prototype
NTSTATUS NtSetInformationWorkerFactory( HANDLE WorkerFactoryHandle, WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, PVOID WorkerFactoryInformation, ULONG WorkerFactoryInformationLength );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| WorkerFactoryHandle | HANDLE | in | Handle vers la worker factory. Nécessite l'accès WORKER_FACTORY_SET_INFORMATION. |
| WorkerFactoryInformationClass | WORKERFACTORYINFOCLASS | in | Sélecteur de classe — WorkerFactoryBasicInformation, WorkerFactoryThreadMinimum/Maximum, WorkerFactoryThreadCpuSets, WorkerFactoryAdjustThreadGoal, etc. |
| WorkerFactoryInformation | PVOID | in | Buffer dont la mise en page dépend de la classe — ex. une structure WORKER_FACTORY_BASIC_INFORMATION ou un seul ULONG. |
| WorkerFactoryInformationLength | ULONG | in | Taille en octets du buffer d'information. Une longueur incohérente renvoie STATUS_INFO_LENGTH_MISMATCH. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x183 | win10-1507 |
| Win10 1607 | 0x18C | win10-1607 |
| Win10 1703 | 0x192 | win10-1703 |
| Win10 1709 | 0x195 | win10-1709 |
| Win10 1803 | 0x197 | win10-1803 |
| Win10 1809 | 0x198 | win10-1809 |
| Win10 1903 | 0x199 | win10-1903 |
| Win10 1909 | 0x199 | win10-1909 |
| Win10 2004 | 0x19F | win10-2004 |
| Win10 20H2 | 0x19F | win10-20h2 |
| Win10 21H1 | 0x19F | win10-21h1 |
| Win10 21H2 | 0x1A1 | win10-21h2 |
| Win10 22H2 | 0x1A1 | win10-22h2 |
| Win11 21H2 | 0x1AA | win11-21h2 |
| Win11 22H2 | 0x1AE | win11-22h2 |
| Win11 23H2 | 0x1AE | win11-23h2 |
| Win11 24H2 | 0x1B1 | win11-24h2 |
| Server 2016 | 0x18C | winserver-2016 |
| Server 2019 | 0x198 | winserver-2019 |
| Server 2022 | 0x1A7 | winserver-2022 |
| Server 2025 | 0x1B1 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 B1 01 00 00 mov eax, 0x1B1 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
L'énumération `WORKERFACTORYINFOCLASS` (définie dans phnt/ntexapi.h) sélectionne quel champ de la structure noyau `EWORKER_FACTORY` est modifié. La plupart des classes — min/max de threads, ensembles CPU, ajustements de timeout — sont des boutons de dimensionnement banals du threadpool. Deux sont intéressantes : `WorkerFactoryBasicInformation` expose (et, en Set, peut réécrire) les champs `StartRoutine` et `StartParameter`, et `WorkerFactoryThreadFlags` peut marquer les workers comme longs ou courts, modifiant l'agressivité avec laquelle le noyau les récupère.
Usage courant par les malwares
Les variantes PoolParty « Start Routine Overwrite » scindent l'opération en deux : d'abord appeler NtCreateWorkerFactory avec une StartRoutine bénigne (ntdll!TppWorkerThread est le choix évident — la factory devient indiscernable d'une légitime sur un cliché bref), puis appeler NtSetInformationWorkerFactory avec `WorkerFactoryBasicInformation` pour réécrire StartRoutine vers le pointeur de shellcode juste avant de poster le travail. Le schéma en deux étapes met en échec les détections inter-processus simples qui n'inspectent la StartRoutine qu'à la création. Le même syscall sert à mettre les minimums de threads à zéro dans certains gadgets d'évasion de sleep qui utilisent le threadpool pour imiter le comportement au repos d'un processus inoffensif.
Opportunités de détection
Les écritures WorkerFactoryBasicInformation sont rares en code normal — le threadpool ntdll fixe la StartRoutine à la création et n'y touche plus jamais. Un callback noyau qui compare `EWORKER_FACTORY.StartRoutine` avant/après ce syscall et signale tout changement est très fiable. L'invocation inter-processus amplifie le signal : le réglage légitime du threadpool est toujours intra-processus. Microsoft-Windows-Threading ETW émet certaines classes mais pas toutes ; une couverture fiable demande ObRegisterCallbacks sur le type d'objet WorkerFactory ou un minifilter qui observe le syscall en noyau.
Exemples de syscalls directs
cPoolParty StartRoutine overwrite
// Step 2 of the 'overwrite' variant — flip the entry point to shellcode
// after the factory was created with a benign decoy routine.
typedef struct _WORKER_FACTORY_BASIC_INFORMATION {
LARGE_INTEGER Timeout;
LARGE_INTEGER RetryTimeout;
LARGE_INTEGER IdleTimeout;
BOOLEAN Paused;
BOOLEAN TimerSet;
BOOLEAN QueuedToExWorker;
BOOLEAN MayCreate;
BOOLEAN CreateInProgress;
BOOLEAN InsertedIntoQueue;
BOOLEAN Shutdown;
ULONG BindingCount;
ULONG ThreadMinimum;
ULONG ThreadMaximum;
ULONG PendingWorkerCount;
ULONG WaitingWorkerCount;
ULONG TotalWorkerCount;
ULONG ReleaseCount;
LONGLONG InfiniteWaitGoal;
PVOID StartRoutine;
PVOID StartParameter;
HANDLE ProcessId;
SIZE_T StackReserve;
SIZE_T StackCommit;
NTSTATUS LastThreadCreationStatus;
} WORKER_FACTORY_BASIC_INFORMATION;
WORKER_FACTORY_BASIC_INFORMATION info = {0};
NtQueryInformationWorkerFactory(hWf, WorkerFactoryBasicInformation,
&info, sizeof(info), NULL);
info.StartRoutine = pRemoteShellcode; // hijack
info.StartParameter = NULL;
NtSetInformationWorkerFactory(hWf, WorkerFactoryBasicInformation,
&info, sizeof(info));asmx64 direct stub (Win11 24H2 SSN 0x1B1)
NtSetInformationWorkerFactory PROC
mov r10, rcx
mov eax, 1B1h ; Win11 24H2 / Server 2025
syscall
ret
NtSetInformationWorkerFactory ENDPMappings MITRE ATT&CK
Last verified: 2026-05-20