There is a sub-technique of MITRE for injecting DLLs, called DLL Hijacking. And in this post you will find a theoretical explanation and a simple proof of concept, with a C++ programmed DLL that opens the Windows calculator in case of a successful injection.
Bulletins and reports like this one are published every week on Twitter of the ISH Threat Intelligence group, the Heimdall. Keep up with us there!
Dynamic-link library, or DLL, is Microsoft's implementation of the concept of shared libraries. These are modules that contain functions that can be used by other executables. The idea is that developers do not have to reinvent the wheel to use basic operating system functions such as reading files, creating sockets for connecting to the Internet, etc. The system DLLs provide ready-made code for these functions (APIs) and the executable in question only imports those that are relevant.
Loading Modules into a Process
Every program that is to be executed receives a set of memory resources necessary for its operation. We call this set of resources a process. A crucial part of the initialization of any process is the import of all the DLLs specified in the executable.
The image below provides an example of the import information contained in such a file.
Importing all these modules is the responsibility of Image Loadercomponent of ntdll.dll (this module is essential for the startup of all processes in a Windows environment).
The focus of this report is not to explain in detail how Windows works when creating a process. However, we will provide throughout the report the names of functions and modules involved in process creation, along with references that the reader can consult if he or she wishes to delve deeper into the subject.
The operation of Image Loader involves a number of ntdll.dll functions, with special emphasis on LdrpLoadDll, LdrpCheckForLoadedDll and LdrpMapDll. For each of the modules listed, LdrpLoadDll will start the import process. Part of this process is to check whether the desired DLL has already been imported; this is what the LdrpCheckForLoadedDll function does. If the module is not yet part of the process, it is up to LdrpMapDll to find the module on disk and load it into memory. Understanding how disk searching happens is crucial to understanding how DLL hijacking works.
Search Order
There is a specific order of directories where any module to be imported will be fetched from. The default order for Windows is as follows:
- The directory from which the application was launched
- The system directory (C:³³Windows³System32)
- The 16-bit version of the system directory
- The Windows directory (C:³³)
- The current directory
We call this sequence the default because it is defined by a key in the registry, HKEY_LOCAL_MACHINE\System\CurrentControlSet\ControlSession Manager\SafeDllSearchMode, which is enabled by default. If it is disabled, the sequence changes to:
- The directory from which the application was launched
- The current directory
- The system directory (C:³³Windows³System32)
- The 16-bit version of the system directory
- The Windows directory (C:³³)
One way to observe this search in action is by using the Process Monitor from SysInternals. The image below demonstrates this routine with the running process explorer.exe.
CreateFile operations are search actions for the modules specified in the import table of the explorer executable. Important: the C:\Windows searches shown above are not the result of the fourth step of the search order, but of the first. The full path to this file is C:\Windowsexplorer.exe, so C:\Windows is the directory from which the application was launched.
We have highlighted only operations that had "NAME NOT FOUND" as a result, which means that the module was not found in that directory. LdrpMapDll will then move on to the next directory until it finds the desired module. In the case at hand, for example, cscapi.dll is located in C:\Windows\System32. It will then be found in the second step of the search and mapped into the process memory.
But what would happen if there was a DLL of the same name in C:\Windows?
DLL hijacking
DLL hijacking is a tactic to load malicious modules into a process by taking advantage of the search order used by Windows. Answering the question asked in the previous item: if there was a library called cscapi.dll in the same directory as explorer.exe, it would be loaded instead of the legitimate module located in C:\WindowsSystem32.
But what is the point of loading a fake DLL into a process? After all, it will not contain the functions that the process wants to import, so in theory none of your code would be executed. For this we need to understand another component of the Image Loader, LdrpRunInitializeRoutineswhich is responsible for invoking the entry point of executables and libraries.
This routine, as well as the other functions of ntdll.dll that we mentioned in previous items, are not officially documented by Microsoft. However, there is an API that is documented and calls LdrLoadDLL: LoadLibraryA.
The official documentation details that after the process of mapping a library, this API invokes the DLLMain function of the module, with the value DLL_PROCESS_ATTACH. In reality, this is the invocation of the entry point performed by LdrpRunInitializeRoutines that we mentioned at the beginning of this item. Let's translate into less technical terms what this invocation implies.
According to the DLLMain documentation, the value DLL_PROCESS_ATTACH means that the DLL in question is being loaded into the memory of a new process. What LdrpRunInitializeRoutines will do is execute the code that is tied to this value at the time this module is imported.
This answers the question at the beginning of this item: we don't need a function exported from a DLL to be called in order for some code in it to execute. We only need the code in question to be associated with the value DLL_PROCESS_ATTACH. We have created a simple POC to further demonstrate these concepts. Its code follows below:
Notice what comes right after case DLL_PROCESS_ATTACH: WinExec("calc.exe", 0). Translation: as soon as our library is mapped into the memory of a process, it will open the calculator. To test the theory we have presented so far, we need to compile our code, call it cscapi.dll and put the file in the same directory as explorer.exe
Now all that remains is to terminate the explorer.exe process and restart it.
If all went successfully, the new process should find cscapi.dll in the C:\Windows directory. The Process Monitor log below demonstrates this action:
After finding the file, the module in question will be imported by the process.
If our code in DLL_ PROCESS_ATTACH is executed, we should see explorer.exe creating a Windows calculator process (calc.exe).
Our proof of concept of DLL hijacking worked perfectly!
Conclusion
DLL hijacking is a very useful technique to achieve persistence in a system, while avoiding already known gimmicks such as registry keys and directories that run programs during the Windows startup phase.
This method also has its weaknesses. Firstly, by using legitimate Windows methods to load a library into memory, this method populates regions of process memory with the complete path to the malicious module. In the hands of an experienced analyst, DLLs being loaded from incorrect locations is a clear sign that malware is present.
Another problem lies in the fact that this technique replaces a legitimate DLL. This means that any functions present in the module that has been replaced are no longer available to the target process. Unsuccessful hijacking attempts can eliminate important functions for an application, causing instability or even crashes.
Finally, there is the permission problem. The explorer.exe, chosen by us to demonstrate this technique, may seem like a good target. It is an executable that is present in any version of Windows and is guaranteed to run. But it resides in a system directory. This means that we were only able to place our malicious DLL in the same folder as it because we have administrative permissions on the machine. For an attacker who has just gained first access to an asset, using explorer for this technique is impossible.
References
- https://www.youtube.com/watch?v=3eROsG_WNpE&ab_channel=IppSec
- https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain
- https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications
- https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya
- https://docs.microsoft.com/en-us/sysinternals/downloads/procmon
- https://web.archive.org/web/20010618170125/http://www.microsoft.com:80/msj/0999/hood/hood0999top.htm
- https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/windows-2000-loader-what-goes-on-inside-windows-2000-solving-the-mysteries-of-the-loader
- https://guidedhacking.com/threads/dll-injection-methods.14569/
- https://docs.microsoft.com/en-us/sysinternals/resources/windows-internals