我在C中编写了一个dll,我将CreateRemoteThread()
注入到C控制台程序中。
C程序只调用Sleep(INFINITE)
,基本上充当注入的dll的主机。
这是DllMain:
HINSTANCE thisDllHandle = NULL;
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD entryReason, void *impLoad)
{
switch (entryReason)
{
case DLL_PROCESS_ATTACH:
{
thisDllHandle = hInstance;
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, Boss, NULL, 0, NULL);
if (thread) CloseHandle(thread);
}
}
return TRUE;
}
通过CreateRemoteThread()
创建的线程然后返回,我的Boss线程是运行此dll代码的唯一线程。
如果我告诉Boss退出,在清理之后调用FreeLibraryAndExitThread(thisDllHandle, 0);
- 线程退出但dll仍然在我的主机进程中加载。
在Brandon对here的回答中使用了这个想法,我让主程序告诉我加载了哪些模块并显示模块的GlblcntUsage
和ProccntUsage
。
注入dll后,计数为1.在FreeLibraryAndExitThread()
之后,计数为零 - 但仍然加载了dll!为什么呢?
顺便说一下,如果我改为调用FreeLibrary(thisDllHandle)
,主机程序会崩溃(如预期的那样),但dll会被卸载。
修改
总结我正在尝试做的事情:我正在尝试通过创建一个加载我的dll的远程线程在远程进程中注入一个dll;该DLL生成另一个运行相同dll代码的线程,并且原始线程退出;然后我希望该线程卸载dll并退出。
虽然尝试减少代码以便发布它以回应@David Heffernan的评论,但我设法让它工作 - 通过在调用FreeLibrary
之前调用退出线程调用FreeLibraryAndExitThread
。但是我想明白为什么我必须两次释放它 - 我对这些东西并不是很了解。我不认为这需要代码,因为它非常简单:
LoadLibraryW
的地址。CreateRemoteThread
,将步骤2中的地址作为起始地址传入,将步骤3中的地址作为参数传递。这会导致远程进程中的线程使用LoadLibraryW
加载我的dll。当我的Dll加载时,它启动一个新线程(参见前面的DllMain代码),它在我的dll中运行其他一些函数(这个函数中的内容不重要 - 我可以让它睡10秒然后调用{{1} },行为是一样的)。我远程创建的原始线程在LoadLibraryW返回时死亡。所以现在只有一个线程运行我的dll代码。
当该线程调用FreeLibraryAndExitThread
时,我希望我的dll从远程进程中卸载,因为该线程已释放库并退出。但是dll仍然会被加载,只有释放它两次才能卸载。
答案 0 :(得分:1)
由于你在一个注入的DllMain函数中,并且因为你没有通过调用_endthreadex()函数退出该线程,所以你应该使用CreateThread()而不是_beginthreadex()来启动新线程。避免使用任何 C运行时库函数也是明智之举,特别是如果您无法确保C库与目标进程的C库匹配。
[究竟为什么以及在什么情况下运行时库以所描述的方式表现的行为对我来说并不清楚,但是OP报告说使用CreateThread()纠正了问题。我最好的猜测是它与_onexit()支持有关。]