This post is also available in: 日本語 (Japanese)

Executive Summary

Unit 42 researchers recently discovered a Guloader variant that contains a shellcode payload protected by anti-analysis techniques, which are meant to slow human analysts and sandboxes processing this sample. To help speed analysis for this sample and others like it, we are providing a complete Python script to deobfuscate the Guloader sample that is available on GitHub.

In early September 2022, we discovered a Guloader variant with low VirusTotal detection. Guloader (also known as CloudEye) is a malware downloader first discovered in December 2019.

We analyzed the control flow obfuscation technique used by this Guloader sample to create the IDA Processor module extension script so researchers can deobfuscate the sample automatically. The script can be applied to other malware families like Dridex, which utilize similar anti-analysis techniques.

Palo Alto Networks customers receive protections from malware families using similar anti-analysis techniques with Cortex XDR or the Next-Generation Firewall with cloud-delivered security services, including WildFire and Advanced Threat Prevention.

Related Unit 42 Topics Malware, anti-analysis

Guloader Control Flow Obfuscation Technique

The Guloader sample in question uses the control flow obfuscation technique to hide its functionalities and evade detection. This technique impedes both static and dynamic analysis.

First, let’s look at how this threat hampers static analysis. In short, it uses CPU instructions that trigger exceptions, resulting in unintelligible code during static analysis.

After peeling away the packer layer of our Guloader sample, we see that its code is obfuscated. Using static analysis tools such as IDA Pro, we observe many 0xCC bytes (or int3 instructions) littered throughout the sample, as shown in Figure 1.

Following the 0xCC bytes are junk instructions. These added bytes disrupt the static analysis tool’s disassembly process, resulting in the wrong disassembly listing.

Scrolling through obfuscated code to show 0xCC bytes throughout.
Figure 1. Obfuscated code blocks.

0xCC bytes are CPU instructions that trigger an exception EXCEPTION_BREAKPOINT (0x80000003), which pauses the execution of a process. The CPU will pass the code flow to the handler function before the execution continues. The handler function is responsible for moving the instruction pointer to the correct address.

The presence of these same 0xCC bytes make it so that using a debugger during dynamic analysis would crash the Guloader sample. Debuggers insert 0xCC bytes as software breakpoints to halt the execution of the sample. The debugger handles the exception instead of the handler function.

Before understanding what happens in the handler function, we first have to locate its address.

Guloader uses the AddVectoredExceptionHandler function to register the handler function, as shown in Figure 2. The second argument of the AddVectoredExceptionHandler function points to the address of the handler function.

Function prototype of AddVectoredExceptionHandler used to register the handler function.
Figure 2. Function prototype of AddVectoredExceptionHandler.

Using a debugger as shown in Figure 3, we locate the address of the handler function registered by the Guloader sample. With the address information, we can examine its code. Notably, this ExceptionHandler is registered with the order of 1, meaning it is the first handler to be invoked.

Using a debugger to locate the address of the AddVectoredExceptionHandler function registered by the Guloader sample.
Figure 3. Debugging the call to AddVectoredExceptionHandler in Guloader sample.

Analyzing the Vectored Exception Handler Function

The first step of analyzing the handler function is to apply its type information, as shown in Figure 4.

Showing the type information for the handler function.
Figure 4. Type information for the handler function.

Next, we apply the type information for three Windows data structures (shown in Figure 5) used by the handler function.

Showing the type information of three Windows data structures to be applied on the handler function.
Figure 5. Type information of three Windows data structures to be applied on the handler function.

With the type information applied, we can examine how the function handled the exceptions caused by the 0xCC bytes. Figure 6 shows the decompiled handler function (Func_VectoredExceptionHandler) annotated with comments.

Decompiled handler function (Func_VectoredExceptionHandler) annotated with the following comments: "Check type of exception raised," "Check for hardware breakpoint," "CC byte raising exception," "Decode offset byte," "Loop to check for software breakpoint," "Exit handler function if software breakpoint is found," and "Update EIP with offset."
Figure 6. Decompiled handler function.

The handler function begins with anti-debugging checks. It will terminate execution when hardware or software breakpoints are found. Next, the offset value is computed by XOR decoding the byte after the 0xCC byte with 0xA9. Finally, the offset value is added to the instruction pointer before the code execution resumes. Code execution continues at the address pointed to by the updated instruction pointer.

After understanding how the obfuscation is carried out, we can identify the legitimate instructions and discard the unwanted ones, as shown in Figure 7.

Labeled code block so we can identify the legitimate instructions and discard the unwanted ones
Figure 7. Labeled code block.

To completely deobfuscate the Guloader sample, we need to replace all the 0xCC bytes with a JMP short instruction (0xEB) and the following byte with the decoded offset value.

Because doing all this manually is time consuming, in the next section we will show you how to write an IDA Processor module extension to automate the deobfuscation process.

Writing an IDA Processor Module Extension

IDA Processor module extensions allow us to influence the disassembler logic in IDA Pro. These extensions are written using Python to enable us to filter and manipulate how IDA Pro disassembles the instructions in the sample.

The Python script extends the ev_ana_insn method in the IDP_Hooks class. It starts by checking if the current instruction is the 0xCC byte. Next, the 0xCC byte is replaced with the JMP short instruction (0xEB). Finally, the following byte is replaced with the decoded offset value.

Figure 8 shows the function in the Python script where this deobfuscation is implemented.

Function in the Python script where we're extending the ev_ana_insn() to deobfuscate the sample.
Figure 8. Extending the ev_ana_insn() to deobfuscate the sample.

After applying the Python script, IDA Pro can deobfuscate the Guloader sample automatically, as shown in Figure 9.

Code before and after applying the Python script so IDA Pro can deobfuscate the Guloader sample automatically
Figure 9: Obfuscated code (left) and code block after deobfuscation (right).

Conclusion: Malware Analysts vs. Malware Authors

Malware authors often include obfuscation techniques, hoping that they will increase the time and resources required for malware analysts to process their creations. Using the steps above, you can reduce the time needed to analyze these malware samples from Guloader, as well as those of other families using similar techniques.

Palo Alto Networks customers receive protections from malware families using similar anti-analysis techniques with Cortex XDR or the Next-Generation Firewall with cloud-delivered security services, including WildFire and Advanced Threat Prevention.

Indicators of Compromise

SQ21002728.IMG:
SHA256: fb8e52ec2e9d21a30d7b4dee8721d890a4fbec48103a021e9c04dfb897b71060
SQ21002764

SQ21002728.vbs:
SHA256: 56cdfaa44070c2ad164bd1e7f26744a2ffe54487c2d53d3ae318d842c6f56178
SQ21002764

Additional Resources

 

Enlarged Image