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
  }
}
