cd ../$RANDOM

Make Your Dynamic Module Unfreeable (Anti-FreeLibrary)

1 minute read

Let’s say your product injects a module into a target process, if the target process knows the existence of your module it can call FreeLibrary function to unload your module (assume that the reference count is one). One way to stay injected is to hook FreeLibrary function and check passed arguments every time the target process calls FreeLibrary.

There is a way to get the same result without hooking.

When a process uses FreeLibrary to free a loaded module, FreeLibrary calls LdrUnloadDll which is exported by ntdll:

kernel_ntdll

Inside LdrUnloadDll function, it checks the ProcessStaticImport field of LDR_DATA_TABLE_ENTRY structure to check if the module is dynamically loaded or not. The check happens inside LdrpDecrementNodeLoadCountLockHeld function:

call_stack

ProcessStaticImport_Ghidra

If ProcessStaticImport field is set, LdrpDecrementNodeLoadCountLockHeld returns without freeing the loaded module

struct

So, if we set the ProcessStaticImport field, FreeLibrary will not be able to unload our module:

poc

In this case, the module prints "Hello" every time it attaches to a process, and "Bye!" when it detaches.

Note:

There is an officially supported way of doing the same thing: Calling GetModuleHandleExA with GET_MODULE_HANDLE_EX_FLAG_PIN flag. "The module stays loaded until the process is terminated, no matter how many times FreeLibrary is called." Thanks to James Forshaw

whoami: @_qaz_qaz