I've written a dll in C which I'm injecting via CreateRemoteThread()
into a C console program.
The C program simply calls Sleep(INFINITE)
, basically acting as a host for the injected dll.
This is 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;
}
The thread created via CreateRemoteThread()
then returns, and my Boss thread is the only thread running this dll's code.
If I then tell Boss to exit, after cleaning up it calls FreeLibraryAndExitThread(thisDllHandle, 0);
- the thread exits but the dll remains loaded in my host process.
Using the idea in the answer by Brandon over here, I made the host program tell me what modules are loaded and show the GlblcntUsage
and ProccntUsage
of the module.
After injecting the dll, the counts are 1. After FreeLibraryAndExitThread()
, the counts are zero - but the dll is still loaded! Why?
Incidentally, if I call FreeLibrary(thisDllHandle)
instead, the host program crashes (as expected) but the dll gets unloaded.
EDIT
To summarise what I'm trying to do: I'm trying to inject a dll in a remote process by creating a remote thread that loads my dll; that dll spawns another thread which runs the same dll's code and sticks around, and the original thread exits; I then want that thread to unload the dll and exit.
Whilst trying to reduce the code in order to post it in response to @David Heffernan's comment, I managed to get it to work - by making the exiting thread call FreeLibrary
before calling FreeLibraryAndExitThread
. However I'd like to understand why I had to free it twice - I don't really know much about this stuff. I don't think this requires code as it's quite straightforward:
- Get handle to remote process.
- Get address of
LoadLibraryW
in own kernel32 module. - Allocate memory in remote process, write [path to dll] to said memory.
- Call
CreateRemoteThread
on remote process handle, passing in address from step 2 as start address, and address from step 3 as parameter.
This causes the thread in the remote process to load my dll using LoadLibraryW
. When my Dll is loaded, it kicks off a new thread (see DllMain code earlier) which runs some other function in my dll (the content in this other function is unimportant - I can make it sleep 10 seconds and then call FreeLibraryAndExitThread
, and the behaviour is the same). The original thread I created remotely dies as LoadLibraryW returns. So now there is only one thread running my dll's code.
When that thread calls FreeLibraryAndExitThread
, I expect my dll to get unloaded from the remote process, as the thread has freed the library and exited. But the dll remains loaded, and only by freeing it twice does it unload.