Classic DLL injection

DLL injection is a classic method of putting code into another process in memory. The first stage — the loader — adds the path of the new DLL in the virtual address space of the target process. Next, the target process will load the DLL by creating a remote thread and execute it. During malware analysis, it is common to find calls to the CreateToolhelp32Snapshot, Process32First and Process32Next Win32 API functions used to enumerate and get a handle to a target process. After that, adversaries can put their malicious DLLs into the memory by using the VirtualAllocEx, WriteProcessMemory and CreateRemoteThread calls capabilities.  Figure 1 shows the block of code responsible for performing DLL injection.

Figure 1:  Rebhip malware executing a common DLL injection (source).

Reflective DLL injection

Reflective DLL injection, in contrast to the DLL injection approach, loads a DLL from memory rather than from disk. Instead of using a LoadLibrary() call, this technique requires a custom loader that emulates the tasks of the native LoadLibrary() call. In short, the main stages to map a DLL with this technique into a new process are the following:

Initially, the loader maps the DLL into the memory After mapping it, the IAT must be rebuilt Base relocation is also parsed to fix the calls’ addresses due to the difference in the image base Finally, the mapped DLL is injected into a new target process.

Netwalker is a malicious data encryption malware that uses this technique to dynamically inject into the memory an additional payload.

Figure 2: Reflective DLL injection used by Netwalker ransomware (source).

PE injection

This technique is similar to the reflective DLL injection as it doesn’t drop the PE file on the disk. PE injection is the most widely used technique in the wild by malicious authors and malware. In short, the code is injected into a target process and executed. The following steps below describe how this approach works:

The current image base address and size from the PE header are obtained. The new memory region is allocated in the target process by using the VirtualAlloc call. The code is copied into the target memory region using the memcpy call. VirtualAllocEx is invoked to allocate memory to fit the image in the target process. WriteProcessMemory is used to copy into the new memory region the local image. A new thread is created with the start address using the CreateRemoteThread call.

Figure 3: High-level diagram of PE injection technique (source).

Process hollowing

The process hollowing technique creates a suspended state (CREATE_SUSPENDED (0x00000004)), unmapping its memory and replacing it with the target code. In detail, the target process can be created using the CreateProcess call with the suspended flag to suspend the main thread. After this point, the memory of the created process is unmapped using Win32 calls such as ZwUnmapViewOfSection and NtUnmapViewOfSection. Next, the new code is injected and realigned using VirtualAllocEx and WriteProcessMemory calls. Finally, the main thread is resumed using the ResumeThread call.

Figure 4: Cryak ransomware using process hollowing to evade detection (source).

Understanding abused memory injection techniques

Memory injection techniques are abused by malware and emerging threats as a camouflage layer, making it difficult to analyze them and learn how they work. For instance, it’s impossible to use the task manager to inspect and differentiate an injected or legitimate process because the two processes are very similar except its inner content. Two real examples are the Brazilian trojan URSA that takes advantage of the PE injection technique during its infection chain to inject into the memory an additional payload.

Figure 5: The PE injection technique used by trojan URSA to load additional payloads into the memory (source). On the other hand, this new warsaw trojan banker was observed using the process injection technique in .NET to load the Horus Eyes RAT into the memory. However, .NET binaries work on a high-level code paradigm and have a set of well-defined libraries such as System.Reflection, which can be used to load assemblies at runtime, the model is the same as described previously in Figure 3.

Figure 6: Warsaw trojan taking advantage of PE injection to load into the memory the infamous Horus Eyes RAT at runtime (source). As memory injection techniques are hard to detect, threats using one of these techniques can bypass host-based solutions, such as firewalls, antivirus and EDRs. The usage of updated software and the users’ training about social engineering and phishing, in general, is a crucial step to put away malicious threats.  

Sources:

Process injection techniques, Elastic Code injection, Ired.team Memory injection techniques, MITRE URSA and Warsaw trojans, Segurança-Informática