Threat Research

Salted Algorithm - Part 2

By Raul Alvarez | July 30, 2012

date: 2014-05-01 01:00:00 -0700

category: "Security Research"


This article originally appeared in Virus Bulletin



For Part 1 of this article Click Here


Sality has been around for many years, yet it is still one of today's most prevalent pieces of malware. Last month, we described Sality's algorithm, showing the strengths of its encryption, how it uses the stack as temporary memory for code manipulation, and some of its system configuration manipulation [1].

In this follow-up article, we will continue to discuss some of the threads spawned by Sality, including those for file infection, code injection, and so on.

Infection Thread

Sality was originally defined as a file infector. However, recent variants have shown that Sality is capable of far more than that.

Let's look at the malware's infection routine.

Sality searches for files to infect starting at the root directory. It traverses all folders and files in alphabetical order. When it finds a folder, it checks all subfolders and files within it, leaving no stone unturned.

Whenever a new subfolder is found, Sality reinitializes all the required variables and data to zero. It sleeps for 2,048 milliseconds before proceeding with the rest of the routine.

The malware checks whether the current pathname contains 'c:\windows'. If the path doesn't contain this string, it will start looking for files to infect. It queries the given pathname for all files using a regular call to the FindFirstFileA and FindNextFileA APIs.

Sality looks for EXE and SCR files to infect. If the extension name of the file is either 'EXE' or 'SCR', it will continue to process the file. Otherwise, it will skip the rest of the process and look for another file.

When it finds a file with an appropriate extension name, Sality parses the filename to determine whether it contains any strings from a list of names of anti-virus and security applications. If the filename doesn't contain any such strings, Sality will proceed to infect the file. Otherwise, it skips the file without infecting it.

Infection Routine

The same check for strings containing names of anti-virus and security applications is applied to the path name of the current host file. This is a redundant check to make sure that everything is working according to plan.

Since Sality queries all files in the hard drive, it makes sure that system files will not be infected by using the SfcIsFileProtected API. This API is one of the functions under Windows Resource Protection (WRP) that prevents the modification of important system files in Windows. If a potential host file has WRP protection, the malware will skip the file and search for another.

If a file is suitable for infection, Sality saves its attributes after a call to the GetFileAttributesA API, and sets the 'FILE_ATTRIBUTE_ARCHIVE' attribute using the SetFileAttributesA API, for easier processing of the host file. Then it calls the CreateFileA API to open the host file with GENERIC_READ and GENERIC_WRITE access, and FILE_SHARE_READ and FILE_SHARE_WRITE sharing modes.

Sality gets the file size of the host file and checks whether it is within (0x200) 512 bytes and (0x2800000) 41,943,040 bytes. If the file size meets the criteria, the next step is to call the GetFileTime API to save and preserve the file time of the host file.

After configuring the header of the host file in memory, Sality appends (0x11000) 69,632 bytes of malware code to the mapped file. The (0x11000) 69,632 bytes of code is the whole encrypted version of Sality. Finally, the UnmapViewOfFile API is called to flush all modifications made to the mapped file to the file in the disk.

Since the memory allocated to the mapped file is bigger than the actual infected file, the malware cuts the infected file just enough for the original code plus the malware code to fit in, using the SetFilePointer and SetEndOfFile APIs. The host file is now infected with Sality.

Further processing of the newly infected file is performed: the original file time is restored by calling the SetFileTime API using the file time that was saved prior to infection, and control of the infected file is released by calling the CloseHandle API. Sality is so meticulous that it also replaces the original file attributes of the infected file using the SetFileAttributes API.

The original file attributes and the original file time are saved before the file infection routine. They are restored to the infected file to avoid further suspicion. It is easy to notice that there is something wrong with your machine if all your executable files have the same time stamp. The file size is an avoidable risk, but of course, nobody memorizes the file sizes of each and every file on their machine.

After the infection, Sality sleeps for (0x400) 1,024 milliseconds before checking out the next file to infect. Earlier, we saw that Sality avoids infecting files within the folder containing the string 'c:\windows'. Further in the code, Sality also avoids files within a folder containing the string 'SYSTEM'. In this regard, the malware is playing it safe by avoiding the infection of files that are generally part of a standard Windows installation. It also prevents performance degradation by skipping the infection of critical executable files found in the Windows system.

