
The Emotet-ion Game (Part 3)
This blog is a continuation of our blog series on the Emotet banking Trojan. So far, we have analysed Emotet’s delivery mechanism and its behaviour through dynamic analysis. The host and network data captured from Emotet found that it escalates its privileges by registering itself as service, persists in multiple locations and finally deletes the dropper file.
In this post, we demonstrate how the main payload is unpacked and follow its execution after unpacking in a debugger. We also discuss how early on in the unpacking code Emotet checks for the existence of a registry key. If the registry key is not accessible, the payload is not unpacked and run. We found that this behaviour can be forced by blocking read access to the key.
The execution of Emotet comprises multiple stages of obfuscated executables that are loaded into memory and has an elaborate code flow through different memory regions. These are designed to make it harder for analysts, static analysis engines and disassemblers to analyse the Trojan.
Read part 1: Emotet: How It Might Infect Your PC
Read part 2: Emotet: Catch Me If You Can
In part two, we discussed how Emotet acts as a dropper of other malware families and how this is an indication that its operators have adopted a malware-as-a-service business model. Our analysis of an Emotet executable called 15.exe ultimately dropped Trickbot, another banking Trojan.
As discussed in the Bromium Threat Insights Report for April 2019, we continue to see a high volume of Emotet, and it is among the top threats that Bromium isolates. On computers that have Bromium installed, Emotet runs in an isolated micro virtual machine without damaging the integrity of the system. Since the malware runs dynamically it produces indicators of compromise (IOCs) that can be used by security teams to defend other parts of a network.
Emotet’s packer
The main purpose of a packer is to compress and encrypt a portable executable (PE) file. The encrypted payload is unpacked at runtime and the unpacking code then passes execution to the newly unpacked code. For malware authors, packers help evade detection by making static analysis of the binary more difficult. Emotet’s packer is polymorphic which makes it even trickier for signature-based detection tools to profile the sample based on the footprint of the packer.
- Filename: 15.exe
- Size: 428808 bytes
- MD5: 322F9CA84DFA866CB719B7AECC249905
- SHA1: 147DDEB14BFCC1FF2EE7EF6470CA9A720E61AEAA
- SHA256: AF2F82ADF716209CD5BA1C98D0DCD2D9A171BB0963648BD8BD962EDB52761241
Let’s look at the PE file. Its resource section takes up a significant proportion of the total size of the file (51%), which is an indication that the malware might be packed.
Figure 1 – Resource section consuming more than half of the binary.
Looking at the resource (.rsrc) section reveals two anomalous resources called EXCEPT and CALIBRATE. The high entropy and large size of EXCEPT suggests that this might be an encrypted payload. Dumping the resource confirms that it contains encrypted data. In some samples we found that a decrypted PE file is dropped from the .data section.
Figure 2 – Anomalous resources called EXCEPT and CALIBRATE.
Figure 3 – Encrypted data in EXCEPT.
Emotet is modular and uses anti-analysis techniques such as sandbox detection to evade analysis. An unpacked Emotet binary contains hundreds of functions. When the suspected packed sample is opened in a disassembler such as Ghidra, only a handful of functions are identified. This is another indication that the binary is packed.
Figure 4 – List of functions identified by Ghidra in the packed Emotet sample.
Packer registry check
During our analysis of the packer code, we noticed a function that generates an array of chars and has a conditional while(true) infinite loop. This finding made us curious whether we could trigger the infinite loop to stop the execution of the unpacking code, thereby preventing the main Emotet payload from running. The function works by reading a Windows Registry key through a call to RegOpenKeyA. If the key isn’t found, the malware enters an infinite loop (figure 5).
Figure 5 – Function that checks for the existence of “interface\{aa5b6a80-b834-11d0-932f-00a0c90dcaa9}” in the registry.
Function FUN_00401a90 decodes a string with the value “interface\{aa5b6a80-b834-11d0-932f-00a0c90dcaa9}” which is passed as a parameter to RegOpenKeyA. This registry key is required for the Windows scripting engine interface IActiveScriptParseProcedure32 to function. Specifically, the interface parses a given code procedure and adds the procedure to the namespace.
Figure 6 – RegOpenKeyA parameters.
We reviewed other samples of Emotet for similar functions. Interestingly, upon execution all the samples either exited the main thread or entered an infinite loop in the absence of this registry key.
- Filename: 891.exe
- First submitted to VirusTotal: 08/05/2019
- MD5: BD3B9E60EA96C2A0F7838E1362BBF266
- SHA1: 62C1BEFA98D925C7D65F8DC89504B7FBB82A6FE3
- SHA256: 28E3736F37222E7FBC4CDE3E0CC31F88E3BFC16CC5C889B326A2F74F46E415AC
Figure 7 – Main thread goes into an infinite loop in the absence of the registry key.
- Filename: 448.exe
- First submitted to VirusTotal: 07/03/2019
- MD5: 193643AB7C0B289F5DE3963E4ADC1563
- SHA1: B14290BFAE015D37EBA7EDD8F5067AD5E238CC68
- SHA256: FD9E5C47F9AEB47F5E720D42DD4B8AD231EE3BA5270E3FBD126FC8C6F399D243
Figure 8 – Main thread exits in the absence of the registry key.
Binary analysis with a debugger
To confirm our suspicions that 15.exe is a packed Emotet binary, let’s open it in x64dbg and check its mapped memory region. In the optional header of 15.exe, address space layout randomisation (ASLR) is disabled, which means that if possible the module is loaded into memory at its preferred base address of 0x400000.
Stage 1
One of the imported functions in 15.exe is VirtualAllocEx. This function is used to allocate memory in a remote process and is often used by malware for process injection. We will start by putting a breakpoint on the return address for VirtualAllocEx.
Figure 9 – Memory mapped sections of 15.exe.
If we run until the breakpoint, we see that Emotet creates an allocation of memory at 0x00220000. It then copies a code stub from the .data section of the mapped image at 0x00422200 (file offset 0x0001FE00) to the newly allocated memory space and gives control to it.
Figure 10 – Allocation of memory at 0x00220000.
Emotet then deobfuscates API and DLL names from the code copied to 0x00220000.
Figure 11 – Deobfuscating LoadLibraryExA and kernel32.dll.
Figure 12 – Deobfuscating VirtualAlloc.
It then calls GetProcAddress from kernel32.dll to get the addresses of the decoded API names.
Figure 13 – GetProcAddress API being called from the code stub at 0x00220000 to retrieve the addresses of exported APIs from the mapped image of kernel32.dll.
First, the address of LoadLibraryExA is retrieved in this way. It then uses this address to load kernel32.dll into the address space at 0x766D00000. Afterwards, it uses the handle to the loaded module kernel32.dll to call GetProcAddress on the list of functions below:
- LoadLibraryExA
- GetProcAddress
- VirtualAlloc
- SetFilePointer
- LstrlenA
- LstrcatA
- VirtualProtect
- UnmapViewOfFile
- GetModuleHandleA
- WriteFile
- CloseHandle
- VirtualFree
- GetTempPathA
- CreateFileA
Figure 14 – Call to GetProcAddress to get the address of LoadLibraryExA.
Figure 15 – Call to LoadLibraryExA to load kernel32.dll into memory.
Figure 16 – Deobfuscated API names whose addresses are resolved.
One of the interesting things to note is that Emotet calls GetProcAddress for an invalid API called “mknjht34tfserdgfwGetProcAddress”. Since this is invalid, the function returns a null value with an error code of 0000007F (ERROR_PROC_NOT_FOUND). In all the Emotet samples we reviewed a call was made to GetProcAddress for this invalid function name.
Figure 17 – Call to GetProcAddress for an invalid API.
Figure 18 – Call to GetProcAddress to fetch the address of GetProcAddress.
Figure 19 – Function addresses of APIs saved on the stack.
Once the code stub has retrieved the function addresses, VirtualAlloc is called to allocate another memory region where it writes the deciphered PE file from the .data section of 15.exe, rather than from the .rsrc section.
Figure 20 – Allocation of memory at address 0x00240000.
Figure 21 – Stub writes PE file at address 0x00240000.
Emotet binary dumped from 0x00240000
- Filename: emotet_dumped_240000.exe
- MD5: D623BD93618B6BCA25AB259DE21E8E12
- SHA1: BBE1BFC57E8279ADDF2183F8E29B90CFA6DD88B4
- SHA256: 01F86613FD39E5A3EDCF49B101154020A7A3382758F36D875B12A94294FBF0EA
- Bromium Cloud Classification: Win32.Trojan.Emotet
Dumping the executable and examining it reveals that it is another packed Emotet binary that contains the main payload. We have seen in some Emotet samples that the first mapped decrypted executable cannot be directly run after dumping it from memory, but this sample was able to run.
Pestudio identifies several suspicious characteristics about this file, including the absence of imports, the detection of a packer signature “Stranik 1.3 Modula/C/Pascal” and that the file may contain another file.
Figure 22 – Suspicious indicators about emotet_dumped_240000.exe identified by pestudio.
Figure 23 – Bromium Controller process interaction graph of emotet_dumped_240000.exe. It launches itself and creates service a called “ipropmini”, which closely matches the behaviour shown by 15.exe.
Figure 24 – Bromium Controller view of high severity events detected for emotet_dumped_240000.exe.
Stage 2
After writing and decrypting the executable file at 0x00240000, the code stub allocates another memory region at address 0x00260000 using VirtualAllocEx. After allocating memory, it reads the payload from memory region 0x00240000 and writes it to 0x00260000.
Figure 25 – Call to VirtualAllocEx to allocate memory at 0x00260000.
Figure 26 – Stub writes the main Emotet payload at 0x00260000.
After writing the main Emotet payload at 0x00260000, the code stub then inserts hooks and JMP instructions in the code (figure 28). Emotet does this to make code analysis trickier and to confuse disassemblers.
After the hooks are in place the payload becomes dependent on another memory region to run which means that dumping to disk will not allow it to run even after fixing the alignment and raw offsets of the PE file’s sections.
Figure 27 – Execution error for dumped PE file from virtual address 0x00260000.
Figure 28 – Modification of executable located at 0x00260000 by the code stub.
Stage 3
Once the payload is modified and ready at 0x00260000, the stub calls UnmapViewOfFile to unmap 15.exe from 0x00400000, which is the memory region that the first Emotet image was loaded into. It then allocates a new memory region at 0x00400000 that is the same size of the payload at 0x00260000 (15000 bytes). After allocating the new memory region, it then copies the modified payload to 0x00400000. This is a process injection technique where the malware modifies its binary in memory and then overwrites itself.
Figure 29 – Emotet unmaps the loaded image 15.exe from 0x00400000.
Figure 30 – Memory map view after image 15.exe is unmapped.
Figure 31 – Newly allocated memory at 0x00400000.
Figure 32 – Memory view after allocation at 0x00400000.
Figure 33 – Copying of the payload from 0x00260000 to 0x00400000.
Stage 4
After copying the payload into 0x00400000, Emotet resolves API names and then transfers execution flow to the payload. In this case, it transfers execution to 0x0040C730, which then calls a function that resolves hashes that correspond to API names.
The main Emotet payload makes it hard for an analyst to follow the code flow because of how strings that might give an insight into the functionality of the malware are obfuscated.
Figure 34 – Pass list of API hashes to deobfuscation function for name resolution.
Figure 35 – Resolution of API names from ntdll.dll and kernel32.dll.
After API name resolution, GetCurrentProcessId is called to get the process ID (PID) of Emotet‘s running process. Afterwards, Emotet iterates through all running processes to find its module name and parent PID. Once it finds its parent PID, it creates two mutexes with the format PEM%X. One of the mutexes is created using the parent process ID (PEM[PPID]) and the other uses its own PID (PEM[PID]).
After creating these mutexes, it calls CreateEventW to create an event using the format PEE%X, where %X is its parent PID. If both mutexes are successfully created, it launches 15.exe again from the same path. After launching the child process, it calls WaitForSingleObject on the PEE%X event.
We have seen in some of the Emotet samples that it launches child process with a command line switch. This command line switches are an indication that an Emotet process has been launched as a child process and has to perform a designated task.
The launched child process does everything same until it evaluates whether to create the two mutexes described above. This time the call to CreateMutex for mutex PEM[PPID] fails with the error “ERROR_ALREADY_EXISTS”. After the mutex creation fails in the child process, it signals the event PEE[PPID] to the parent process 15.exe. The parent process exits from a waiting state and then terminates itself.
Figure 36 – Control flow graph which shows the decision to launch a child process based on calls to CreateMutex and CreateEvent.
Figure 37 – PIDs of Emotet child process 15.exe (1352 or 0x548) and Parent PID (3520 or 0xDC0).
Figure 38 – CreateMutex call on mutex object name PEMDC0, where 0xDC0 is the parent PID.
Figure 39 – CreateMutex call on mutex object name PEM548, where 0x548 is the PID of Emotet process 15.exe.
Figure 40 – CreateEventW call on event object name PEE548, where 0x548 is the PID of Emotet process 15.exe.
The launched child process then creates a service called “ipropmini” and establishes command and control (C2) communications.
Summary
Figure 41 – Summarised view of payload unpacking steps.
- The dropped Emotet binary (15.exe) allocates a new memory region with execute permission and writes a code stub there (figure 41, memory region 1).
- The stub decrypts an embedded PE file from the .data section of the image and writes it in the new memory region (figure 41, memory region 2).
- The file written to memory region 2 is a valid PE file that is another Emotet binary and can be dumped and executed without needing to fix its relocations.
- The stub from memory region 1 allocates a new region with execute permission (figure 31, memory region 3).
- The stub reads an embedded payload from memory region 2 and writes it to memory region 3.
- After writing the payload to memory region 3, it then modifies it by inserting new code and trampolines.
- Once the payload is ready in memory region 3, it unmaps the 15.exe image.
- After unmapping the image, it allocates a new region of the same size as memory region 3 with execute permission and copies the payload from memory region 3 to the newly allocated region (figure 41, memory region 4).
- The stub then passes execution to memory region 4, which launches the main Emotet payload.
Conclusion
Emotet uses a layered approach to unpack its main payload. It performs a self-injection technique to execute the payload in memory after modifying its mapped image. As the payload is never written to the filesystem and contains hooks and JMP instructions, it can easily evade anti-virus and detection based on dynamic code analysis.
Indicators of Compromise
The Emotet dropper can be stopped by blocking read access to the registry keys below. Since the dropper will enter an infinite loop or end the process, it will not harm the integrity of the system because the conditional branch occurs before the payload is executed.
- For 32-bit systems:
- HKEY_CLASSES_ROOT\Interface\{AA5B6A80-B834-11D0-932F-00A0C90DCAA9}
- For 64-bit systems:
- HKEY_CLASSES_ROOT\Wow6432Node\Interface\{AA5B6A80-B834-11D0-932F-00A0C90DCAA9}
The Emotet dropper can be detected in the following ways:
- Monitoring read accesses to the registry key “Interface\{AA5B6A80-B834-11D0-932F-00A0C90DCAA9}” by processes launched from globally writable directories, such as %USERPROFILE% and %TEMP%.
- Monitoring API calls to GetProcAddress for the function name “mknjht34tfserdgfwGetProcAddress”.
- Monitoring the sequence of API calls to GetProcAddress can be used as a heuristic.
The post The Emotet-ion Game (Part 3) appeared first on Bromium.
*** This is a Security Bloggers Network syndicated blog from Bromium authored by Ratnesh Pandey. Read the original post at: https://www.bromium.com/emotet-analysis-part-3/