Deadlock in dll detach

c++ / delphi package - dll injection and api hooking
Post Reply
EaSy
Posts: 150
Joined: Tue Oct 23, 2012 12:33 pm

Deadlock in dll detach

Post by EaSy »

Hi Madshi,
one more thank you for your explanation about how MCH works. I have a question about safe uninjection.
madshi wrote: 1) madCodeHook has a feature called "safe unhooking" and "safe uninjection". This feature works like this: In the moment when you uninject your hook dll, madCodeHook tries to *first* unhook all APIs, before unloading your hook dll. Only after all hooks were successfully uninstalled, FreeLibrary is called. This logic makes sure that all the dirty work is done outside of DllMain, to avoid deadlocks. For every hooked API, madCodeHook first uninstalls the hook, and then it checks whether the hook is still "in use". E.g. if GetOpenFileNameW is hooked, but one of the running threads is still "inside" of GetOpenFileNameW (meaning, GetOpenFileNameWHook is in the callstack of a thread), madCodeHook enters a Sleep() loop and waits until that is no longer the case. Only then the hook installation is considered "complete". This logic results in DLL uninjection sometimes being delayed, sometimes even stuck. But it's an important feature to make uninjection as stable as possible.
We have a situation like this:

Code: Select all

0:000:x86> ~* kb

.  0  Id: 2a94.468c Suspend: 0 Teb: 7efdb000 Unfrozen
ChildEBP RetAddr  Args to Child              
0018f43c 77998e44 00000148 00000000 00000000 ntdll_77960000!ZwWaitForSingleObject+0x15
0018f4a0 77998d28 00000000 00000000 7798faa4 ntdll_77960000!RtlpWaitOnCriticalSection+0x13e
0018f4c8 7798fff3 77a620c0 6f47335e 77997da3 ntdll_77960000!RtlEnterCriticalSection+0x150
0018f638 7798fd4f 00000001 00000000 00000000 ntdll_77960000!LdrGetDllHandleEx+0x2f7
0018f654 56548e76 00000000 00000000 0018f6d8 ntdll_77960000!LdrGetDllHandle+0x18
0018f670 56549706 0018f6d8 77997da3 00000000 STGuard32!GetModuleHandleEx+0x26 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 648]
0018f6ac 71a5003b 002f932c 0018f6f0 0018f6d8 STGuard32!LdrLoadDllCallbackProc+0x46 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 687]
WARNING: Frame IP not in any known module. Following frames may be wrong.
0018f6e8 76d1aac3 00000000 00000000 002f932c 0x71a5003b
0018f828 7797010a 0018f840 00000000 0018ffc4 user32!__ClientLoadLibrary+0x66
0018f868 76d1a8e8 00000000 0000c03b 0000c03b ntdll_77960000!KiUserCallbackDispatcher+0x2e
0018fb14 76d1aa3c 00000000 0000c03b 0018fbb0 user32!VerNtUserCreateWindowEx+0x1a9
0018fbc8 76d18a5c 00000000 0000c03b 0018fbb0 user32!_CreateWindowEx+0x210
0018fc04 76ee644f 00000000 0000c03b 76ee6470 user32!CreateWindowExW+0x33
0018fc3c 76ee650c 76fe6b04 76fe7724 00000002 ole32!InitMainThreadWnd+0x3e [d:\w7rtm\com\ole32\com\objact\mainthrd.cxx @ 160]
0018fc54 76ee0b81 00000000 00000002 00000000 ole32!wCoInitializeEx+0xef [d:\w7rtm\com\ole32\com\class\compobj.cxx @ 2437]
0018fc74 76ebed55 00000002 00000002 7efde000 ole32!CoInitializeEx+0x29d [d:\w7rtm\com\ole32\com\class\compobj.cxx @ 2110]
0018fc8c 76ebefe6 00000000 00000002 00000000 ole32!OleInitializeEx+0x12 [d:\w7rtm\com\ole32\ole232\base\ole2.cpp @ 245]
*** ERROR: Module load completed but symbols could not be loaded for setup - Universal - safetica 6.0.0 updater - 2015-02-22.exe
0018fc9c 00403420 00000000 00000000 00000000 ole32!OleInitialize+0xf [d:\w7rtm\com\ole32\ole232\base\ole2.cpp @ 195]
00000000 00000000 00000000 00000000 00000000 setup___Universal___safetica_6_0_0_updater___2015_02_22+0x3420

   1  Id: 2a94.4710 Suspend: 0 Teb: 7efd8000 Unfrozen