Infection Marker

Once the infection routine has finished infecting all possible executable files, Sality will jump back to the root folder (c:\) to start the whole infection process again. It will look for new executable files to infect, skipping any files that are already infected within each folder.

To avoid reinfecting files, a standard file infector adds an infection marker as part of the infection process. This marker is checked every time the malware attempts to infect a file. Some infection markers are easily recognizable, and may even be used by anti-virus engines use to detect a particular variant. For Sality, the marker is not easy to spot.

For a quick view of the infected files, Sality zeroes-out the CRC checksum value of each infected file. It seems that this is an infection marker and anti-virus software can use this as part of a detection algorithm, since most regular executables have a non-zero value in their CRC checksum. The CRC checksum is located at offset 0x58 from the start of the PE header. Unfortunately, however, this is not what is checked by Sality to avoid reinfection.

Going back to the infection process: since Sality appends its code at the end of the host file, it is normal to reconfigure the values of the last section header. Sality increases the VirtualSize and SizeOfRawData values and makes sure the characteristics of the last section are EXECUTABLE, READABLE and WRITABLE. These are the normal values modified by most file infectors.

However, if you look more closely, each section header has a property called 'NumberOfLineNumbers' located at offset 0x22 from the start of the section header. This property contains zero for most executable files. Sality allocates a non-zero value to this property as part of the infection process. Since it will look like part of a regular infection algorithm, the malware assumes that it will be overlooked.

To avoid reinfection, Sality checks this value within its code. If the 'NumberOfLineNumbers' property is zero, the file is not yet infected and Sality will perform the infection routine. In the same respect, if an infected file somehow contains zero in the 'NumberOfLineNumbers' property, the file will be reinfected - it will keep reinfecting the file as long as the 'NumberOfLineNumbers' property is zero.

Meanwhile, if a clean executable file has a non-zero value in the 'NumberOfLineNumbers' property, Sality will skip the file, thinking that it is already infected.

Code Injection Thread

Spawned from the main thread, this thread is responsible for injecting code into remote processes. Its main goal is to search for processes to infect.

After allocating a section of global memory, Sality maps the section named 'purity_control_90833', containing (0x11000) 69,632 bytes of malware code, using the MapViewOfFile API. It then copies the contents of the section to the global memory space and unmaps it using the UnmapViewOfFile API.

Then, Sality parses the list of processes that are currently running in the system using a combination of the CreateToolhelp32Snapshot, Process32First and Process32Next APIs. The malware will skip processes that have a PID (process ID) that is less than or equal to 0x0A (basically, avoiding system processes).

Each process with a PID above 0x0A is subjected to the following routine:

Sality opens the process and queries its token using calls to the OpenProcess and OpenProcessToken APIs. The malware gets the SID (security identifier) of the process token using the GetTokenInformation API. Sality will determine the SID's account name by calling the LookupAccountSidA API. The resulting account name determines which user account has access to the given process.

If the account name is either 'SYSTEM', 'LOCAL SERVICE' or 'NETWORK SERVICE', Sality will create a mutex with the name format '{processname}M_%d_', producing, for example, 'smss.exeM_544_'. Afterwards, it will close the handle to the current process and get the next process in the list by using the Process32Next API. Then it repeats the same procedure all over again.

If the account name is anything but the three names mentioned above, Sality will allocate remote memory space within the remote process by calling the VirtualAllocEx API. This is followed by copying (0x2000) 8,192 bytes of code to the newly allocated memory using the WriteProcessMemory API and activating the remote thread using the CreateRemoteThread API. The injected code is a decrypted version of Sality and the initial execution is similar to that of the main thread, discussed in [1], without the decryption.


Figure 1: Remote thread injected into Notepad creating the mutex as a marker.

After activating a new thread in the remote process, Sality allocates another remote memory space, writes (0x1000) 4,096 bytes of code, and activates a new remote thread.

The second injected code creates a mutex with the same name format as before ('{processname}M_%d_'). For example, if the notepad.exe process is being infected, the second remote thread will create a mutex named 'notepad. exeM_194_', where 194 is the PID. The mutex name serves as the infection marker for the process to avoid reinfection (see Figure 1).

