Click to See Complete Forum and Search --> : SetEvent not signalling in hooked DLL


indiocolifa
January 6th, 2011, 07:00 PM
I'm doing IPC between an EXE program and a DLL which is injected into another process via SetWindowsHookEx.

The problem is that I want to the DLL to unload when the main EXE quits, I'm doing that in the WM_CLOSE message:


LRESULT MsgClose(HWND hwnd)
{
dprintf(L"Closing.");

SetEvent(g_hQuitEvent);
WaitForSingleObject(g_thRegNotify, INFINITE);
CloseHandle(g_thRegNotify);
CloseHandle(g_hQuitEvent);

UnhookWinEvent(g_hEvtHook);

dprintf(L"Removing mailslot mappings\n");

for (std::map<DWORD,HANDLE>::iterator it = g_mailslotMap.begin();
it != g_mailslotMap.end(); ++it)
{
CloseHandle(it->second);
}

dprintf(L"Unhooking processes...\n");

for (std::set<HHOOK>::iterator it = g_hHookSet.begin();
it != g_hHookSet.end(); ++it)
{
UnhookWindowsHookEx(*it);
}
if (g_hLib32)
FreeLibrary(g_hLib32);



The DLL hook contains a thread that listens for two evetns: mailslot messages and the quit event with WaitForMultipleObjects:


do
{
OVERLAPPED ov;
ZeroMemory(&ov,sizeof(ov));

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
ov.hEvent = hEvent;

if (!ReadFile(g_hMailSlot, &ipcMsg, sizeof(IPCMESSAGE), 0, &ov))
{
if (GetLastError() != ERROR_IO_PENDING)
{
dprintf(L" ReadFile FAILED with error %d\n",GetLastError());
bContinue = FALSE;
rv = GetLastError();
}
}

HANDLE waitEvents[2] = { hEvent, g_hQuitEvent };
DWORD wo = WaitForMultipleObjects(2, waitEvents, FALSE, INFINITE);

if (wo - WAIT_OBJECT_0 == 1)
{
dprintf(L" (mailslot thread) Quit event signaled.\n");
bContinue = FALSE;
}
else
{
// Process mailslot message
...
...
...


At DLL exit I perform:


if (g_hMailSlot && g_hMailSlotThread)
{
SetEvent(&g_hQuitEvent);
WaitForSingleObject(g_hMailSlotThread, INFINITE);
CloseHandle(g_hMailSlotThread);
}

dprintf(L" Mailslot thread terminated.\n");



If I close the process that the DLL resides in, the g_hQuitEvent is signalled properly. But not when hooking is removed via closing the main EXE.

Any idea as where I can look? The thread awaits at the WaitForSingleObject line marked above, halting the hosting EXE.

Thanks in advance.

Codeplug
January 6th, 2011, 08:08 PM
You can't wait on a thread handle while in the context of DllMain. The state of the thread handle will never change while the loader lock is being held. This includes global object constructors and destructors.

http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx

gg

indiocolifa
January 6th, 2011, 10:11 PM
Thank you very much Codeplug.

I removed the fatal calls from DllMain, but i'm still with the problem of how the following can be achieved:

1) External EXE posts a (e.g: DLL_UNLOAD_REQUEST) message to a known mailslot.
2) The injected DLL receives the mailslot message in a worker thread.
3) This DLL must do something to finalize this worker thread. If this not succeeds, the injected process won't exit later since the DLL contains a WaitForSingleObject call on process exit. The intention is to unload the DLL without killing the hosting process, when the external EXE is closed (I handle WM_CLOSE).

I've devised some synchronization scheme as follows:

- EXE sends request to unload DLL and waits for some signal to continue safely (prior to UnhookWindowsHookEx) -- eg: wait on a global "\\SafeToUnload" named event or a message posted to it's queue (alternatives?).

- Worker thread in injected DLL finalizes itself (preventing locking process waiting for it's thread handle) and signals the event / sends message to EXE app queue to notify that the thread has exited.

- Now main EXE can safely go with UnhookWindowsHookEx.

Ideas?

EDIT: The problem is that when the EXE is running without injected DLLs (this is possible). Termination will lock on waiting for some injected DLL to set the event. I'm sure this can be solved with an array of events for each injected DLL handle. If no injected DLLs = no events available, exits normally.

indiocolifa
January 6th, 2011, 10:57 PM
Solved. :)