Dynamically loading libraries in an application can lead to vulnerabilities if not secured properly. In this blog post we talk about loading a library using LoadLibraryEx() API and make use of options to make it safe.
Know the defaults:
- The library file name passed to LoadLibrary() / LoadLibraryEx() call need not contain an extension. If one is not specified, then the default library file extension, .DLL, is used. As a result of this feature, if a null is passed as library name it tries to load ".DLL" which could be exploited by placing a ".DLL" in the path searched.
- The library file name passed to LoadLibrary() / LoadLibraryEx() call need not specify a directory path. If one is specified, library is loaded only from the specified path. Otherwise, following default DLL search order is used:
- The current process image file directory, application directory.
- The system directory.
- The 16 bit system directory.
- The windows directory.
- The current working directory.
- The directories listed in the PATH environment variable.
- Windows maintain a list known DLLs, which are basically a set of system DLLs, that are always guaranteed to load from the system directory when absolute name is specified.
- DllMain() function within the loaded library is called after loading the library into memory.
Control the DLL search order:
There are various option to modify the order in which the loading library is searched other than the default search order when absolute name is provided.
Some of the APIs that can influence the DLL search order/path by the LoadLibraryEx() are as below:
- SetDllDirectory() : Adds a directory to the search path used to locate DLLs for the application
- SetDefaultDllDirectories() : Adds a directory to the process DLL search path
- AddDllDirectory() : Adds a directory to the process DLL search path
- RemoveDllDirectory() : Removes a directory that was added to the process DLL search path by using AddDllDirectory()
- SearchPath() : Searches for a specified file in a specified path
- SetSearchPathMode() : Sets the per-process mode that the SearchPath() function uses when locating files
- SetCurrentDirectory() : Changes the current directory for the current process
- DefaultDllImportSearchPathsAttribute : For managed application use this attribute to specify the paths used to search the DLLs during platform invokes
LoadLibraryEx() provide many flags that can be used to alter the default search order. Below table lists most of the flags and also depicts the DLL search order that is followed for each of them. Some of the options even consider the paths set with above mentioned APIs.
Loading library as non-executable:
It is not always required to load a library as an executable image. LoadLibraryEx() makes it possible to load a library as a data file, or an image resource, for example. For this purpose, it supports following different options:
These options helps in treating a file as a normal data file rather as an executable module. Loading with this option doesn't call DLLMain() and none of the memory space of the loaded DLL data is marked as executable.
Blocking the library from loading:
Sometimes it might be required to block a library or block an illegitimate library from loading into an application. Check out following facilities to aid that:
- AppLocker is a policy based mechanism to block DLLs from loading into applications. These policies can be pushed via group policy. AppLocker can control executables, scripts and installers.
- When a new DLL loads, a notification is sent to AppLocker to verify that the DLL is allowed to load. AppLocker calls the Application Identity component to calculate the file attributes. It duplicates the existing process token and replaces those Application Identity attributes in the duplicated token with attributes of the loaded DLL. AppLocker then evaluates the policy for this DLL, and the duplicated token is discarded. Depending on the result of this check, the system either continues to load the DLL or stops the process.
- AppLocker can block the DLL based on path, publisher or file hash.
- Microsoft Authenticode technology can be used to sign the DLL, which is to attach digital signatures to the DLL to guarantee its authenticity and integrity.
To summarize our discussion:
To ensure secure loading of libraries
- Use proper DLL search order.
- Always specify the fully qualified path when the library location is constant.
- Load as data file when required.
- Make use of code signing infrastructure or AppLocker.
Some common attack vectors we see:
- Application directory attacks, especially from the temporary internet or download folder perspective. Particularly when the application is an installer, it is a common thing for people to download the installer into default directory and execute from there. Considering attacker can drop malicious file in the default directory can make use of application directory to load the DLLs. Manifest and .local redirection can also be used in this scenario.
- Loading DLL from memory and also Powershell DLL injection. Which can be used by malwares to keep the loading of a malicious DLL from getting detected.
- TOCTOU attacks when loading library from remote location.
- Swamy Shivaganga Nagaraju, MSRC engineering team