In an earlier blog about crypto-malware, we described different techniques used by cybercriminals, such as cryptomining and wallet stealing. In this blog, we will provide a technical analysis of yet another type of cryptominer malware using a bootkit and other kernel-level shellcode for persistence.
The installer is responsible for infecting a system’s master boot record (MBR), which identifies how and where the operating system is located. It opens the boot drive (figure 1) and reads the first 0x400 bytes, which is MBR data.
Figure 1: Opens boot drive
It checks for GUID Partition Table (GPT) partition flag and doesn’t infect GPT disks (see figure 2).
Figure 2: Checking GPT Disk
It moves the clean MBR code from sector 0 to sector 1 (figure 3) and inserts malware code in sector 0 (figure 4). Malicious code is written from sector 2-53.
Figure 3: Clean MBR code
Figure 4: Infected MBR code
Analysis for malicious MBR
Malicious MBR code hooks 15h interrupt (figure 5). It specifically hooks for service 0xE820 of interrupt (int) 15h (figure 6). This service is used to query system memory.
Figure 5: Interrupt 15h hooking
Figure 6: Service 0xE820
After hooking, it loads the original MBR code to resume the booting process. During execution, when bootloader calls int 15h, malware code receives the control and verifies the AddressRangeDescriptor Type, BaseAddrLow, BaseAddrHigh, and LengthLow. After verification, it modifies the LengthLow value to hide the malicious MBR code (figure 7).
Figure 7: Hiding malware code
Loading in kernel
The malware uses different methods, depending on the Windows version, for loading into the kernel. Figure 8 lists the different ways for XP and 7 versions of Windows.
Figure 8: Flow of execution
In Windows XP, it patches code in BlLoadDeviceDriver function in osloader.exe. It also patches code in BlLoadDeviceDriver after it calls to function BlLoadImageEx. The BlLoadImageEx function maps all device drivers in memory. Ntoskrnl.exe will load and execute these drivers (IopInitializeBootDrivers->IopInitializeBuiltinDriver) (figure 9).
Figure 9: Comparison of patched and unpatched code of BlLoadDeviceDriver function
When osloader.exe tries to load the ftdisk.sys driver, it injects malicious shell code in the resource section and a modified entry point to malicious shellcode.
Figure 10: Searching for resource section and comparing section size for shellcode
Figure 11: Malware shellcode in the ftdisk.sys resource section
In Windows 7, the malware searches the address of the OslArchTransferToKernel function from OslpMain (entry point) in winload.exe. OslArchTransferToKernel transfers control to NTOSKRNL.EXE. The malware patches this function (figure 12) to get the loading address of NTOSKRNL.EXE.
Figure 12: Patched OslArchTransferToKernel function code
After getting control to NTOSKRNL.EXE, the malware patches ZwCreateSection API (figure 13).
Figure 13: Patched ZwCreateSection API
Analysis of kernel shellcode1:
This shellcode is responsible for hiding the malicious MBR code and preventing AV products from loading. Shellcode first retrieves the base address of ntoskrnl.exe and gets the address of different APIs. An undocumented field (at offset 0x14) of DRIVE_OBJECT is used to retrieve the MODULE_ENTRY pointer and enumerated to get base address of ntoskrnl.exe (see figure14).
Figure 14: Searching for base address of ntoskrnl.exe
API names are stored as 32-bit hash values in the code. The ROR13 calculation method is used to generate hash values for each API name (figure 15).
Figure 15: API hash calculation
To stop AV systems from loading, the malware creates notification objects similar to the device names used in 360 AV product device drivers.
Figure 16: Holding AV-related device names
Hiding Malicious MBR code
Different low-level drivers are patched to hide malicious MBR code. In Windows XP, the IdePortStartIo function of atapi.sys is hooked (figure 17).
Figure 17: Hooking IdePortStartIo function of atapi.sys
The hooking function specifically looks for read and write requests (figure 18). If there is a read request for sector 0-61, it hooks CompletionRoutine of IRP sent to atapiDeviceObject and serves a clean MBR code.
Figure 18: Checking SCSI command descriptor block (CDB) for read and write request
If there is a write request for sector 0-61, the malware modifies the operation code in command descriptor block (CDB) and SrbFlags flags of SCSI_REQUEST_BLOCK object. The operation code is changed to 0x28 (SCSIOP_READ) and the SrbFlags are set to SRB_FLAGS_DATA_IN which indicates that it is a read operation. So, the write request is simply converted to a read request and passed to the driver. Figure 19 shows the execution flow of the MBR hiding function.
Figure 19: IdePortStartIo hook function execution flow
Analysis of kernel shellcode 2:
This shellcode executes as a system thread but terminates itself if the system is booting in safe mode. It searches for the explorer.exe process and injects usermode shellcode (referred as ushellcode1 afterword). Ushellcode1 is compressed using LZ compression with COMPRESSION_ENGINE_MAXIMUM flag (figure 20).
Figure 20: First usermode shellcode
Ushellcode1 is injected in explorer.exe with thread data, which is shared memory between the kernel mode thread and ushellcode1 thread, as shown in figure 21. The remote APC thread technique, KeInitializeApc, and KeInsertQueueApc kernel APIs are used to achieve this. It also executes downloaded kernel shellcode by the ushellcode1.
Figure 21: Thread data
In the second step, it searches for processes related to different security software solutions (table 1) and terminates the process.
Analysis of ushellcode1
This shellcode downloads another shellcode and a config file. The config file is encrypted (using simple XOR) and saved in C:\Windows\Temp\ntuser.dat file.
Figure 22: Downloading config file
The config file contains different URL addresses, used to download further shellcodes and config files. Content of the config file is shown in figure 23. For the IPs mentioned under the main section, it appends the “TestMsg.tmp” string at the end URL to generate a full URL, which serves as shellcode. Similarly, for all the URLs mentioned under section [update] as seen below, it appends string “address.txt” so these URLs are used to download the updated config file.
Figure 23: Config file content
The downloaded shellcode continues to download the final payload using information from the new config file (figure 24). The payload is saved in the %SYSTEMROOT%\\TEMP folder with the name conhost.exe (figure 25) and executed with the “-C create -r” parameter.
Figure 24: new config file contents
Figure 25: Download of final payload
Analysis of payload
This payload works as a downloader. During our analysis, we found it downloading a cryptomining tool. It registers itself as a Windows service with name “Windows Audio Control.” It supports different command line options (figure 26), including the main ones: Create, delete, start, and stop services.
Figure 26: Different command line options.
Upon executing without any command, it first downloads xpxmr.dat file that contains a list of C&C IP addresses and URLs. This config file is saved in the C:\Program Files\Common Files folder. It also downloads the below config files:
Contains new version of the malware payload; if it does not match the current version, a new version will be downloaded
Receives the URL for downloading additional malware payloads
This file contains the name of processes to terminate and file paths to delete
Zscaler detects this threat via following signatures:
Cloud Sandbox Report showing the detonation activity for this malware can be seen below: