Wednesday, October 16, 2019

DLL Entry-Point Function

DLL Entry-Point Function

BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID fImpLoad)

It is not required to implement DllMain. If DllMain is not present, the DLL will still link but no entry function will be called. 

fImpLoad (aka lvpReserved) is nonzero if DLL implicitly loaded (static load) and 0 when explicitly loaded (dynamic load). 
hInstDll identifies the virtual memory address where DLL's file image was mapped into the process space
fdwReason indicates why system is calling the function 

Remember that DLLs use DllMain to initialize themselves. Avoid calling other functions imported from other DLLs inside DllMain since they might not have been initialized yet. 

Also avoid calling LoadLibrary(Ex) and FreeLibrary from DllMain because dependency loops. 
Also avoid calls to User, Shell, ODBC, COM, RPC, socket functions. 

Constructor/Destructor for global/static C++ objects is called at the same time as DllMain function. 

DLL_PROCESS_ATTACH

System passes this as fdwReason only when Dll is first mapped. A thread that calls LoadLibrary(Ex) on this same Dll that has already been mapped to proc address space will not cause DllMain to be called again with DLL_PROCESS_ATTACH.

System only cares about the return value of DllMain when passed DLL_PROCESS_ATTACH. Return true if initialization is successful. 

The process primary thread calls each of the DLL's DllMain functions that the process needs. If any return FALSE, then proc is terminated. 

When DLL is load explicitly, the system will not terminate proc if LoadLibrary(Ex) fails. It will just unmap DLL file and return NULL. 

DLL_PROCESS_DETACH

When DLL is unmapped from process space, system calls DllMain with DLL_PROCESS_DETACH (assuming DLL did not return FALSE when initially called with DLL_PROCESS_ATTACH). 

Primary thread usually makes this call, but if thread called FreeLibrary or FreeLibraryAndExitThread then that thread executes this call. 

OS kills proc only after DLL completes DLL_PROCESS_DETACH notification. 

If a thread calls TerminateProcess, DLL does not get a chance to DLL_PROCESS_DETACH :( 


DLL_THREAD_ATTACH

When process creates a thread, system examines all DLL files currently mapped into proc address space, and calls each DllMain with DLL_THREAD_ATTACH. The new thread is responsible for executing these calls. 

System only makes this call for new threads, not for existing threads. 

DLL_THREAD_DETACH


System does not immediately kill a thread that calls ExitThread. System calls all the mapped DLL's DllMain's functions with DLL_THREAD_DETACH on the thread that wants to die. 

System does not get to make this call when TerminateThread :(

System does not call DLL_THREAD_DETACH for threads that are currently running when DLL is detached. 

Serialized Calls to DllMain

Calls to DllMain are serialized. That means if we call CreateThread in the DLL_PROCESS_ATTACH of one thread, the system suspends the new thread until the current DLL returns from DllMain. Do not try to wait for thread while in PROCESS_ATTACH code because the system will not resume that thread until DllMain is finished. 

DisableThreadLibraryCalls will not solve this problem. Do not call WaitForSingleObject inside and DllMain function. 

(DisableThreadLibraryCalls tells the system that we do not want DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications sent to the specified DLL's  DllMain)


C/C++ Run-Time Library

Linker embeds address of DLL's entry-point function in resulting DLL file image. 
Specify address of function with linker's /ENTRY switch. 

MSFT linker assumes _DllMainCRTStartup is the entry function (a statically linked function from C/C++ run time library)

_DllMainCRTStartup initializes C/C++ run time library and then calls your DllMain. 

If the linker cannot find a DllMain function in DLL .obj files, it will link the DllMain from C/C++ run-time library. 

Sources

Windows via C/C++ - J. Richter 2008 Chapter 20

No comments:

Post a Comment