2015-08-30 55 views
1

因爲大多數關於http://undocumented.ntinternals.net上這個特定問題的鏈接顯然已經死亡,並且NtQueryInfoThread和相關的THREADINFOCLASSes已經從Winternl.h消失了。我現在坐在這裏掙扎找到我知道句柄的過程的TEB。 我嘗試從ntdll.dll加載方法,這是另一種解決方案,似乎工作,但遺憾的是我仍然無法獲得所需的地址。通過它的線程處理獲取線程的TIB/TEB(2015)

typedef NTSTATUS(*ThreadInfoProc)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); 
PVOID CProcessHelper::GetThreadStackTopAddress(HANDLE hThread) 
{ 
HINSTANCE ntdllInstance; 
ThreadInfoProc NtQueryInfoThread; 

ntdllInstance = LoadLibrary("Ntdll.dll"); 

if (ntdllInstance != NULL) 
{ 
    NtQueryInfoThread = (ThreadInfoProc)GetProcAddress(ntdllInstance, "NtQueryInformationThread"); 

    if (NtQueryInfoThread != NULL) 
    { 

     THREAD_BASIC_INFORMATION bi; 
     NT_TIB tib; 

     NTSTATUS ntstat = 0; 
     NTSTATUS ntstat = (NtQueryInfoThread)(hThread, (THREADINFOCLASS)0, &bi, sizeof(THREAD_BASIC_INFORMATION),NULL); 

     ReadProcessMemory(CurrentProcessHandle, bi.TebBaseAddress, &tib, sizeof(NT_TIB), 0); 

     PrintHex(tib.StackBase); // output: CCCCCCCCCC 
    } 
} 

return nullptr; 
} 

是否有任何其他方式,也許使用公共API調用來獲得線程的TEB? (正如MSDN指出,這種做法不應再使用。)

最好的問候,

亞歷

回答

1

工作正常:是唯一的其他方式來獲得一個線程的TEB是讀它使用:

NT_TIB* tib = (NT_TIB*)__readfsdword(0x18);

並讀取從該基地址。

您的呼叫可能失敗,因爲您可能沒有正確的權限來讀取內存。嘗試使用VirtualProtect

下面的作品,但我只測試了它當前的進程..

#include <iostream> 
#include <windows.h> 

typedef LONG NTSTATUS; 
typedef DWORD KPRIORITY; 
typedef WORD UWORD; 

typedef struct _CLIENT_ID 
{ 
    PVOID UniqueProcess; 
    PVOID UniqueThread; 
} CLIENT_ID, *PCLIENT_ID; 

typedef struct _THREAD_BASIC_INFORMATION 
{ 
    NTSTATUS    ExitStatus; 
    PVOID     TebBaseAddress; 
    CLIENT_ID    ClientId; 
    KAFFINITY    AffinityMask; 
    KPRIORITY    Priority; 
    KPRIORITY    BasePriority; 
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; 

enum THREADINFOCLASS 
{ 
    ThreadBasicInformation, 
}; 

void* GetThreadStackTopAddress(HANDLE hProcess, HANDLE hThread) 
{ 
    bool loadedManually = false; 
    HMODULE module = GetModuleHandle("ntdll.dll"); 

    if (!module) 
    { 
     module = LoadLibrary("ntdll.dll"); 
     loadedManually = true; 
    } 

    NTSTATUS (__stdcall *NtQueryInformationThread)(HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength); 
    NtQueryInformationThread = reinterpret_cast<decltype(NtQueryInformationThread)>(GetProcAddress(module, "NtQueryInformationThread")); 

    if (NtQueryInformationThread) 
    { 
     NT_TIB tib = {0}; 
     THREAD_BASIC_INFORMATION tbi = {0}; 

     NTSTATUS status = NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), nullptr); 
     if (status >= 0) 
     { 
      ReadProcessMemory(hProcess, tbi.TebBaseAddress, &tib, sizeof(tbi), nullptr); 

      if (loadedManually) 
      { 
       FreeLibrary(module); 
      } 
      return tib.StackBase; 
     } 
    } 


    if (loadedManually) 
    { 
     FreeLibrary(module); 
    } 

    return nullptr; 
} 

void __stdcall Test() 
{ 
    for (int i = 0; i < 10; ++i) 
    { 
     printf("Hi. "); 
     Sleep(500); 
    } 
} 


int main() 
{ 
    std::cout<<GetThreadStackTopAddress(GetCurrentProcess(), GetCurrentThread())<<"\n"; 

    DWORD threadID = 0; 
    HANDLE hThread = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(Test), nullptr, 0, &threadID); 
    std::cout<<GetThreadStackTopAddress(GetCurrentProcess(), hThread)<<"\n\n"; 
    CloseHandle(hThread); 
    Sleep(7000); 

    return 0; 
} 
+0

謝謝你,我通過您的代碼閱讀,並注意到在我自己犯了一些錯誤。我的一個無關但重要的錯誤是,我仍然有winternal.h包括在內。當我試圖再次聲明THREADINFOCLASS時,我收到了類型錯誤(因此在我的第一次嘗試中投) 我也注意到NTSTATUS在很多情況下返回0xc000008之前,這應該是我首先檢查的東西...因此顯然,我在從其他進程中得到句柄的方式中也出現了一個錯誤,導致了一堆無效的線程句柄。 謝謝! –