From macro to malware – a step by step analysis

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!

Document hash

SHA-256:  DC8FD31BA535551021327EB3DFF8ADB7CBA261E6F1796CB6F53FE95DF46B4C05

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  VirtualAlloc and 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  HeapCreate and 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:

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.

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.

shellcode-entry-point

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:

  1. Access self-document file, and read the contents.
  2. Use an egg-hunter to locate the POLA keyword located at (Embedded_PE_Offset – 8).
  3. Decode and drop the embedded PE file in %temp% directory using jj814.exe as a filename.
  4. Start a new process for it.

Digging inside the dropped PE file

PE SHA-256: 0D03FADE2B60A0581D688E2631BE65F77E40F4353B43D9E49BB751D780F6678B

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:

  1. The dropped jj814.exe executable loads an encoded PE file which is embedded as resource data.
  2. It starts a suspended child process of itself.
  3. It overwrites its memory with the decoded PE file.
  4. It changes the EIP to the new entry point and resumes execution.
  5. It terminates itself.

Analyzing the embedded PE file

We isolated the PE file from memory.

It’s SHA-256 hash is 023081297DCCDBED9C289D32B351ED02FC07FCF8A14486609ABFABBB4D75566A.

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:

  1. Start a suspended instance of explorer.exe.
  2. Overwrite its memory with some malicious code.
  3. Resume its main thread.
  4. 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.

in-memory-modified-entry-point

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:

decoded-unpacked-pe-file

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:

  1. Eliminate OS defences by stopping and then permanently disabling important services such as the Windows Firewall, Windows Defender, Windows Security Center and Windows Update.
  2. Search for available drives and network shares.
  3. Queries value of HKEY_USERS\S-1-5-21-4132500612-3697680674-1831287676-1000_CLASSES\http\shell\open\command which can be eventually used to launch the default web browser.
  4. Calls CreateProcess and starts a suspended instance of the default web browser.
  5. Uses the aforementioned trick to perform code injection in the suspended child process of the web browser.
  6. Child process contacts attacker’s domains and downloads the actual malware, which comes as a DLL PE file
    (SHA-256: 5A0CF8A63F38D1F2797FF223048817A37851B2B10496189DC8285EF5E0AEF37A).
  7. The End!

As a side note, the malware appeared to be an information stealer. You know, the usual stuff, stealing stored passwords, credentials, etc… 🙂

Conclusion
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.