DLL (Dynamic-link library) are the Microsoft's implementation of the shared library concept and provide a mechanism for shared code and data, allowing a developer of shared code/data to upgrade functionality without requiring applications to be re-linked or re-compiled.
DLLs may be explicitly loaded at run-time, a process referred to simply as run-time dynamic linking by Microsoft, and its code is usually shared among all the processes that use the same DLL.
When you need to load a DLL in Windows, you need to call LoadLibrary, that takes the file path of a DLL and loads it in to memory.
This method can also used to perform a DLL injection, that inserts code in the context of another process by causing the other process to load and execute code.
The code is inserted in the form of a DLL, since DLLs are meant to be loaded at run time.
Running code in the context of another process provides adversaries many benefits, such as access to the process's memory and permissions.
It also allows adversaries to mask their actions under a legitimate process.
Reflective DLL loading refers to loading a DLL from memory rather than from disk.
Windows doesn’t have a LoadLibrary function that supports this, so to get the functionality you have to write your own, omitting some of the things Windows normally does, such as registering the DLL as a loaded module in the process , potentially bypassing DLL load monitoring.
The process of reflective DLL injection is as follows:
- Open target process with read-write-execute permissions and allocate memory large enough for the DLL.
- Copy the DLL into the allocated memory space.
- Calculate the memory offset within the DLL to the export used for doing reflective loading.
CreateRemoteThread(or an equivalent undocumented API function like
RtlCreateUserThread) to start execution in the remote process, using the offset address of the reflective loader function as the entry point.
- The reflective loader function finds the Process Environment Block of the target process using the appropriate CPU register, and uses that to find the address in memory of
kernel32.dlland any other required libraries.
- Parse the exports directory of kernel32 to find the memory addresses of required API functions such as
- Use these functions to then properly load the DLL (itself) into memory and call its entry point, DllMain.
The process of remotely injecting a library into a process is two fold. Firstly, the library you wish to inject must be written into the address space of the target process (Herein referred to as the host process). Secondly the library must be loaded into that host process in such a way that the library's run time expectations are met, such as resolving its imports or relocating it to a suitable location in memory.
And here a video demo of a reflective injection using metacploit module:
In the attempt to evade AV, attackers go to great lengths to avoid the common reflective injection code execution function, CreateRemoteThread(). Alternative techniques include native API (ntdll) thread creation and user APCs (necessary for SysWow64->x64), etc.
This technique uses SetThreadContext() to change a selected thread's registers, and performs a restoration process with NtContinue(). This means the hijacked thread can keep doing whatever it was doing, which may be a critical function of the injected application.
(a PoC is available here)
It can be detected or mitigated?
Limiting access to specific API calls will likely have unintended side effects, such as preventing legitimate software from operating properly.
A possible mitigation could be identify or block potentially malicious software that may contain DLL injection functionality by using whitelisting tools or Software Restriction Policies.
Also, monitoring API calls indicative of the various types of code injection may generate a significant amount of data and may not be directly useful for defense, since benign use of API functions may be common and difficult to distinguish from malicious behavior.
And finally, Reflective DLL Injection uses custom function that can easily avoid detection.
However at DEF CON 20 Andrew King demonstrated that he was able to detect DLL's injected using reflective DLL injection. His presentation was called "Detecting Reflective Injection".
I created a small tool called antimeter which scans memory for detecting and also killing Metasploit’s meterpreter. I did not expect that much interest from the community therefore I did not implement core features like logging and autokill but suddenly antimeter got nice feedbacks so I have decided to implement these features and more for the community.
Here a video demo of the tool: