在Win32进程中运行的第一个线程是"主线程"吗?需要理解语义
-
13-12-2019 - |
题
我创建一个进程使用 CreateProcess()
与 CREATE_SUSPENDED
然后继续在远程进程中创建一小段代码来加载一个DLL并调用一个函数(由该DLL导出),使用 VirtualAllocEx()
(与 ..., MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE
), WriteProcessMemory()
, ,然后打电话 FlushInstructionCache()
在那块带有代码的内存上。
之后我打电话 CreateRemoteThread()
要调用该代码,请为我创建一个 hRemoteThread
.我已经验证了远程代码按预期工作。 注: 此代码只是返回,它不调用任何Api以外 LoadLibrary()
和 GetProcAddress()
, ,然后调用导出的存根函数,该函数当前只是返回一个值,然后将作为线程的退出状态传递。
现在是特殊的观察:请记住, PROCESS_INFORMATION::hThread
仍被暂停。当我简单地忽略 hRemoteThread
的退出代码,也不要等待它退出,一切都"好"。调用的例程 CreateRemoteThread()
申报表及 PROCESS_INFORMATION::hThread
得到恢复和(远程)程序实际上得到运行。
但是,如果我打电话 WaitForSingleObject(hRemoteThread, INFINITE)
或者执行以下操作(具有相同的效果):
DWORD exitCode = STILL_ACTIVE;
while(STILL_ACTIVE == exitCode)
{
Sleep(500);
if(!GetExitCodeThread(hRemoteThread, &exitCode))
break;
}
其次是 CloseHandle()
这导致 hRemoteThread
整理前 PROCESS_INFORMATION::hThread
得到恢复和过程简单地"消失"。这足以允许 hRemoteThread
以某种方式完成 PROCESS_INFORMATION::hThread
使过程死亡。
这看起来可疑地像比赛条件,因为在某些情况下 hRemoteThread
可能仍然更快,并且该过程可能仍然"消失",即使我将代码保留为原样。
这是否意味着在进程中运行的第一个线程自动成为主线程,并且该主线程有特殊的规则?
我总是觉得一个进程在最后一个线程死亡时结束,而不是在一个 特别是 线死亡。
另请注意: 没有电话要 ExitProcess()
以任何方式卷入这里,因为 hRemoteThread
简单地返回和 PROCESS_INFORMATION::hThread
在我等待的时候仍然暂停 hRemoteThread
返回。
这发生在Windows XP SP3,32位。
编辑: 我刚刚尝试过Sysinternals Process Monitor来查看发生了什么,我可以验证我以前的观察结果。注入的代码不会崩溃或任何事情,相反,我会看到,如果不等待线程,它不会在关闭代码注入的程序之前退出。我在想电话是不是 CloseHandle(hRemoteThread)
应该推迟什么的。..
编辑+1: 不是的 CloseHandle()
.如果我只是为了测试而忽略它,那么在等待线程完成时,行为不会改变。
解决方案
运行的第一个线程并不特别。
例如,创建一个控制台应用程序,它创建一个挂起的线程并终止原始线程(通过调用ExitThread)。此过程永远不会终止(无论如何在Windows7上)。
或者让新线程等待五秒钟然后退出。正如预期的那样,进程将存活五秒钟,并在辅助线程终止时退出。
不知道你的例子发生了什么。避免竞争的最简单方法是使新线程恢复原始线程。
现在推测,我想知道你所做的事情是否不太可能引起问题。例如,所有的 DllMain
调用隐式加载的Dll?它们是否意外地发生在错误的线程上,它们是否被跳过,或者它们是否被推迟到您的代码运行并且主线程启动之后?
其他提示
赔率是好的,线程与 main
(或等效)函数调用 ExitProcess
(显式或在其运行时库中)。 ExitProcess
, ,那么,退出整个进程,包括杀死所有线程。由于主线程不知道您注入的代码,因此它不会等待它完成。
不知道有一个很好的方法可以让主线程等待你的完成。..