Sality has been around for many years, yet it is still one of today’s most prevalent pieces of malware. In this two-part article, Raul Alvarez takes a close look at a variant of Sality that not only infects executables but also has some trojan-like attributes.
Copyright © 2014 Virus Bulletin
Sality has been around for many years, yet it is still one of today’s most prevalent pieces of malware.
In this article, we will concentrate on a variant of Sality that not only infects executables but also has some trojan-like attributes. Although such a combination of malicious functions is not uncommon in malware nowadays, it is important to study them to give us an insight into why these pieces of malware are so persistent in our digital world.
There are two parts to this article: the first discusses the multiple decryption, decoding and other algorithms that make this malware very evasive. It also discusses the main thread and the thread that performs some system manipulation. The second part (which will be published next month) will discuss the first layer threads spawned from the main thread, and some further threads generated by them.
This variant of Sality has a launcher executable. Before it infects any files, it prepares for the infector codes to be executed in a different context.
The malware parses the PEB (Process Environment Block) to obtain the path name of the module found in the first InLoadOrderModuleList structure and save it for future use.
It then parses the hex bytes starting at the entry point of the malware code, looking for the character ‘M’. Every time an ‘M’ is found, it checks whether the next two bytes are the characters ‘^4’ – it will keep searching for an exact match.
‘M^4’ is a terminating marker used by the malware to identify the boundary within its code. Immediately after the marker is the size (0x434) of the encrypted hex bytes for later processing.
A call to the VirtualAlloc or VirtualAllocEx API is a common method used by malware to create a space in virtual memory. The newly created virtual memory space serves as a memory scratch pad for the malware. It can be used as a swapping space when the malware is performing a decryption/encryption routine, moving hex bytes from file to memory or vice versa, and anything else that requires memory manipulation.
However, Sality does things a little differently: instead of creating virtual memory using the aforementioned APIs, it uses the available memory space allocated for the stack. To make sure that it won’t destroy any data currently being used in the stack, Sality sets an address pointer away from the commonly used area. It adds 0xFFFF81DF to the current base pointer (EBP) and sets it as the initial location for data manipulation.
Once the initial location has been set, the malware copies 0x434 hex bytes to the stack memory. These hex bytes come from the malware body starting at the boundary address discussed earlier. The exact starting location is the boundary address, which is found after the terminating marker (‘M^4’), plus 0x14.
After copying 0x434 bytes from the malware’s memory space to the stack memory, Sality decrypts the code twice.
On the first pass, the malware decrypts the code byte-by-byte using a simple SUB (subtract) instruction. It reads a byte from the stack, subtracts 0x1420 (value taken from the fifth byte of the terminating marker ‘M^4’), and stores the resulting byte back on the stack. It will perform the subtraction for the 0x434 bytes found in the stack.
On the second pass, the process is repeated for the 0x434 bytes, but instead of using subtraction, the malware will use a simple XOR for each byte. The XOR key is the same key (0x1420) as is used in the subtraction routine, plus 7. The instruction will be ‘XOR byte, 0x1427’.
The SUB and XOR instructions use a DWORD every time they decrypt the malware code, but only the resulting bytes (i.e. not the whole DWORD) are relevant to the malware.
After the decryption routine, the malware saves the location of the base64-encoded block of code found within the malware body. Then it transfers execution to the start of the newly decrypted code in the stack.
At the beginning of the newly decrypted code, Sality parses the PEB again to obtain the path name of the current module. After removing the drive letter from the path name, the malware checks if the first letter of the current executable starts with ‘m’ or if the second letter is ‘y’. If it is either of these, it will jump straight to the location of the base64 encoded block. The malware assumes that this block is already decoded.
The malware also checks if the 12th character of the path name is ‘e’, and if it is, then it assumes that the block is decoded. The malware also assumes that it is one of its own executables
If the above conditions are not met, Sality proceeds with setting up the characters used for its custom base64 encoding scheme. The malware uses the same technique as that used for decoding base64-encoded text but using a different index character. The sequence of 64 characters used for this variant of Sality is ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/’, which is slightly different from the standard base64 encoding characters.
The malware decodes 0x1DD76 text characters to generate an equivalent of 0x16618 bytes of yet another encrypted piece of code (see Figure 1).
(To view a larger version of Figure 1 please click here.)
The base64-decoded binaries are decrypted using the following algorithm:
XOR EDX,EDX MOV DL,BYTE PTR DS:[EAX+EBX] MOV ECX,EAX IMUL ECX,DWORD PTR SS:[EBP+10] XOR EDX,ECX MOV BYTE PTR DS:[EAX+EBX],DL INC EAX
Starting at the initial location of the decoded binary, each byte is placed at the DL register. The current location is saved from EAX to ECX, which is multiplied (IMUL) with a key (0x2210) found at DWORD PTR SS:[EBP+10]. The key (0x2210) is constant throughout the decryption routine.
Finally, the byte (DL) within the EDX register is XORed with ECX, the result of the multiplication. Then it is saved to the current memory location at BYTE PTR DS:[EAX+EBX].
After the decryption, control is passed to the decrypted binary codes (see Figure 1).
After the decoding and decryption process, the malware parses the PEB to get the base of kernel32.dll. Once the malware knows the location of kernel32.dll, it parses the export table to look for the GetProcAddress API, by checking each string in a list of API names found in the table.
Using the GetProcAddress API, the malware generates all the APIs needed for its malicious activities. Afterwards, it decrypts a block of binaries, producing an image of an executable file. The image contains a complete MZ/PE header, together with the rest of the code and data.
Sality could easily have dropped the executable file and run it, but instead the malware spawns a new process, using CreateProcessA in suspended mode. Note that the new process is a copy of itself with the same module name.
The decrypted image is then injected into the new process using the WriteProcessMemory API. A series of calls to this API copies the entire image, thus creating a completely new process that is different from the original Sality module.
This technique is not new, but it is fairly effective against heuristic detection that monitors the dropping and executing of dropped files.
Once the set up is complete, the malware will resume the suspended process and terminate the original application. Any break points set on the original process will not be triggered, thereby avoiding further analysis.
After spawning a new version of itself, Sality executes its malicious activities. However, these are not easy for an analyst to observe when the malware is loaded in the context of a debugger.
Within a debugger, the malware will decrypt most of its binaries and proceed to generate multiple threads. Once the first thread is generated, Sality will intentionally access a non-existent memory location to produce an exception that will crash the debugger.
In normal execution, the exception will be ignored since the new thread will be executed in its own context. But if it is inside a debugger, you have to find a way to execute the first thread before the main thread calls the exception.
The primary goal of the main thread is to decrypt the malware code for its execution. Every four bytes (DWORD) are decrypted using 32 iterations with 403 instructions per iteration. In other words, it will take an estimated 12,896 instructions just to decrypt a single DWORD. Even tracing through the code takes time just to figure out the exact location of the initial DWORD.
A significant number of IMUL, SHL and jump instructions are allocated to perform the decryption for each WORD. The extensive jump instructions will lead you almost everywhere in the code.
After decrypting (0xFEE8) 65,256 bytes, Sality transfers control to the newly decrypted code.
As it did in the initial process, Sality parses the PEB to get hold of kernel32.dll. Then it parses the list of API names in kernel32’s export table to look for the LoadLibraryExA and GetProcAddress APIs.
To make sure that the malware has the right kernel32, it reloads kernel32.dll using the LoadLibraryExA API and uses the GetProcAddress API to resolve the rest of the APIs that it needs.
Sality creates two file mapping objects, namely ‘hh8geqpHJTkdns0’ and ‘purity_control_90833’ with INVALID_HANDLE_VALUE as file handles. The resulting file mapping objects are not associated with any regular file. They are basically used as names for the newly generated section of memory (see Figure 2).
A call to the MapViewOfFile API with the handle set to the ‘purity_control_90833’ file-mapping object generates a memory space in a similar way to calling the VirtualAlloc API. This is followed by copying the 65,256 bytes decrypted earlier to the new virtual memory space.
Afterwards, it creates a new thread that will run in its own context. The newly created thread sends a signal to the main thread indicating that it is executing properly – if the main thread does not receive such a signal it will generate an exception.
The main thread is also responsible for spawning the first layer threads.
This thread stores the filename of the current process and creates a mutex named ‘uxJLpe1m’. It then creates a virtual memory space using the VirtualAlloc API and copies the executable image. This executable image is taken from the 65,256 bytes decrypted from the main thread. The image has the regular MZ/PE header and section names UPX0, UPX1 and UPX2, indicating that it is a UPX packed executable. This is followed by resolving the APIs it needs before transferring control to the UPX executable in memory.
Within the UPX, the initial step is to unpack the malware’s main code. After unpacking, Sality initializes the use of Windows Sockets functions by calling the WSAStartup API, for later use.
This is followed by setting the files and folders views to hidden by changing the registry entry ‘Hidden’ to 2 within the [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] key (see Figure 3).
Within the System Configuration thread, Sality sets the following data found in the [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Security Center] key:
AntiVirusOverride AntiVirusDisableNotify FirewallDisableNotify FirewallOverride UpdatesDisableNotify UacDisableNotify
Setting these values to 1 disables AV, firewall, and UAC related notifications. Normally, these notifications remind and notify the user about the status of their anti virus software, firewall and User Access Control settings – for example, warning the user if the AV software needs an update, if the firewall is turned off, or if a file access is using an inadvisable security level.
It also creates and sets the same set of data found in the [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Security Center\Svc] key.
After setting the Security Center’s registry keys, the malware makes sure that Internet Explorer is not in offline mode by setting [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\GlobalUserOffline] to 0.
Still within the System Configuration thread, Sality also disables the UAC (User Account Control) by setting the EnableLUA subkey to 0 from the [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system] key.
UAC is a security feature of the operating system that prompts the user for permission if an event or action could potentially harm the computer. Disabling this feature could help Sality to carry out some of its malicious activities without being noticed.
Finally, Sality adds its current module name to the firewall’s exceptions list in [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List], simply to bypass the firewall blocking. The module name is in the form <modulename>:*:Enabled:ipsec.
The malware is a little paranoid. It not only adds itself to the firewall’s exceptions list but it also disables the firewall by setting the EnableFirewall subkey to 0. And to make sure that exceptions are allowed, it disables the DoNotAllowExceptions subkey. Notifications are also disabled by placing the value 1 in the DisableNotifications subkey. The subkeys can be found in the [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile] key.
Sality spawns one thread after another. Each thread is dedicated to a specific task, although some threads simply wait for information provided by others. We have already seen some threads in action here. In the second part of the article, we will discuss those used for code injection, file infection, and some others in between.