Sitemap

Dancing With Shellcodes: Cracking the latest version of Guloader

14 min readApr 19, 2021

Guloader is a downloader that has been active since 2019. It is known to deliver various malware, more notably: Agent-Tesla, Netwire, FormBook, Nanocore, and Parallax RAT.

The malware architecture consists of a VB wrapper and a shellcode that does all the malicious activities of Guloader. Although many malware use crypters that have shellcode in their initial droppers, the Guloader shellcode is notorious for its anti-analysis capabilities; thus making the unpacking mechanism of Guloader much more challenging.

The majority of the anti-analysis functionality of Guloader is already published by several security researchers. However, for researchers who are not 100% familiar with the Guloader shellcode, it could be challenging to predict where these features are located, which might lead to failure in analysis.

In this article, I will present a step-by-step dynamic analysis of Guloader. As well, the malware anti-analysis functions, and how to overcome them.
Also, I will demonstrate the malware’s main objectives.

Note- Guloader heavily uses time checks and other traditional anti-analysis techniques. Therefore, to save time, in this analysis I will use the ScyllaHide plugin.
Also, several of the Guloader’s anti-analysis techniques are impossible to evade without manual intervention. So I will mainly (but not only) focus on them.

File metadata

Hash: d55259bcf47af7e645ab7b003aa2cd4071cb36c6

Press enter or click to view image in full size
Sample metadata in Pestudio

Getting into the shellcode

In its initial state, Guloader is wrapped with a VB. To overcome it, we’ll first reach the entry point and then set a breakpoint on VirtualAlloc. Next, we will click Run 12 times (the VB wrapper calls several times to VirtualAlloc, but we only care about the 12th time).

As we return to user code from the 12th VirtualAlloc, we will see the next image

Press enter or click to view image in full size
12th VirtualAlloc

Now, Guloader will write the shellcode to this newly allocated memory - The process consists of several JMP instructions. Scroll down until you’ll see a CALL to the register EDI (the place where the shellcode is eventually stored). Taking this CALL will lead us to the shellcode itself.

Call the shellcode

Immediately after taking the CALL to EDI, we’ll see a jump to another location. Take this jump as well.

Take the jump

The shellcode

After taking the initial jump, we see three different functions. For our unpacking tutorial, we can skip them and go straight to the JMP 602766, located at the end.

Take the jump

After taking the jump, we see an immediate CALL to 600144, step into it.

Step into

Now, we see several functions and a JMP at the end. Also, we see that the first function is 6013A9.

Anti VM function

Anti-Analysis 1: Anti-VM

To our surprise, when we will try to step over the CALL to function 6031A9 we encounter the following message box.

Gotcha

Why did it happen?

Without paying attention, the shellcode pushed 8 pre-computed hashes into the stack, in the following order:
push 0xB314751D
push 0xA7C53F01
push 0x7F21185B
push 0x3E17ADE6
push 0xF21FD920
push 0x27AA3188
push 0xDFCB8F12
push 0x2D9CC76C
These hashes will be used by the function 6031A9 in the following manner:
1) The function will use the API call ZwQueryVirtualMemory (the kernel equivalent of VirtualQuery) to scan the process’s memory.

2) The pre-computed hashes will be calculated using the djb2 algorithm. Each one of them will represent a string that is related to a Virtual Machine product (for example 0xB314751D represents “vmtoolsdControlWndClass”).

3) If one of these strings will be found by the ZwQueryVirtualMemory, the process will create the previously mentioned message box.

How we overcome this anti-VM technique?

There are three different approaches we can take:
1) The first approach is to change the pre-computed hashes on the stack before the call to 6031A9.
2) Fill the CALL line with no operation (NOP)
3) Change the control flow by redirecting the EIP register to contain the address of the next instruction (after the CALL to 6031A9)

For this example, I took the first approach and changed the hashes suffix to “22”.

Press enter or click to view image in full size
Changing the hashes on the stack

As we continue to step over to the next functions, we encounter the function 601F28, which is 2 functions below 6031A9 (the anti-VM function).

Anti-Analysis 2: Time checks & CPUID

If we will try to step over this function, we’ll see that we are stuck and can't move forward.

Anti-Analysis function

Why did it happen?

Inside the function 601F28, there is another routine that consists of two anti-analysis mechanisms. Time cheks using RDTSC (Read Time-Stamp Counter), and anti-VM using CPUID.

Anti-Analysis function

How we overcome this anti-analysis?

Similar to the first anti-VM, we can change the control flow with the EIP register, or fill the line of the CALL to 601F28 with NOPS.

After choosing our preferred method, we can go to the next JMP instruction.