DLL Hijacking - the MITRE sub-technique for injecting DLLs

DLL Hijacking - injecting DLLs for evasion and persistence

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.

Figure 1: List of modules to be imported into the notepad (notepad.exe)

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:

  1. The directory from which the application was launched
  2. The system directory (C:³³Windows³System32)
  3. The 16-bit version of the system directory
  4. The Windows directory (C:³³)
  5. 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:

  1. The directory from which the application was launched
  2. The current directory
  3. The system directory (C:³³Windows³System32)
  4. The 16-bit version of the system directory
  5. 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.

Figure 2: explorer searching for DLLs in the directory from where it was run

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.

Figure 3: result of the CreateFile action for cscapi.dll

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:

Figure 4: POC code to demonstrate DLL Hijacking

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

Figure 5: POC DLL saved in the same directory as explorer.exe

Now all that remains is to terminate the explorer.exe process and restart it.

Figure 6: Shutting down and restarting explorer.exe

If all went successfully, the new process should find cscapi.dll in the C:\Windows directory. The Process Monitor log below demonstrates this action:

Figure 7: Our cscapi.dll was found in the directory C:\Windows

After finding the file, the module in question will be imported by the process.

Figure 8: Module successfully loaded into the explorer.exe process

If our code in DLL_ PROCESS_ATTACH is executed, we should see explorer.exe creating a Windows calculator process (calc.exe).

Figure 9: explorer.exe creating a Windows calculator process

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

  1. https://www.youtube.com/watch?v=3eROsG_WNpE&ab_channel=IppSec
  2. https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain
  3. https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications
  4. https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya
  5. https://docs.microsoft.com/en-us/sysinternals/downloads/procmon
  6. https://web.archive.org/web/20010618170125/http://www.microsoft.com:80/msj/0999/hood/hood0999top.htm
  7. 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
  8. https://guidedhacking.com/threads/dll-injection-methods.14569/
  9. https://docs.microsoft.com/en-us/sysinternals/resources/windows-internals

By Alexandre Siviero, Laura Cardillo and Átila Altoé

Leave a Comment

Your e-mail address will not be published. Required fields are marked with *