After activating the two remote threads, Sality gets the next process in the list by using the Process32Next API. Then it repeats the same routine again.

After performing the routine on all processes, the thread sleeps for (0x2800) 10,240 milliseconds. When it wakes up, it will try to perform the routine on all processes all over again.

To avoid reinfecting processes, Sality checks each process for a mutex with the format '{processname}M_%d_' - if the mutex is found, it will skip the process.

This thread ensures that all suitable processes can be infected, including new processes that the user will soon use.

Safemode Deleter Thread

Normally, if we want to figure why a machine is not behaving in the way it is expected to be, we boot the system in Safe Mode. The system restarts with minimal services.

There are three common options: Safe Mode, Safe Mode with Networking, and Safe Mode with Command Prompt. The information for these options can be found in the registry entry HKLM\SYSTEM\CurrentControlSet\Control\ SafeBoot with the following subkeys: Minimal, Network, and AlternateShell. The subkeys each have lists of services depending on the selected options.

Sality deletes these subkeys in the following way:

Initially, the thread sleeps for (0x1D4C0) 120,000 milliseconds before it opens HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot using the RegOpenKeyExA API. This is followed by enumerating the subkeys using a call to the RegEnumValueA API.

The AlternateShell subkey commonly contains the value 'cmd.exe', which is the first to be deleted using a call to the RegDeleteValueA API.

The Minimal and Network subkeys contain their own second-layer subkeys. The second-layer subkeys are deleted first, before the Minimal and Network keys.

When all of the subkeys under HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot have been deleted, the system will not be able to restart in Safe Mode.

After deleting the subkeys under SafeBoot, Sality gets the addresses of service-related APIs from ADVAPI32.DLL using the GetProcAddress API. Then the malware creates a new thread, the Anti-Malware Services Killer Thread, which will be discussed later.

Afterwards, Sality will check if '\\.\amsint32' exists. If it doesn't, the malware will create a driver file, jnhrks.sys, in the %system%\drivers folder. It will use this driver file to create a service named 'amsint32' using the CreateServiceA API with parameters dwServiceType with (0x01) SERVICE_KERNEL_DRIVER, and dwStartType with (0x03)SERVICE_DEMAND_START. After creating the service, it closes the handle to it. This is followed immediately by opening and starting the service using the OpenServiceA and StartServiceA APIs, respectively. After successfully running the 'amsint32' service, Sality deletes the 'jnhrks.sys' %system%\drivers folder to hide any trace of the driver file.

On the other hand, if '\\.\amsint32' does exist, Sality will create a copy of 'ntkrnlpa.exe' using a randomly generated five-character filename, e.g. 'cdbpa.exe' in the %temp% folder. This is followed by loading the copied file, 'cdbpa.exe', into the memory by calling the LoadLibraryExA API with the parameter DONT_ RESOLVE_DLL_REFERENCES.

Anti-Malware Services Killer Thread

It is common for malware to parse a list of names of running processes to spot processes that belong to anti-virus applications or ones that are security-related. The malware compares the substrings of the process name, and if they match those of particular applications it terminates them. However, Sality goes one step deeper. Rather than looking at the running processes, it looks for services used by security and anti-virus applications and disables any it finds, effectively removing whatever protection the application provides.

The procedure is as follows:

Initially, Sality connects to the service control manager using the OpenSCManagerA API. It sleeps for (0x1000) 4,096 milliseconds before it starts searching for anti-virus and security-related services.

It checks if certain services with given string names exist by calling the OpenServiceA API with the SERVICE_ ALL_ACCESS (0xF01FF) parameter. The string names come from a long list of names of services used by anti-virus and security applications. We can tell that the malware author has done extensive research to compile this list.

If such a service exists, the malware will open it using the OpenServiceA API and disable it by calling the ChangeServiceConfigA API with a dwStartType parameter of SERVICE_DISABLED (0x04) (see Figure 2).

After closing the service handle, Sality will sleep for (0x80) 128 milliseconds, after which it will get the next string name from the list. Sality will go through the same procedure of opening and disabling services, if they exist, until all the names have been checked.

Once all names have been checked, Sality will sleep for (0x2D000) 184,320 milliseconds, and will wake up to perform this thread all over again. This is to make sure that no new anti-malware services have started running, and no disabled services have been restarted.


