extern "C" { #include "undocnt.h" NTSTATUS _ZwQueryInformationThread(HANDLE ThreadHandle,THREAD_INFORMATION_CLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength,PULONG ReturnLength); } //extern "C" /* global variable for SDT index of ZwQueryInformationThread that will be initialized from user mode application before hooking */ ULONG SDT_index_ZwQueryInformationThread=0; /* this version uses ZwQueryInformationThread in kernel driver to determine process that owns specific thread, unfortunately ntoskrnl.exe exports ZwQueryInformationThread in XP and higher, but the implementation is also available in W2k, so we will do a little hack here and from user mode ntdll.dll we retrieve an index to SDT and send it to kernel driver to call ZwQueryInformationThread using this index we could hardcode the index for W2k but this way it is more elegant as we don't need to care about service pack differences this is quite simple solution but it works only if this function is not hooked in ntdll.dll, if the function is hooked (and index is rewritten) this hack fails, however, in this case we should load and map ntdll.dll from disk to get raw unhooked image and find our function address in export table and retrieve the index from the image then, this is not implemented in this version, we assume clear (not hooked) environment */ __declspec(naked) NTSTATUS _ZwQueryInformationThread(HANDLE ThreadHandle,THREAD_INFORMATION_CLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength,PULONG ReturnLength) { __asm { cmp SDT_index_ZwQueryInformationThread,000h jz failed mov eax,SDT_index_ZwQueryInformationThread lea edx,[esp+004h] int 02Eh retn 00014h failed: mov eax,0xC00000001 //STATUS_UNSUCCESSFUL retn 00014h } }