【问题标题】:Getting the TIB/TEB of a Thread by it's Thread Handle (2015)通过线程句柄获取线程的 TIB/TEB (2015)
【发布时间】:2015-11-24 16:08:26
【问题描述】:

由于http://undocumented.ntinternals.net 上指向此特定问题的大多数链接显然已失效,并且 NtQueryInfoThread 以及相关的 THREADINFOCLASSes 已从 Winternl.h 中消失,所以我现在坐在这里努力寻找我知道的进程的 TEB 句柄. 我尝试从 ntdll.dll 加载该方法,这是另一种似乎可行的解决方案,但遗憾的是我仍然无法获得所需的地址。

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 所说,不应再使用这种方法。)

最好的问候,

亚历克斯

【问题讨论】:

    标签: c++ multithreading memory process handle


    【解决方案1】:

    工作正常:S 获取线程 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;
    }
    

    【讨论】:

    • 谢谢,我通读了您的代码,发现自己的一些错误。我的一个不相关但至关重要的错误是我仍然包含了 winternal.h。当我再次尝试声明 THREADINFOCLASS 时,我收到了类型错误(因此在我的第一次尝试中进行了强制转换),我还注意到 NTSTATUS 在很多情况下都返回了 0xc000008,老实说这应该是我检查的第一件事......所以显然我我从其他进程获取句柄的方式也有错误,导致一堆无效的线程句柄。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2014-09-29
    • 2016-05-08
    • 2023-03-29
    • 2011-07-03
    • 1970-01-01
    • 2022-01-16
    相关资源
    最近更新 更多