Qbot or Qakbot is a sophisticated worm with banking capabilities. This malware family has been infecting computers since 2009, utilizing a number of techniques (some of them quite advanced) which make it difficult to detect. It has a packing layer, anti-VM techniques, anti-debug techniques, and anti-sandbox techniques which make the analysis of this threat difficult. Qakbot is capable of updating itself and this also makes this threat more complex to detect since it is constantly changing on disk.
Using Triage we analyzed the most recent variant of this malware, and we added a new module to support the detection and configuration extraction of Qakbot samples as shown in the image below. A tool to deobfuscate the Qakbot payload is also included (qakbuscator.py).
Qakbot family detection in Hatching Triage
Qakbot config extraction Hatching Triage
Qakbot has a custom packer. There are probably other versions of Qakbot in the wild with different packers, but this section is based on analysis of the packer for the sample: e736cf964b998e582fd2c191a0c9865814b632a315435f80798dd2a239a5e5f5.
In summary, the unpacking process is as follows:
The unpacking process
The packer allocates memory and then drops an encrypted buffer there (Step 1-2).
The dropped buffer is decrypted and the decrypted data contains a PE file (Step 3). This PE file is not at the beginning of the buffer but starts at offset 0x427. From the beginning to the PE file offset is filled with 0x00 bytes.
Offset is filled with ``0x00`` bytes
This could be a trick to make analysts think that this function is “freeing memory” or that it’s a memset-like function.
The PE header is modified - this can also confuse analysts or memory dumping tools that look for PE file signatures since they can’t find the “MZ” magic number. This is shown in the image below.
Modified PE header
The decrypted PE file image size is calculated to allocate memory for it. The PE file is copied (mapped as a windows loader would do) from the decrypted buffer to the newly allocated memory (Step 3-4).
The PE is copied over
Mapping file to Allocated Memory
Once the file is mapped to the newly allocated memory, the header is fixed as shown in the following image. Once the PE file is mapped its entry point is called. (Step 4)
Calling the entry point
This PE is going to read the rest of the previous decrypted buffer since there is still some encrypted data. Once the data is decrypted a new PE file can be found. (Step 4-5)
The new PE file
This time the header is also modified and is fixed before mapping it. (Step 5-6)
New PE file with new header
The decrypted PE is Qakbot itself. In this case the PE header doesn’t have the well-known string “This program cannot be run in DOS mode”, because the DOS-Stub was deleted.
This PE file is the final payload of Qakbot so finally the PE file is mapped to the ImageBaseAddress of the original file (Step 6).
The original image loaded at address 0x400000 is wiped.
The address 0x400000 is wiped
The newly unpacked PE (Qakbot) is copied to the original image base address 0x400000.
Qakbot copied over to 0x400000
So, after mapping the Qakbot binary the execution flow goes to the EntryPoint of this file. (Step 7).
The unpacked sample hash of the file we ran in Triage: 850ff92b7f3badda4bd4eca0a54fbdea410667db1ea27db8069337bf451078d1
Once the sample is unpacked, Qakbot itself also implements an obfuscation layer in its code. This obfuscation makes the analysis a bit harder. The flow graph of the main function is the following:
The obfuscation basically consists of adding unused loops with an empty body. Like the following:
As is shown in the image above, it does a "XOR EAX, EAX" operation and then decides to loop or not depending on the Z flag which is set with the previous instruction (so the loop will never happen). The goal of these small loops is to make a less comprehensive flow graph and to make the analysis harder. There are more than 600 loops like this throughout the code.
At Hatching, we implemented a tool (qakbuscator.py) to deobfuscate the code and make the analysis much easier. This tool is provided with this analysis to allow all researchers to use it.
The DLLs that are in the Qakbot resources also have this obfuscation layer - you can use the script to deobfuscate them.
The sample used to perform the behavioral analysis is the deobfuscated sample using our deobfuscator tool explained in the previous section.
This is how a process tree of a Qakbot infection looks like:
Process tree after Qakbot infection
Regardless of the input vector, the first time Qakbot runs it tries to install itself.
First of all, it checks if it is running in a virtualized environment or not. Qakbot executes itself with the option "/C". Qakbot admits parameters, in this case the parameter "/C" is to make anti-VM and anti-sandbox checks like the following ones:
Reading from the virtual port in order to detect VMWare
Check the CPUID
There are also other techniques used by Qakbot to know if it is running in an emulated environment like checking the sample name - in order to see if it is set to some default name like “sample.exe” or “malware.exe”; or checking running processes in order to detect any related to a virtual environments, anti-virus, debuggers etc.
Among the different options that Qakbot accepts we can find the following:
|/I [name]||Disable Windows SpyNey and delete scheduled task [name]|
|/P[file]||Decrypt [file] and load it|
|/Q||Set exit status to 0x6F|
|/T||Sync related stuff|
|/i [name]||Install itself and delete scheduled task [name]|
|/t||Send Window Message|
|/A  ||Unknown|
If a VM is detected it exits. Otherwise, it copies itself into %APPDATA% under a randomly generated folder with a randomly generated name. Those names are unique for each infected machine since they are created using some characteristics from infected host.
Copying to %APPDATA%
It also creates the following registry key in order to be run when the system reboots “HKCUSoftwareMicrosoftWindowsCurrentVersionRun”.
Run on system boot
Also, it drops a .dat file that has configuration information, like botnet name, timestamp, etc. This file contains encrypted data which is decrypted in memory during run time. Once this file is decrypted it looks like is shown in the image below.
The following table, from a blog post by the security researcher Vitaly Kremez (link) , shows the meanings of some of these config values:
|11 = 2 (number of hardcoded C2)|
|1 = date of qbot install in HH:MM:ss-dd/mm/yyyy|
|2 = victim qbot install|
|45 = C2 IP|
|46 = C2 Port|
|39 = victim external IP|
|38 = last victim call to C2 (time in Unix)|
|43 = time of record ((time in Unix)|
|5 = victim network shares|
Finally, the copied file is executed and the original file is overwritten with calc.exe. Some malware deletes the file directly, but Qakbot has decided to overwrite it with a legitimate binary. This way it doesn't leave traces.
Overwriting with legitimate binary
When Qakbot is installed, its behavior is different. In this case, it is going to create an instance of the explorer.exe process in order to inject itself into it.
Once injected into explorer, the main .dll is loaded. At this point, different things could happen since the communication with the control panel begins. As shown in the process tree above, the explorer process executes an update of Qakbot directly downloaded from the C&C. Also, it can exfiltrate data, or infect browsers in order to get banking information from the victim system.
Qakbot update sample: https://tria.ge/reports/191104-athqk1tjxn/task2
In Triage we’ve just added support for this family, meaning you can detect Qakbot as well as get its configuration directly after the analysis.
Qakbot in Triage
The Triage report for the sample that was used for this blog can be found here.
|Qakbot resource 1 (main.dll)||83273809a35ba26c2fb30cba58ba437004483ae754babad63c5d168113efa430|
|Deobfuscated Qakbot resource 1 (main.dll)||74f8907acfd070d2590895523433a8c85b5ef87f4e1a5ef7ccd356f5562b7a6b|
|Qakbot resource 2 (injects dll x86)||b7d9a462bd105193e998b6324f3343b84f11ceb21ab24e60e2580a26d95e4494|
|Qakbot resource 3 (injects dll x64)||8c7a43002ee6105fc37fcdfc00a192239639f7c08bf28e06ca1432551fe21b3f|
Here is a list of related samples and their corresponding Triage reports.