Make Your Dynamic Module Unfreeable (Anti-FreeLibrary)
/
When your product injects a module into a target process, the target process can call the FreeLibrary function to unload your module, assuming the reference count is one.
One way to remain injected is to hook the FreeLibrary function and check the arguments passed each time the target process calls it. However, there is an alternative method that does not require hooking.
When a process uses FreeLibrary to free a loaded module, it calls LdrUnloadDll, which is exported by ntdll:
Inside the LdrUnloadDll function, it checks the ProcessStaticImport field of the LDR_DATA_TABLE_ENTRY structure to determine if the module is dynamically loaded.
This check occurs within the LdrpDecrementNodeLoadCountLockHeld function:
If the ProcessStaticImport field is set, LdrpDecrementNodeLoadCountLockHeld returns without freeing the loaded module.
By setting the ProcessStaticImport field, FreeLibrary will be unable to unload our module:
In this scenario, the module prints "Hello" every time it attaches to a process and "Bye!" when it detaches.
Note: There is an officially supported method to achieve similar results: calling GetModuleHandleExA with the GET_MODULE_HANDLE_EX_FLAG_PIN flag. This ensures that the module remains loaded until the process is terminated, regardless of how many times FreeLibrary is called.
Thanks to James Forshaw for the insights.