Safe place to put unsafe DLL cleanup code on Windows? - windows

We hit a case where it would be the best solution for us to put a FreeLibrary call into DllMain / DLL_PROCESS_DETACH.
Of course, you must not do that:
It is not safe to call FreeLibrary from DllMain.
The use case is that we have a situation like this:
(unknown client dll or exe) links dynamically or statically to ->
-> DLL_1, loads dynamically -> DLL_x
DLL_1 should load DLL_x transparently wrt. to it's client code, and it should to load DLL_x dynamically. Now, the loading can be done lazily, so that the LoadLibrary call needn't reside in the DLL_PROCESS_ATTACH part of DLL_1.
But once the client is done with DLL_1, when/before DLL_1 is unloaded from the process, it should also unload (== FreeLibrary) DLL_x.
Is there any way to do this without an explicit DLL_1/Uninitialize function that must be called by the client?
I'll note:
DllMain, and thus also any C++ global static destructor cannot be used.
Is there any other callback mechanism in either kernel32/ntdll or maybe in the shared MS CRT to make this happen?
Are there other patterns to make this usecase work?

The correct approach is an explicit Uninitialize function in DLL_1.
However, if you can't do that, you can work around the problem by launching a helper thread to do the unload for you. If you want to play it safe, launch the thread at the same time you load DLL_x and have it wait on an event object. (For the record, though, it is generally considered safe to launch a thread from DllMain so long as you respect the fact that it won't start up until DllMain has exited.)
Obviously, the helper thread's code can't be in DLL_1. If you can modify DLL_x you can put it there. If not, you'll need a helper DLL. In either case, the DLL containing the helper thread's code can safely self-unload using the FreeLibraryAndExitThread function.

Related

Can I explicitly invoke property destructors so that I can see which one causes problems?

I guess this is a really nasty issue - seems like one of the property destructors of my class creates deadlock. Property destructors are called automatically after class destructor. And I'd like to call them manually and make a log entry after every single one succeeds.
The problem only occurs on devices, where debugger can't be used, so I am using log instead.
Client::~Client() {
// Stops io service and disconnects sockets
exit();
LOG("io_service stopped"<<endl);
// Destroy IO service
io_.~io_service();
LOG("io_service destroyed"<<endl);
}
But the code above actually causes exception, because the ~io_service() gets called twice.
So is there a way to do this properly? If not, what's an alternative to debugging destructors?
You can't alter the compiler behaviour like that. the compiler will augment the destructor to destruct nested objects.
What you can do is to declare io as a pointer and allocate it dynamically with new. then call delete io and monitor what happens there.
Other solution is just to put a breakpoint on the io destructor and follow what happens there upon destruction. this is probably the best idea.

Loading/calling ntdll from DllMain

One should not use functions other than those in kernel32.dll from DllMain:
From MS documentation:
Because Kernel32.dll is guaranteed to be loaded in the process address space when the entry-point function is called, calling functions in Kernel32.dll does not result in the DLL being used before its initialization code has been executed. Therefore, the entry-point function can call functions in Kernel32.dll that do not load other DLLs. For example, DllMain can create synchronization objects such as critical sections and mutexes, and use TLS. Unfortunately, there is not a comprehensive list of safe functions in Kernel32.dll.
...
Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.
My question:
But the documentation does not mention ntdll.dll. - Can I call LoadLibrary for "ntdll" and use functions in ntdll from DllMain:
1) during DLL_PROCESS_ATTACH (load and use functions of ntdll)?
2) during DLL_PROCESS_DETACH (use functions of previously loaded ntdll)?
Also, please, would somebody with 1500+ reputation like to create a new tag titled "dllmain" ?
The answer to the question "is it safe in DllMain" always defaults to "no". In this case, calling LoadLibrary is never okay.
Generally speaking, calling anything in ntdll.dll is not recommended even places where it is safe to do so.

A GetModuleHandle implementation

I need to do it this way because I am in DllMain() therefore, loader lock is held. I've read that GetModuleHandle() also uses the loader lock [page #6] which would result in deadlock.
How could GetModuleHandle() implemented? Some code would be a plus.
Update: Since I am using SetWindowsHookEx on WinXP only. Just going to take advice in the comments, go the easy way, and use GetModuleHandle() the first time the callback gets called.
You can call GetModuleHandle from DllMain. It doesn't load any libraries and doesn't increment module reference count. Other story is with LoadLibrary. Never call it from DllMain.

Are COM objects responsible for keeping their own module in memory?

