Last active
September 28, 2024 04:01
-
-
Save alfarom256/fc8fab62103def18d467a25ebdad1ada to your computer and use it in GitHub Desktop.
Thread Execution via NtCreateWorkerFactory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <winternl.h> | |
#include <stdio.h> | |
#define WORKER_FACTORY_FULL_ACCESS 0xf00ff | |
// https://github.com/winsiderss/systeminformer/blob/17fb2e0048f062a04394c4ccd615b611e6ffd45d/phnt/include/ntexapi.h#LL1096C1-L1115C52 | |
typedef enum _WORKERFACTORYINFOCLASS | |
{ | |
WorkerFactoryTimeout, // LARGE_INTEGER | |
WorkerFactoryRetryTimeout, // LARGE_INTEGER | |
WorkerFactoryIdleTimeout, // s: LARGE_INTEGER | |
WorkerFactoryBindingCount, // s: ULONG | |
WorkerFactoryThreadMinimum, // s: ULONG | |
WorkerFactoryThreadMaximum, // s: ULONG | |
WorkerFactoryPaused, // ULONG or BOOLEAN | |
WorkerFactoryBasicInformation, // q: WORKER_FACTORY_BASIC_INFORMATION | |
WorkerFactoryAdjustThreadGoal, | |
WorkerFactoryCallbackType, | |
WorkerFactoryStackInformation, // 10 | |
WorkerFactoryThreadBasePriority, // s: ULONG | |
WorkerFactoryTimeoutWaiters, // s: ULONG, since THRESHOLD | |
WorkerFactoryFlags, // s: ULONG | |
WorkerFactoryThreadSoftMaximum, // s: ULONG | |
WorkerFactoryThreadCpuSets, // since REDSTONE5 | |
MaxWorkerFactoryInfoClass | |
} WORKERFACTORYINFOCLASS, * PWORKERFACTORYINFOCLASS; | |
// https://github.com/winsiderss/systeminformer/blob/17fb2e0048f062a04394c4ccd615b611e6ffd45d/phnt/include/ntexapi.h#LL1212C1-L1218C64 | |
struct _FILE_IO_COMPLETION_INFORMATION; | |
typedef struct _WORKER_FACTORY_DEFERRED_WORK | |
{ | |
struct _PORT_MESSAGE* AlpcSendMessage; | |
PVOID AlpcSendMessagePort; | |
ULONG AlpcSendMessageFlags; | |
ULONG Flags; | |
} WORKER_FACTORY_DEFERRED_WORK, * PWORKER_FACTORY_DEFERRED_WORK; | |
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, * PWORKER_FACTORY_BASIC_INFORMATION; | |
typedef NTSTATUS(WINAPI* tNtCreateWorkerFactory)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, HANDLE, PVOID, PVOID, ULONG, SIZE_T, SIZE_T); | |
typedef NTSTATUS(WINAPI* tNtWorkerFactoryWorkerReady)(HANDLE); | |
typedef NTSTATUS(WINAPI* tNtSetInformationWorkerFactory)(HANDLE, WORKERFACTORYINFOCLASS, PVOID, ULONG); | |
typedef NTSTATUS(WINAPI* tNtQueryInformationWorkerFactory)(HANDLE, WORKERFACTORYINFOCLASS, PVOID, ULONG, PULONG); | |
typedef NTSTATUS(WINAPI* tNtWaitForWorkViaWorkerFactory)(HANDLE, _FILE_IO_COMPLETION_INFORMATION*, ULONG, PULONG, WORKER_FACTORY_DEFERRED_WORK*); | |
/* | |
* https://github.com/DavidXanatos/TaskExplorer/blob/48c349ddf8481d4b04ede8f4564c8fc76f4a3bbc/ProcessHacker/phnt/include/ntzwapi.h#L4596 | |
* | |
NTSYSCALLAPI | |
NTSTATUS | |
NTAPI | |
ZwWaitForWorkViaWorkerFactory( | |
_In_ HANDLE WorkerFactoryHandle, | |
_Out_writes_to_(Count, *PacketsReturned) struct _FILE_IO_COMPLETION_INFORMATION *MiniPackets, | |
_In_ ULONG Count, | |
_Out_ PULONG PacketsReturned, | |
_In_ struct _WORKER_FACTORY_DEFERRED_WORK* DeferredWork | |
); | |
*/ | |
/* | |
https://processhacker.sourceforge.io/doc/ntexapi_8h_source.html | |
NTSYSCALLAPI | |
NTSTATUS | |
NTAPI | |
NtCreateWorkerFactory( | |
_Out_ PHANDLE WorkerFactoryHandleReturn, | |
_In_ ACCESS_MASK DesiredAccess, | |
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, | |
_In_ HANDLE CompletionPortHandle, | |
_In_ HANDLE WorkerProcessHandle, | |
_In_ PVOID StartRoutine, | |
_In_opt_ PVOID StartParameter, | |
_In_opt_ ULONG MaxThreadCount, | |
_In_opt_ SIZE_T StackReserve, | |
_In_opt_ SIZE_T StackCommit | |
); | |
*/ | |
void test() { | |
MessageBoxA(NULL, "Test", "test", MB_OK); | |
} | |
int main(int argc, char** argv) { | |
ULONG ulThreadMinimum = 1; | |
ULONG ulKey = 'lain'; | |
HANDLE hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, ulKey, 0); | |
NTSTATUS status = 0; // STATUS_SUCCESS | |
tNtCreateWorkerFactory stubNtCreateWorkerFactory = NULL; | |
tNtSetInformationWorkerFactory stubNtSetInformationWorkerFactory = NULL; | |
tNtQueryInformationWorkerFactory stubNtQueryInformationWorkerFactory = NULL; | |
HANDLE hWorkerFactory = INVALID_HANDLE_VALUE; | |
HMODULE hNtdll = GetModuleHandleA("ntdll"); | |
if (!hNtdll) { | |
return -1; | |
} | |
stubNtCreateWorkerFactory = (tNtCreateWorkerFactory)GetProcAddress(hNtdll, "NtCreateWorkerFactory"); | |
if (!stubNtCreateWorkerFactory) { | |
return -1; | |
} | |
stubNtSetInformationWorkerFactory = (tNtSetInformationWorkerFactory)GetProcAddress(hNtdll, "NtSetInformationWorkerFactory"); | |
if (!stubNtSetInformationWorkerFactory) { | |
return -1; | |
} | |
stubNtQueryInformationWorkerFactory = (tNtQueryInformationWorkerFactory)GetProcAddress(hNtdll, "NtQueryInformationWorkerFactory"); | |
if (!stubNtQueryInformationWorkerFactory) { | |
return -1; | |
} | |
// So I'm not entirely certain if this is an actual stack? | |
// ProcessHacker et. al. report this as an initial CONTEXT | |
// but in Windbg, the PVOID lpParam provided by NtCreateWorkerFactory | |
// does not appear to resemble a CONTEXT, rather a true stack. | |
// TBD I guess? | |
PVOID stack = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x100 * sizeof(DWORD64)); | |
for (size_t i = 0; i < 0x100; i++) { | |
((PDWORD64)stack)[i] = (DWORD64)'a' + i; | |
} | |
status = stubNtCreateWorkerFactory(&hWorkerFactory, WORKER_FACTORY_FULL_ACCESS, NULL, hIocp, (HANDLE)-1, test, stack, 1, 0x1000, 0x1000); | |
if (!NT_SUCCESS(status)) { | |
printf("NtCreateWorkerFactory - %d\n", GetLastError()); | |
return -1; | |
} | |
status = stubNtSetInformationWorkerFactory(hWorkerFactory, WorkerFactoryThreadMinimum, &ulThreadMinimum, sizeof(ULONG)); | |
while (TRUE) {} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note to self, sleep before publishing and revise in the morning.