2009-12-28 597 views
10

我在一些小的测试应用程序中创建了一个附加线程,并且想要暂挂这个附加线程的主线程。附加线程通过CreateRemoteThread从外部进程创建。获取进程主线程的句柄

由于SuspendThread需要一个HANDLE到应该被挂起的线程,我想知道如何从运行在我的附加线程中的代码获得这个HANDLE

+0

什么是你的目标平台? – 2009-12-28 14:03:17

+0

这是Windows 7下的一个32位程序。我使用Visual Studio 2008,因此使用Visual C++。 – Etan 2009-12-28 14:09:00

+0

你只想暂停“主”线程还是全部?你究竟想达到什么目的?它可能有另一种方式来做到这一点...... – cedrou 2009-12-28 14:14:01

回答

6
DWORD GetMainThreadId() { 
    const std::tr1::shared_ptr<void> hThreadSnapshot(
     CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0), CloseHandle); 
    if (hThreadSnapshot.get() == INVALID_HANDLE_VALUE) { 
     throw std::runtime_error("GetMainThreadId failed"); 
    } 
    THREADENTRY32 tEntry; 
    tEntry.dwSize = sizeof(THREADENTRY32); 
    DWORD result = 0; 
    DWORD currentPID = GetCurrentProcessId(); 
    for (BOOL success = Thread32First(hThreadSnapshot.get(), &tEntry); 
     !result && success && GetLastError() != ERROR_NO_MORE_FILES; 
     success = Thread32Next(hThreadSnapshot.get(), &tEntry)) 
    { 
     if (tEntry.th32OwnerProcessID == currentPID) { 
      result = tEntry.th32ThreadID; 
     } 
    } 
    return result; 
} 
+0

是否保证进程的“主”线程始终是快照中的第一个线程?另外,问题不在于如何确定主线程;这是关于如何得到一个句柄,这个答案忽略。 – 2010-07-14 14:00:07

+5

甚至没有保证进程的“主”线程仍然存在!该进程的主线程可能已经完成了'ExitThread'。 – 2011-11-09 00:20:14

2

这种类型的许多有用的API函数都在(当然是!)Tool Help套件下。 CreateToolhelp32Snapshot() API将为指定的进程拍摄正在运行的线程的快照。

// Take a snapshot of all running threads 
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 
if(hThreadSnap == INVALID_HANDLE_VALUE) 
    return(FALSE); 

完整的示例代码here.

的结构返回不区分与其他主线程。我不知道这样做的机制;而一些版本的C运行时将在主线程结束时全部使用ExitProcess(),在所有最新版本中,进程将继续运行,直到最后一个线程退出。

Interjay建议使用GetThreadTimes可能是最好的选择。如果您可以CreateProcess()目标进程,则PROCESS_INFORMATION块的hThread成员包含主线程的tid。欢迎来自他人的任何想法。

+0

我想知道像OllyDbg这样的软件如何找出“主线程”是什么。您也可以使用它附加到已经运行的进程。 – Etan 2009-12-28 16:38:58

+0

DebugActiveProcess() - http://msdn.microsoft.com/en-us/library/ms679295%28VS.85%29.aspx GetThreadContext()返回“当前线程上下文”的寄存器,但不区分主我知道的线程。 – 2009-12-28 21:20:30

3

你为什么不只是创建一个计划范围的全球性(使用extern如果你有)

HANDLE mainThread ; 
DWORD mainThreadId ; 

在主的第一行,(在创建任何线程之前)做

mainThread = GetCurrentThread() ; 
mainThreadId = GetCurrentThreadId() ; 

您可以使用any form of IPC共享所述1D或与远程进程的句柄(未验证共享手柄会工作,但它应该!)

+0

为什么在main而不是简单的'HANDLE mainThread = GetCurrentThread()'? – Liviu 2014-06-17 14:01:57

+0

也问在这里:http://stackoverflow.com/questions/13287963/id-of-main-thread-in-c – Liviu 2014-06-17 14:08:16

+1

根据'GetCurrentThread()'的文档,它返回一个伪句柄,而不是句柄,所以使用它进行比较,我不会假设。 – Pol 2016-07-06 03:01:04

6

获取线程ID使用此项功能:

/* CAUTION: ONLY x86 TESTED 
* get the thread id of the main thread of a target process 
* 
* params: 
*  DWORD dwPid process id of the target process 
* 
* return: 
*  Success  thread id 
*  Error  NULL 
*/ 
DWORD GetMainThreadId(DWORD dwPid) 
{ 
    LPVOID lpTid; 

    _asm 
    { 
     mov eax, fs:[18h] 
     add eax, 36 
     mov [lpTid], eax 
    } 

    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwPid); 
    if(hProcess == NULL) 
     return NULL; 

    DWORD dwTid; 
    if(ReadProcessMemory(hProcess, lpTid, &dwTid, sizeof(dwTid), NULL) == FALSE) 
    { 
     CloseHandle(hProcess); 
     return NULL; 
    } 

    CloseHandle(hProcess); 

    return dwTid; 
} 

简单的开线程获取句柄:

/* 
* get a handle to the main thread of a target process 
* if successfull, the returned handle must be closed with CloseHandle() 
* 
* params: 
*  DWORD dwPid    process id of the target process 
*  DWORD dwDesiredAccess desired access rights to the thread 
* 
* return: 
*  Success  thread handle with desired access rights 
*  Error  NULL 
*/ 
HANDLE GetMainThreadHandle(DWORD dwPid, DWORD dwDesiredAccess) 
{ 
    DWORD dwTid = GetMainThreadId(dwPid); 
    if(dwTid == FALSE) 
     return NULL; 

    return OpenThread(dwDesiredAccess, FALSE, dwTid); 
} 
+2

我不相信这会在各种环境下完美运作。具体来说,假设Tib地址在所有机器上的每个进程中都是相同的,甚至GetMainThreadId()的调用者都是主线程,对吧?你应该解释它是如何工作的,因为它有太多可疑的事情要问。 – Laie 2015-06-26 01:31:25

+0

这真棒,但我试图使一个功能与32位和64位兼容 – Acidic 2017-09-19 06:29:07