Say you do the following:
1) Load foo.dll using LoadLibrary.
2) Get a pointer to a function using GetProcAddress.
3) Invoke the function, giving you a reference to a COM object implememented in that module.
4) Free foo.dll by calling FreeLibrary.
5) Call a method on the COM object.
Would you expect that step 5 succeeds and doesn't AV? That is, is the COM object itself responsible for calling LoadLibrary (again) to increment the reference count that Windows keeps for each module, ensuring that it doesn't outlive the module?
Certainly not. The module reference count is maintained by the normal methods of use - what you are doing is a backdoor into the runtime scheme. Normally, you use CoCreateInstance and so on to create your objects - these are a wrapper around calling CoGetClassObject and DllGetClassObject. CoGetClassObject calls CoLoadLibrary which maintains a reference count on the dll. Additionally, you can call LockServer on the class object to maintain a reference count on the class object for performance, but this is not required to ensure that the dll remains loaded.
I'd expect an AV. Even if it didn't AV today, this is probably a crash waiting to happen.
For a case like this, where a COM object is returned via a custom DLL export, I would not expect the COM object to increment the reference count of the DLL - as long as the application is using resources from a DLL it explicitly loaded, it's the application's responsibility to keep that DLL loaded.
For in-proc COM objects that are created via the normal CoCreateInstance route, the DLL will typically export DllCanUnloadNow, which should return S_FALSE as long as there are outstanding references.
However, there is nothing preventing the COM object from incrementing the DLL's reference count via LoadLibrary - there is nothing illegal or unsafe about doing so.

Does a DLL get removed if the DLL that loaded it is unloaded?

Take a standard Windows application. It loads a DLL using LoadLibrary to call a function in it (we'll call this DLL_A). That function loads another DLL (we'll call it DLL_B). The application now unloads the DLL_A DLL using FreeLibrary as it no longer requires it.
The question is:
Is DLL_B still in memory and loaded?
Is this something I can depend upon, or is it undocumented?
No. DLL_B will not be unloaded. The LoadLibrary() call made by DLL_A will increment the load count for DLL_B. Since there is no corresponding FreeLibrary() call for DLL_B, the refcount will not go to zero.
From the LoadLibrary() docs:
The system maintains a per-process
reference count on all loaded modules.
Calling LoadLibrary increments the
reference count. Calling the
FreeLibrary or
FreeLibraryAndExitThread function
decrements the reference count. The
system unloads a module when its
reference count reaches zero or when
the process terminates (regardless of
the reference count).
You will have a handle leak in the case:
Program -Load> Dll A
-Load> Dll B
-Unload> Dll A
No code is implicitly executed by a module being unloaded to unload the modules that it loaded.
Since no code is executed to decrease the reference count, the module B will never be unloaded.
Here are the rules for loading / unloading dlls:
Each call to LoadLibrary and LoadLibraryEx will increment the reference count for that module. This is in the context of the calling process only, not across process boundaries.
Each call to FreeLibrary or FreeLibraryAndExitThread will decrement the reference count.
When the reference count reaches 0, it will be unloaded.
When Windows sees that your program is closed, any leaked unloaded modules will then be unloaded.
Depending on what you are doing, DllCanUnloadNow might be useful to you.
Still in memory vs still loaded:
There is no guarantee that your module will be released from memory at a certain time when the reference reaches 0. But you should consider the module as if it is unloaded when the reference count reaches 0.
Stopping the DLL from being unloaded:
To force the DLL from being unloaded you could try
The system calls DllMain with the DLL_PROCESS_DETACH flag. You could try to not return from this via some kind of blocking operation.
You could try to call LoadLibrary from within the DLL that you want to not be able to unload. (Self load)
Edit:
You mentioned your goal is to injet code into the running program and that you wanted to leak the handle on purpose.
That is fine, but if you run this operation a lot it can lead to a crash in your source Program because too many handles will be used, or eventually too much memory will be used.
You can return FALSE from your DllMain to stop it from being loaded so that you don't waste memory. You do this when fdwReason is DLL_PROCESS_ATTACH. You can read more about it here.
If you are trying to emulate a DLL and add in your own extra functionality, you will need to implement all of the functions that the source DLL implements and delegate each call back to the source DLL.
Read the Remarks section for a detailed explanation.
The key thing to note is:
The system maintains a per-process reference count for each loaded module
and further down
When a module's reference count reaches zero or the process terminates, the system unloads the module from the address space of the process
From MSDN:
Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference count reaches zero, the module is unloaded from the address space of the calling process and the handle is no longer valid.
DLLs in windows are reference counted. When A is unloaded you are decrementing the reference count on A, if it hits zero it will unload, and (assuming no bugs in the code) decrement the reference count on B. If the refcount on B goes to zero it will then be unloaded. It is possible DLL C has a refcount on B, and unloading A will not unload B.

Resources