We recently received an email which contained a malicious Word macro. Usually, the only thing that changes between malicious Office macros is the obfuscation that is used; e.g. changing variable names and splitting text strings. This one was different. We decided to analyse the payload and before we knew it, we were deep down the rabbit hole!
A look at the malicious macro
It is a common practice for people ‘playing’ with Office macros to make use of functions exported by
kernel32.dll in order to take advantage of the extra capabilities offered by the OS. Usually, the
RtlMoveMemory functions are involved in order to allocate one or more memory pages with full access permissions (RWE) where a chunk of shellcode is copied in and executed. To achieve execution, the
CreateThread function exported by the aforementioned DLL is used, since in VB we can’t do low level things like calling function pointers or directly jumping to an address of our choice. There are more ways to allocate and/or use a memory page with full access permissions, but that’s an article for another day.
Another method, which is the one used by our sample, is a combination of the
HeapAlloc functions. The result is basically the same, but moving on from always using
VirtualAlloc might help bypass the AV sitting on the target host and consuming CPU cycles and memory.
What makes our sample document particularly interesting is that the author didn’t use
CreateThread in order to execute the shellcode. Instead, the
EnumResourceTypesW function, also exported by the aforementioned DLL, was used. This may sound difficult, but actually the concept is really simple.
This function is declared as:
BOOL WINAPI EnumResourceTypes( _In_opt_ HMODULE hModule, _In_ ENUMRESTYPEPROC lpEnumFunc,_In_ LONG_PTR lParam);
The interesting parameter is
lpEnumFunc which is essentially a pointer to a callback function that is called for each enumerated resource type. In other words, calling
EnumResourceTypes and supplying the address of our shellcode in memory as a pointer to a callback function, will do the trick. In this case we are not interested at the result returned by
EnumResourceTypes and it is simply used as a bridge to the shellcode. This technique is not really new for PE malware, but personally we have not seen it being used before through a macro. However, since we don’t spend most of our time looking at Office macros, this method has probably been used before, though infrequently.
The following code shows how this function is called through the Office macro.
Dim commendation As Long commendation = 0 Dim doohickey As Long doohickey = impedition + theorist intelligently = EnumResourceTypesW(commendation, doohickey, stood)
In the code above,
doohickey points inside the shellcode in memory. This pointer is derived by adding the base address of the allocated memory stored in the
impedition variable with a value stored in the
theorist variable, which is basically the offset of the shellcode where the execution needs to be transferred. Armed with that information, we can simply attach a debugger to the Word process and start examining the shellcode on runtime, as show in the following image.
Examining the shellcode
The shellcode goes through a series of steps to extract an encoded PE file from inside the document file, drop it to disk and then execute it.
The main steps are:
- Access self-document file, and read the contents.
- Use an egg-hunter to locate the
POLAkeyword located at (Embedded_PE_Offset – 8).
- Decode and drop the embedded PE file in
jj814.exeas a filename.
- Start a new process for it.
Digging inside the dropped PE file
This PE file is basically malware packed with a custom packer. The packer responsible for running the original executable keeps it encoded as a resource data type, which loads and decodes in memory.
At this point, we have another executable in the infection steps. However, this one is not supposed to ever touch the disk. The packer is using
NtUnmapViewOfSection to release the memory that has been allocated in the child process to hold the main executable module. Then, it reallocates the same memory using
VirtualAllocEx, and overwrites it with the embedded PE file by using the
WriteProcessMemory function. Finally, it changes the EIP of the main thread of the suspended process to point to the new entry point using the
SetThreadContext function and then resumes its execution.
The main steps are:
- The dropped
jj814.exeexecutable loads an encoded PE file which is embedded as resource data.
- It starts a suspended child process of itself.
- It overwrites its memory with the decoded PE file.
- It changes the EIP to the new entry point and resumes execution.
- It terminates itself.
Analyzing the embedded PE file
We isolated the PE file from memory.
It’s SHA-256 hash is
Now, remember that this PE file is never really dropped. This is also interesting because while this one doesn’t touch the disk, it will still use another process injection technique to overwrite a suspended child process of the legitimate Windows Explorer. If you are interested in knowing more about the code injection technique used by this sample, there is a good explanatory article at http://blog.w4kfu.com/tag/duqu.
The main steps are:
- Start a suspended instance of explorer.exe.
- Overwrite its memory with some malicious code.
- Resume its main thread.
- Terminate itself.
Examining the infected explorer.exe process
We took control of the injection process mentioned in the previous section; we attached the debugger before anything actually happened.
The following figure shows how the entry point of the infected process looked once in memory.
An experienced eye might also note a xor-decoding loop starting at address
0x00AC10AC, which… decodes another embedded PE file.
This one is packed with the famous Upack packer. Those who were spending their weekends on manually unpacking PE files rather than drinking beer in the past will be familiar with the look of the following image:
This PE file is actually a DLL which, at the next step, is going to be loaded at the address space of the calling process using
VirtualAllocEx along with the
-1 pseudo handle that refers to the calling process.
Going one step further inside the malicious Upacked DLL
This module attempts to bypass UAC in case the user belongs to the Administrators group. In this way, it can execute a process with High Integrity which basically enables all the administrative permissions to a process. To achieve that, the sample uses a well-known trick that is described at https://msitpros.com/?p=3100.
After that step, it will attempt to execute the aforementioned embedded PE file (SHA-256:
023081297DCCDBED9C289D32B351ED02FC07FCF8A14486609ABFABBB4D75566A) with High Integrity and then perform the next step, thus starting
explorer.exe and injecting code to its process, but this time with all the necessary privileges.
Going back to the analysis of the embedded PE file
At this point we have figured out a lot of things, and we know that if the user belongs to the Administrators group, the malware will not proceed until has performed a UAC elevation from Medium to High Integrity. Once this is achieved, the behaviour of this PE file changes and proceeds with the actual infection.
Main infection steps:
- Eliminate OS defences by stopping and then permanently disabling important services such as the Windows Firewall, Windows Defender, Windows Security Center and Windows Update.
- Search for available drives and network shares.
- Queries value of
HKEY_USERS\S-1-5-21-4132500612-3697680674-1831287676-1000_CLASSES\http\shell\open\commandwhich can be eventually used to launch the default web browser.
CreateProcessand starts a suspended instance of the default web browser.
- Uses the aforementioned trick to perform code injection in the suspended child process of the web browser.
- Child process contacts attacker’s domains and downloads the actual malware, which comes as a DLL PE file
- The End!
As a side note, the malware appeared to be an information stealer. You know, the usual stuff, stealing stored passwords, credentials, etc… 🙂
It is remarkable how much work is now put in to conceal every step and element of malware. From experience, we would say that all of this is generally not necessary. Sometimes, the complexity applied to evade analysis and AV is comparable to buying a Ferrari to win a race where everyone else is using a family car. However, it is possible that there are instances where defenders would either trust samples like this one due to automated analysis or else give up the analysis entirely, due to the extra barriers presented.