Figure 2: Partial list of names of anti-malware services.

Thread Monitor Thread

This thread checks the content of three memory locations for certain values. This is some sort of anti-debugging trick to determine if all threads are running simultaneously. Other threads set the three memory locations with the intended values.

Initially, this thread checks for a certain value in memory location 1, if the value is non-zero the thread will sleep infinitely.

If memory location 1 contains a non-zero value, it will sleep for 12 milliseconds, then check the memory location 2. If the value at memory location 2 is not equal to 1, it will go back to the start of the thread and start all over again.

However, if the value at memory location 2 is 1, then it will check the value at memory location 3. If this is not equal to 1, then it will try to run the malware from the very beginning (at the entry point of the malware).

If all conditions are satisified, Sality will get the pathname of the current executable module using the GetModuleFileNameA API. Then, strange as it seems, Sality zeroes-out the fourth character of the pathname and tries to run it using the ShellExecuteA API with the parameter 'open'. Since the result of the GetModuleFileNameA API is the complete path name, the first three characters will be the root folder, e.g. 'c:\', thereby, the root folder will be displayed in a new window.

After displaying the root folder, Sality will create another mutex named 'Ap1mutx7', then sleeps for (0x927C0) 600,000 milliseconds before terminating the current process.

Temp-Executable Killer Thread

This thread has only one goal: to delete executable (.EXE) files found in the %Temp% folder.

After getting the %temp% folder pathname, it will use the FindFirstFileA and FindNextFileA APIs to find any .EXE files. Once a file is found, the malware will change its attributes and delete it. There is no checking of whether the .EXE file really is an executable file or not; the only requirement is to have an extension name of 'EXE'.

After deleting all .EXE files in the %temp% folder, the thread will sleep for 10 minutes. Once the thread wakes up, it will do the same thing all over again.


Figure 3: The generated content of autorun.inf in memory.

Autorun.inf Thread

Sality is a file infector and there are only a handful of file infectors that drop an autorun.inf file.

Initially, the malware sleeps for (0x5D1D) 23,837 milliseconds, as it usually does. This is followed by calling the GetLogicalDrives API to get the available disk drives in the system. Knowing the drives available, Sality checks the drive type by calling the GetDriveTypeA API. It avoids the CD drive by checking if the result from the GetDriveTypeA API is DRIVE_CDROM; otherwise, it will check if 'autorun.inf' already exists in the drive by calling the CreateFileA API with GENERIC_READ access.

If 'autorun.inf' does not exist in the drive, it will call the CreateFileA API again, this time with GENERIC_WRITE access.

This is followed by generating five random characters for a filename and randomly selecting from 'pif' and 'exe' as the extension name. The randomly generated filename is used as part of the autorun.inf content. Sality also generates random characters and strings that will be placed within the autorun.inf file. Figure 3 shows the possible content of the autorun.inf file.

The generated content of autorun.inf is similar to autorun.inf files dropped by common trojans, except that Sality includes all possible start-up commands including: open, shell\explore\command, shell\open\command and shell\autoplay\command.

Finally, the generated content is written to autorun.inf and its attributes are changed to FILE_ ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ HIDDEN|FILE_ATTRIBUTE_SYSTEM.

Once the autorun.inf file has been created successfully, Sality creates the actual executable file mentioned within autorun.inf. First, it creates a file using the CreateFileA API and copies (0x192E4) 103,140 bytes of code to it using the WriteFile API. Then Sality changes the file attributes to ones similar to those used by autorun.inf.

The executable file that is generated is the trojan component of Sality.

This thread will create autorun.inf and the trojan component on all available disk drives in the system. Then it will sleep for (0x1B58) 7,000 milliseconds, after which it will check again for uninfected disk drives.

More Threads?

There are still more threads spawned by Sality. There is not enough space in this article to describe each one, but one thing is certain: Sality continues to evolve. It upgrades itself with more features, more functionalities, and more tricks to defeat the system.

Sality has a strong encryption algorithm as evidence of years of existence. It is very careful in perfoming its routines and hiding traces of its components. It minimizes exposure by avoiding the infection of system files. And it maintains a low-activity profile by sleeping in each and every routine.

Sality comes and goes, but its every appearance demonstrates different strengths and capabilities.

Join the Discussion