GuLoader Anti reverse engineering techniques
Please read the disclaimer
In this quick blog post, we take a look specifically at the Anti reverse engineer techniques used by a recent GuLoader sample. This blog post can be used a reference for other researchers to understand the techniques used by GuLoader.
Code obfuscation through jumps
We can see the malware obfuscate the assembly code by using unconditional jumps to mess up the disassembly.
Opaque predicate in conditional jumps
In other word, it will always evaluate to either a false or a true statement, this is used to fool the disassembler that there is 2 paths but in reality it is just one single path.
Obfuscation of functions parameters through arithmetic calculation
In this example we see the parameter of get_func_address is xored multiple time.
Dynamic retrieval of WinAPI function addresses
It first parse the PEB_LDR_DATA of PEB structure of the process, locates kernel32, then looks for LoadLibraryA function. Then the malware parse the library, hash function names with DJB2 hashing algorithm and compare with the hash given as parameter to the function.
Xoring dexoring the .text instructions to break the disassembly view
Before calling a WINAPI, the malware xors the whole shellcode, then dexor it after calling the WINAPI function. The purpose of this technique is to break the dissasembly view (functions recognized by the disassembler, the graph view etc…)
Check for hardware and software breakpoints
The malware uses ZwGetThreadContext WINAPI to check if hardware breakpoints are set by checking DR0-7 registers.
It also check for software breakpoints before calling a WINAPI function by comparing it’s first bytes to 0xCC 0X3CD 0xB0F, if breakpoints are set the malware will crash itself.
Detect virtual machine through CPUID
Calling CPUID with eax set to 1 can be used to detect if the malicious code is running inside a virtual machine, a quick fix for this is to change the .vmx config file for vmware to always return 0 in the 31st bit.
Example: cpuid.1.ecx="0---:----:----:----:----:----:----:----"
to be added to the .vmx
Check if it is running in a 64bit machine
The shellcode checks if the machine is a 64 bit machine, if yes it will switch to 64bit mode.
Patching DbgBreakPoint && DbgUIRemoteBreakin
The malware patchs both DbgBreakPoint DbgUIRemoteBreakin to prevent debuggers from attaching to the process.
Count the number of application windows using EnumWindows
EnumWindows WINAPI is used to enumerate and count the open windows, this technique is used to detect sandboxes.
Check for QEMU
Guloader tries to open the following two files C:\Program Files\Qemu-ga\qemu-ga.exe
C:\Program Files\qga\qga.exe
, this files are related to Qemu emulator. It is used as sandbox detection
anti debugging NtSetInformationThread
NtSetInformationThread API with ThreadHideFromDebugger as parameter is used to hide the thread from a debugger, if a debugger is already present it will result in a crash.
Enumerate windows devices
The malware uses EnumDeviceDrivers and GetDeviceDriverBaseName to enumerate windows drivers, their names are hashed and compared to pre-hashed values.
Enumerate installed softwares
It uses MsiEnumProductsA MsiGetProductInfoA WINAPI to enumerate installed softwares, the names are hashed then compared to pre-hashed values.
Enumerate Services
The malware uses OpenSCManagerA and EnumServicesStatusA winAPI to enumerate services on the machine, the names are hashed then compared to pre-hashed values.
Retrieve the port number of the debugger for the process using the NtQueryInformationProcess
Guloader retrieve the port number of the debugger for the process using NtQueryInformationProcess API.
Injecting shellcode through process hollowing
The malware uses process hollowing injection technique to inject a similar shellcode with different capabilities, the following outlines the execution flow of the malware:
- It create a suspended process
RegAsm.exe
orMSBuild.exe
with CreateProcessInternalW API.
- It opens a handle to
C:\Windows\syswow64\msvbvm60.dll
with ZwOpenFile WINAPI.
- It creates a new section with
ZwCreateSection
WINAPI. - It maps the section in the created process using
NtMapViewOfSection
WINAPI. - It writes the shellcode to the memory with
NtWriteVirtualMemory
WINAPI. - It change the Instruction pointer of the process to the start of the injected shellcode with
NtSetContextThread
WINAPI. - Finally, it resume the thead with
NtResumeThread
WINAPI.
After bypassing all the anti reverse engineering mechanism, we can dump the second shellcode just before it calls for NtWriteVirtualMemory, another solution is to change the first bytes of the new shellcode to jmp 0x00
, then we can attach to it with a debugger and restore the original bytes.
The second shellcode is a copy of the first shellcode so all the anti reverse engineering mechanism enumerated above applies to it. The second shellcode downloads a payload from a google drive link and execute it.
Some hashes for reference:
- getcontextthread FAD4F3C4
- queryvirtualmemory 0F9CE5538
- kernel32 48522397
- LoadLibraryA 645AAB39
- NtAllocateVirtualMemory 4E829A87
- MSVBVM60 82AAF280
- ZwProtectVirtualMemory 85E648F6
- DbgBreakPoint 676E43AA
- DbgUiRemoteBreakin 0A3B0C16C
- TerminateProcess 9E059483
- EnumWindows BB301E26
- ExitProcess 98EC4D6B
- CreateFileA 97F9AE3
- NtSetInformationThread 0E9BE1A6F
- EnumDeviceDrivers 96ABEF9C
- vmmouse.sys 0D46C4133
- vm3dmp_loader.sys DC8850D2
- vm3dmp.sys 2B5C7A6B
- vmusbmouse.sys 5440D1F6
- MsiEnumProductsA 0E3F98748
- MsiGetProductInfoA 568AB98E
- ShellExecuteW 2A433AAE