ChildEBP RetAddr  Args to Child              
00a6f348 75853bd5 00000000 00a6f38c 1fb7ffa1 ntdll_77960000!ZwDelayExecution+0x15
00a6f3b0 758544a5 000001f4 00000000 00a6f968 KERNELBASE!SleepEx+0x65
00a6f3c0 56550a9a 000001f4 56615b88 00000000 KERNELBASE!Sleep+0xf
00a6f968 56550c4f 024893b8 00a6f9d0 56548624 STGuard32!CCodeHook::~CCodeHook+0x5fa [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\ccodehook.cpp @ 1055]
00a6f974 56548624 00000001 56615b88 00000000 STGuard32!CCodeHook::`scalar deleting destructor'+0xf
00a6f9d0 565497d3 56614a90 00000001 00000001 STGuard32!UnhookInternal+0x1a4 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 439]
00a6f9e4 56548641 00000001 56615b88 00000000 STGuard32!UnhookLoadLibrary+0x43 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 867]
00a6fa40 56547e61 56614f60 00000000 00000001 STGuard32!UnhookInternal+0x1c1 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 443]
00a6fa54 564d8a2f 56614f60 00000000 56470000 STGuard32!UnhookAPI+0x21 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 187]
00a6fa6c 564d76a2 00000000 00000000 00000000 STGuard32!DCCInjectionDll::Destroy+0x7f [s:\5.5.11\discryptor\client service\modules\injectiondll\injectiondll.cpp @ 598]
00a6fa80 5656ef7c 56470000 00000000 00000000 STGuard32!DllMain+0x112 [s:\5.5.11\discryptor\client service\modules\injectiondll\injectiondll.cpp @ 110]
00a6fac4 5656f036 56470000 00a6faf0 779999a0 STGuard32!__DllMainCRTStartup+0x7a [f:\dd\vctools\crt_bld\self_x86\crt\src\crtdll.c @ 512]
00a6fad0 779999a0 56470000 00000000 00000000 STGuard32!_DllMainCRTStartup+0x1e [f:\dd\vctools\crt_bld\self_x86\crt\src\crtdll.c @ 476]
00a6faf0 779bad1e 5656f018 56470000 00000000 ntdll_77960000!LdrpCallInitRoutine+0x14
00a6fb78 779a12d1 56470000 00a6fb9c 6ff93eda ntdll_77960000!LdrpUnloadDll+0x375
00a6fbbc 75852d2c 56470000 00000248 00a6ff88 ntdll_77960000!LdrUnloadDll+0x4a
*** WARNING: symbols timestamp is wrong 0x4ce7c496 0x4ce7b73e for apphelp.dll
00a6fbcc 71af01fe 56470000 00000000 00000000 KERNELBASE!FreeLibrary+0x15
00a6ff88 76a7338a 71b00000 00a6ffd4 77999f72 apphelp!___PchSym_ <PERF> (apphelp+0x501fe)
00a6ff94 77999f72 71b00000 6ff93ab2 00000000 kernel32!BaseThreadInitThunk+0xe
00a6ffd4 77999f45 71af0000 71b00000 00000000 ntdll_77960000!__RtlUserThreadStart+0x70
00a6ffec 00000000 71af0000 71b00000 00000000 ntdll_77960000!_RtlUserThreadStart+0x1b
How is it possible, that the hook STGuard32!LdrLoadDllCallbackProc is still hooked while the function STGuard32!DllMain is called?

Thx, PP.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Deadlock in dll detach

Post by madshi »

This hook is automatically uninstalled when the last API hook is uninstalled. And all API hooks should be uninstalled when your dll is uninjected. I suppose we're talking about the situation where your hook dll's DllMain is called with PROCESS_DETACH, after you called UninjectLibrary? Is that correct? Do you happen to have access to the list of madCodeHook HookItems at that point in time? I would guess that that list is not empty, for whatever weird reason. Maybe this could have the same cause as the other issue you reported?
EaSy
Posts: 150
Joined: Tue Oct 23, 2012 12:33 pm

Re: Deadlock in dll detach

Post by EaSy »

Well, the g_pHookCollection is empty.

Code: Select all

0:001:x86> x STGuard32!g_pHookCollection
56614a84          STGuard32!g_pHookCollection = 0x02484c48
0:001:x86> dt STGuard32!g_pHookCollection
0x02484c48 
   +0x000 mpArray          : 0x0249efd0 tagHookItem
   +0x004 mCount           : 0n0
   +0x008 mSize            : 0n64
   +0x00c mSizeFixed       : 0
So you are right, the last unhook called by STGuard caused this and it was CoCreateInstanceHook.
But why there were still some of the hook active?

Code: Select all

0:001:x86> .frame 7
07 00a6fa40 56547e61 STGuard32!UnhookInternal+0x1c1 [c:\prace\svn\tag\5.5.0.11\common\libraries\madcodehook\sources\c++\hooking.cpp @ 443]
0:001:x86> dv
            pCodeHook = 0x02489360
        unhookHelpers = true
            pNextHook = 0x56614f60
dontUnhookHelperHooks = 0n0
                 wait = 0n1
               result = 0n1
0:001:x86> dd 0x56614f60
56614f60  76ee9d0b 02556fd8 00000000 00000001
56614f70  00000000 00000000 00000000 00000000
56614f80  00000000 00000000 00000000 00000000
56614f90  00000000 00000000 00000000 00000000
56614fa0  00000000 00000000 00000000 00000000
56614fb0  00000000 00000000 00000000 00000000
56614fc0  00000000 00000000 00000000 00000000
56614fd0  00000000 00000000 00000000 00000000
0:001:x86> ln 76ee9d0b
d:\w7rtm\com\ole32\com\objact\actapi.cxx(96)
(76ee9d0b)   ole32!CoCreateInstance   |  (76ee9d4e)   ole32!CoCreateInstanceEx
Exact matches:
    ole32!CoCreateInstance (struct _GUID *, struct IUnknown *, unsigned long, struct _GUID *, void **)
Is it possible that while MCH was unhooking functions, CheckHook have been concurently called and reinstalled all the hooks again? Or something like this?
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Deadlock in dll detach

Post by madshi »

What do you mean with "the last unhook called by STGuard caused this"? Caused what? And why does STGuard call any unhooks at all? Normally madCodeHook should do that automatically when you call UninjectLibrary. CheckHooks only installs hooks which are in the "hook collection". If there are none there, CheckHooks does nothing.
EaSy
Posts: 150
Joined: Tue Oct 23, 2012 12:33 pm

Re: Deadlock in dll detach

Post by EaSy »

Well, we unhook only if the DLL main lpReserved is 0, so we unhook only if process is not terminating. Still your code somehow failed to unhook all hooked functions before dllmain.If we don't unhook it by ourselves it will cause a crash, because some of the them are still active... Any idea what happened? Why the hooks were still active? Can CheckHooks misbehave also in this case?
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Deadlock in dll detach

Post by madshi »

Hmmmm... Are you sure that it's UninjectLibrary() which has resulted in this problem? Is it possible that your hook dll might have been unloaded by some other means?

I'm not sure if CheckHooks() can cause this problem, too. I guess it's possible.

How often do you get this deadlock in dll detach? Can you reproduce it?
EaSy
Posts: 150
Joined: Tue Oct 23, 2012 12:33 pm

Re: Deadlock in dll detach

Post by EaSy »

The latest version of MCH fixed the issue.

In the previous MCH version the AutoUnhook function has been called with hModule = NULL instead of right value due to compiler optimizations. It has nothing to do with the CheckHooks issue. So we can close this one.
Thx.

PP
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Deadlock in dll detach

Post by madshi »

Great - I'm quite happy to hear that! :D
Post Reply