Gacrux – a basic C malware with a custom PE loader
I was given two samples of the malware known as Gacrux recently. Due to the nature of the source of the files, I won’t be able to share the hash or the files publicly, but it should be relatively easy to recognize this malware with the information provided here. The loader was developed in C and compiled with Visual Studio 2017. The malware is sold on certain forums starting from around August 2020, and appears to be heavily inspired by Smoke Loader.
Gacrux features a few anti-debugging and anti-VM tricks. The first trick involves the following jumps, which leads IDA to inaccurately disassembling the instructions after.
This can easily be fixed by patching the bytes following the pair of jumps with nops. After pattern scanning and fixing this, the file can mostly be decompiled with IDA easily.
The next trick involves fake returns that disrupt IDA’s function analysis. Like before, it is easily dealt with by NOPping out the offenders.
The final obfuscation involves two functions being encrypted on disk. The decryption done right before the function is called, and the function is re-encrypted shortly afterward.
The decryption/encryption works by finding two patterns within the function that signifies the beginning and end of the encrypted region. The code in between is then XORed with a key that is passed to the function.
The bot checks the available disk space and RAM size as its anti-VM check. This is easily mitigated by breakpointing on and modifying the return value, or simply nopping out the checks.
Strings are stored in a function which decrypts them based on the ID that was passed in.
The list of strings for the outer module can be found here.
Overall execution flow
Anti-debug and anti-VM tricks
There are some anti-debug tricks littered throughout the code. They are for the most part mixed into important functions and will crash the process if a debugger or VM is detected. The first trick is located in the malloc function, it checks the BeingDebugged member of the PEB, if it is set the function will return the size of the requested buffer instead of allocating it. In addition to this, it checks for blacklisted modules and exits if any are present.
The second trick increments the PID of explorer if the system has too little RAM or disk space – often a sign of virtualization. This would of course result in NtOpenProcess failing and prevent execution from proceeding any further.
The injected initialization shellcode/custom PE loader (which will be explored in further details later) also performs a check of the BeingDebugged and NtGlobalFlag members of the PEB.
The syscall module is almost entirely copied from an open-source crypter.
The hashing algorithm has been changed to djb2, with the output being xored with a constant value.
Persistence is achieved via a Window Procedure that is repeatedly called inside the context of explorer.exe. This procedure checks the installed file and creates the startup .lnk file in the startup directory if it is not present.
For code injection, Gacrux uses NtCreateSection/NtMapViewOfSection as the write primitive on 32-bit environments, and NtAllocateVirtualMemory/NtWriteVirtualMemory on 64-bit environments, both done via direct syscalls. For the execution primitive, it abuses SetPropA as detailed by Adam in his article “PROPagate – a new code injection trick“. This is copied from open-source implementations, as evidenced by the way the function pointer is set up.
The injection is used to invoke a tiny custom PE loader, which’s description follows.
Custom PE Loader and format
This is the most interesting feature of Gacrux. The code injected into explorer is not a regular PE file but rather one with a customized PE header and a customized loader.
The loader first has some antidebug checks.
Then, it resolves 3 APIs and uses them to process the import table and fix up relocation.
Finally, it flushes the instruction cache and calls the entrypoint.
The PE Loader utilizes a custom PE format, the Kaitai descriptor for it can be found here. With the information listed, we can easily restore the original PE file.
I do not have access to any module files and as such cannot describe them. The module loader is entirely copy-pasted from the MemoryModule project on Github.
Networking uses WinInet. This is done from the context of explorer after injection of course.
As we can see, there is not much that is special when it comes to Gacrux. It copies a lot of public code with slight modifications and is filled with bugs (which I have not described in the article as I have no intention of helping the author fix them). The custom PE format was quite interesting to look at, and I had some fun reverse engineering that.