0

I used to unload an injected library by calling FreeLibraryAndExitThread from a thread that was created using CreateThread.

The need to unload the library from a different thread rendered this approach impossible. Now I'm using TerminateThread (as it doesn't terminate the thread it's called from, but the one that is passed) and FreeLibrary separately. However as the WinAPI docs suggest this creates a "race condition" and crashes the process. Is there any way to fix this?

Old code:

HMODULE g_hModule{ NULL };

BOOL WINAPI DllMain(HMODULE hModule, DWORD fwdReason, LPVOID lpReserved) {
    g_hModule = hModule;
    if (fwdReason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)main, 0, 0, 0);
    }

    return TRUE;
}

void Unload(int nExitCode) {
    FreeLibraryAndExitThread(g_hModule, (DWORD)nExitCode);
}

New code:

HMODULE g_hModule{ NULL };
HANDLE g_hThread{ NULL };

BOOL WINAPI DllMain(HMODULE hModule, DWORD fwdReason, LPVOID lpReserved) {
    g_hModule = hModule;
    if (fwdReason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);
        g_hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)main, 0, 0, 0);
    }

    return TRUE;
}

void Unload(int nExitCode) {
    TerminateThread(g_hThread, (DWORD)nExitCode);
    FreeLibrary(g_hModule);
}

Thanks in advance for any help!

CredixYt
  • 13
  • 3
  • Does this answer your question? [Kill a running thread](https://stackoverflow.com/questions/10737417/kill-a-running-thread) In any case, search for "[c++] terminate thread" here and you will find lots of info. Understand the implications of terminating a thread before pursuing this path any further. – Ulrich Eckhardt Dec 25 '20 at 21:21
  • Short answer: no there isn't. C++ does not work this way. Thread termination via any means other than returning from the original thread function is undefined behavior. `TerminateThread` does not have well-defined behavior with C++ code. It is not meant to be used with C++ code. – Sam Varshavchik Dec 25 '20 at 21:22
  • new code wrong in all case and senseless. `TerminateThread` - you terminate the **self** thread. `FreeLibrary` is never called. no sense create thread for just terminate it (even not exit correct). old code is look like correct (assume `main == Unload` and wrong signature for unload) – RbMm Dec 25 '20 at 21:25
  • in the old code `Unload` is called from `main` (the thread created by `CreateThread`) in the new one it is called from a separate thread. this is why i believe `FreeLibrary` should run – CredixYt Dec 25 '20 at 21:37
  • `ULONG WINAPI Unload(PVOID) { FreeLibraryAndExitThread((HMODULE)&__ImageBase, 0);` and `CreateThread(0, 0, Unload, 0, 0, 0);` this is how code need look like – RbMm Dec 25 '20 at 22:06

1 Answers1

1

The only way to terminate a thread safely, in C++ especially, is to have that thread return from the function passed to CreateThread. This is usually done by setting (say) an atomic<bool> that the thread tests regularly to see if it should exit. You might also use a condition variable (or the Win32 equivalent) to wake the thread up, rather than busy-looping.

TerminateThread is deadly dangerous as, for example, the thread might be holding some kind of critical lock (perhaps the one used by malloc) at the time and that would hang the rest of your app. It should never have been provided in the Win32 API in the first place and you should not use it.

Paul Sanders
  • 15,937
  • 4
  • 18
  • 36