A Brief History of SmokeLoader, Part 2

IntroductionIn this two-part blog series, we explore the evolution of SmokeLoader, a malware downloader that has been active since 2011. In Part 1, we explored early versions of SmokeLoader, from its initial rudimentary framework to its adoption of a modular architecture and introduction of encryption and obfuscation. This blog provides an overview of SmokeLoader’s development from 2015 to 2022, where the malware continued to update its algorithms and improve anti-analysis techniques.2015-2017: Protocol RenaissanceVersions 2015 and 2017 of SmokeLoader signify major releases in the evolution of the malware. One of the major changes was to the communication with the command-and-control (C2) server. In version 2015, the network protocol was updated with fields that became the basis for all subsequent versions, where each field was separated by a ‘#’ delimiter.The following table shows these fields, which have remained unchanged in all versions of SmokeLoader.FieldDescriptionBOT_MAGICMagic bytes (version number).BOT_IDUnique victim ID.BOT_AFFIDAffiliate ID.BOT_WINVERVictim’s Windows version.BOT_WINBITVictim’s Windows OS architecture.BOT_PRIVILUser privileges.BOT_CMDCommand ID.BOT_OPTCommand argument (the meaning depends on the specific command).BOT_RESCommand result (the meaning depends on the specific command).BOT_DATAAdditional data sent with the packet.Table 1: SmokeLoader C2 fields present in all versions from 2015-2022.Introduction of a binary protocolBeginning in 2017, all SmokeLoader versions started using a binary protocol with the same fields as version 2015. SmokeLoader version 2017 also updated the network communication to use two different static RC4 keys to encrypt the requests and decrypt the responses. Each RC4 key is 4 bytes and hardcoded in the main module of the malware. This modification provides an additional advantage - the data encrypted by SmokeLoader cannot be decrypted from a network capture unless the encryption keys are known.The binary protocol has remained largely unchanged since 2017, except for the addition of the computer name field, which was added in version 2020. The figure below shows an example packet using SmokeLoader’s binary request format for versions 2020 through 2022.Figure 1: Example SmokeLoader 2020-2022 network data (with RC4 encryption removed).SmokeLoader versions 2017-2022 implement the following command IDs:CommandValueDescriptionCMD_ONLINE0x2711Notifies the server that the infected system is online and awaiting tasking.CMD_GETTASK0x2712Notifies the server that the infected system is ready to execute a personal task, or an update and awaiting more information. May also be used to report the result of an uninstall command.CMD_TASKRESULT0x2713This command is used to confirm that an update or a task was executed correctly and the BOT_RES argument is set to 1.CMD_STEALERRESULT0x2714Exfiltrates data produced by the stealer plugin. The BOT_DATA argument contains the base64 encoded results.CMD_PROCMON0x2715This command is used to notify the server about the presence of a specific process running on the victim’s computer. The BOT_DATA argument contains the name of the process. The server queries the database. If the database contains tasks associated with the given process, the server returns these tasks to the infected system.CMD_PROCMONRESULT0x2716Reports the status of the CMD_PROCMON command and sets BOT_OPT to 1 for success.CMD_FGRESULT0x2717Submits the formgrabber plugin data to the server, where BOT_DATA contains the base64-encoded data. Under the base64 layer, the results are split by the {:!:} substring to get each form grabbing result. Each result is split by comma to get the values: cname, browser, url, uagent, cookies, data, and time.CMD_PASSSNIFRESULT0x2718Submits passwords harvested from the sniffer plugin where BOT_DATA contains the base64-encoded data.CMD_FSRESULT0x2719Sends files from the infected system discovered by the fsearch plugin where the BOT_DATA contains the base64-encoded content of the files.CMD_DDOSRESULT0x271AConfirms the successful execution of a DDoS attack (against the targets configured in the plugins’ rules). If BOT_OPT is 1, the attack was executed successfully. If it is 0, the attack was unsuccessful.CMD_KEYLOGRESULT0x271BSubmits the results of the keylogger plugin where BOT_DATA contains the base64-encoded content of the keylogged data.CMD_HIDDENTV0x271CThis command is used to request the TeamViewer package from the server.CMD_HIDDENTVRESULT0x271DOnce a TeamViewer instance is run, this command sends the ID and password of the TeamViewer session to the server. They are separated by the substring {:!:}.CMD_MINER or CMD_EMPTY0x271ERequests a cryptocurrency miner executable from the server. In newer SmokeLoader versions, this command value is empty (undefined). *This command was introduced in version 2017 of SmokeLoader and removed in version 2020.CMD_EGRABBERRESULT0x271FThis command is used by the bot to submit the email grabber plugin results to the server where BOT_DATA contains the base64-encoded data. *This command was introduced in version 2017 of SmokeLoader.Table 2: Message types implemented by SmokeLoader.The primary message type is the CMD_ONLINE, which serves as a knock or keep-alive. The response from the server may be one of the following values:ByteCommandDescription0x69iPersonal task0x72rUninstall0x75uUpdateTable 3: Commands implemented by SmokeLoader.For all other scenarios, the server will provide the number of available tasks, as well as (optional) plugins and their respective configurations. The figure below shows an example task, with plugins (and their configurations). Figure 2: Example SmokeLoader task with plugins and configuration.Once SmokeLoader receives a response to the CMD_ONLINE request, it will send a sequence of CMD_GETTASK requests for tasks, updates, and confirm the result of previous commands. SmokeLoader will request all available tasks from the server, and in response, the server will provide each task individually. These tasks may include either the content of a file to be executed or the location (URL) from which the file can be downloaded.In May 2024, Operation Endgame with technical assistance provided by Zscaler ThreatLabz, leveraged SmokeLoader’s built-in uninstall (0x72) command to remotely disinfect tens of thousands of infections.Algorithm changesOne notable characteristic of SmokeLoader is that the algorithms used vary across versions, likely as an attempt to break existing detections. For example, in SmokeLoader version 2014, the bot ID was generated from the computer name and volume information using a custom algorithm that combined CRC32 and XOR. However, version 2015 and newer have since replaced the hash algorithm to generate the bot ID with MD5.The encryption of C2 servers was also altered in version 2017, which employs an XOR-based algorithm wherein each byte of the unencrypted C2 URL is encrypted into two bytes. The decryption algorithm utilizes these two bytes, along with a hardcoded 1-byte key, to retrieve the original byte.The Python implementation of the algorithm is shown below:def smoke2017_c2_xor_decrypt(enc, key):
out = b’’
i = 0
while True:
out += (((enc[i] ^ key[0]) -
(enc[i+1] ^ key[0])) & 0xff).to_bytes(1, ‘little’)
i += 2
if i > len(enc) / 2:
break
return outSmokeLoader version 2017 (and newer) also reintroduced string encryption, but replaced the algorithm with RC4.Also beginning with version 2017, the malware adopted a different hash function to locate the addresses of the required APIs.The Python code provided below represents the implementation of the algorithm used to hash the API names in version 2017:def calc_hash_smoke2017(name):
name = name.encode()
hash = 0
for i in range(0, len(name)):
hash ^= (name[i] << 8)
temp = ROL(hash, 8)
temp_bytes = list(struct.pack(‘<L’, temp))
temp_bytes[0] = 0xff &(temp_bytes[1] ^ temp)
temp = struct.unpack(‘<L’, bytes(temp_bytes))[0]
hash = 0xffffffff & (temp * 2)
return hash 2018: The Stager RevolutionThe most significant changes introduced in SmokeLoader version 2018, and subsequent versions, revolve around the stager module. These changes enhanced obfuscation techniques and implemented anti-analysis measures.Starting from version 2018, the stager module incorporates comprehensive anti-analysis features and includes code for injecting the main module, in addition to handling decryption and decompression. Furthermore, the stager module underwent significant improvements to the obfuscation techniques.It is important to note that the stager module, starting in version 2017, no longer loads the main module within the current process context. Instead, the stager itself injects the main module into the address space of an explorer process. In version 2017, the stager creates a new instance of the explorer.exe process, while versions 2018 and onward inject the main module into the default explorer process. The reason why version 2017 was designed to create a new explorer process is because the SmokeLoader main module code (for that version) is only 32-bit. Therefore, if the victim’s Windows operating system is 64-bit, SmokeLoader can still function by creating and injecting the main module into a 32-bit (WoW64) explorer process.Code obfuscationStarting from version 2018, several code obfuscation techniques were implemented in SmokeLoader that persist in the latest versions. These methods are largely targeted at confusing disassemblers and include the following: Code permutationsOpaque predicates (JZ / JNZ)Stack-based obfuscation, which mixes (string) data and codeObfuscated jumps that use the Relative Virtual Address (RVA) of the destination address along with the precalculated image baseEncrypted functionsIn previous versions of SmokeLoader, we observed simple encryption layers using 1-byte XOR keys and straightforward non-obfuscated loops in the stagers. However, starting from version 2018, there was a significant improvement to encryption functions. In the stager of SmokeLoader version 2018 (and newer), a majority of the code is encrypted using nested XOR layers, enhancing the encryption and obfuscation techniques employed, as shown in the figure below.Figure 3: SmokeLoader’s stager using nested XOR encryption layers.Among the final blocks is code responsible for decrypting, decompressing, and injecting the main module. The figure below shows an example of a function that decrypts SmokeLoader’s stager code for versions 2018 through 2022.Figure 4: Code decryption for SmokeLoader versions 2018-2022.After executing a decrypted block of code, it is immediately re-encrypted to minimize the amount of unencrypted code in memory.Anti-analysis tricksSince 2018, a significant portion of the anti-analysis techniques that were previously executed in the main module have been shifted to the stager. As each new version is released, the malware incorporates an expanding array of evasion techniques and expands its target range to include a wider variety of security products.Furthermore, the new and more intricate stager necessitates the loading and utilization of multiple APIs. To locate the required API addresses, it employs a hash-based search mechanism, utilizing the DJB2 algorithm.Starting from version 2018, the stager incorporates checks for keyboard layouts. If it detects Ukrainian or Russian languages, the infection process is halted. Additionally, the stager examines the OsMajorVersion field within the PEB structure and ceases execution for operating system versions below 6 (Windows Vista/Server 2008).PROPagate injectionIn SmokeLoader 2018, the stager employs the PROPagate code injection method to inject the main module within the context of the explorer process. This injection process utilizes native Windows APIs such as NtOpenProcess, NtDuplicateObject, NtCreateSection, and NtMapViewOfSection. Additionally, the SetPropA and SetNotifyMessageA APIs are utilized to execute the PROPagate attack.It is worth mentioning that starting from version 2018, the stager carries both x86 and x64 variants of the main module. Depending on the current platform, it will inject the appropriate variant into the explorer process.Algorithm changesIn the 2018 version of SmokeLoader, significant changes were made to the algorithms used for decrypting and decompressing the main module. For decryption, a straightforward XOR is employed with a 4-byte key, while decompression is accomplished using the RtlDecompressBuffer function provided by Windows, utilizing the LZNT1 algorithm.Furthermore, the encryption method for the C2s was altered in the 2018 version. It now utilizes an XOR-based algorithm with a 4-byte key.The following code shows a Python implementation to decrypt the C2 URLs for SmokeLoader version 2018:def smoke2018_c2_xor_decrypt(enc, key):
out = ‘’
for i in range(len(enc) - 4):
xor_key = struct.unpack(‘<L’, key)[0]
v = struct.unpack(‘<L’, enc[i:i + 4])[0]
for j in range(4):
v = v ^ xor_key
xor_key >>= 8
tmp = (chr(~v & 0xff))
out += tmp
return out.encode()The algorithm for hashing the API names to locate their addresses was also modified, as shown below.def calc_hash_smoke2018_2022(name):
name = name.encode()
hash = 0
for i in range(0, len(name)):
hash = 0xffffffff&((name[i] & 0xDF) +
ROL(hash ^ (name[i] & 0xDF), 8))
return hashVersion 2018 was also the first to use scheduled tasks for persistence. Every SmokeLoader version since then has continued to utilize scheduled tasks with only the task name changing between versions.2019-2022: Contemporary HistoryIn the most recent versions of SmokeLoader, there haven’t been significant changes in the structure and functionality of the malware itself. However, there have been modifications to the algorithms used and the anti-analysis techniques employed.NTDLL hook evasionSmokeLoader’s stager heavily relies on Windows native APIs to carry out its tasks. Instead of utilizing the default ntdll library that is loaded when the process is created, SmokeLoader loads its own copy of ntdll into memory. This approach ensures that if breakpoints are set on the exported functions of the library or if a monitoring tool attempts to perform hooks, they will be unable to trace SmokeLoader’s behavior as it operates with its own separate copy of ntdll.In version 2020 and 2022, SmokeLoader creates the copy of ntdll in memory using functions like CreateFileMappingW and MapViewOfFile. In version 2019, the malware created a copy of the library on disk within the %TEMP% folder and loaded it from there using LdrLoadDll.Detection of security productsSmokeLoader has continuously improved its ability to detect security products on a system in order to avoid infection if any are present. This detection capability has significantly increased in the latest versions, with notable enhancements in 2020 and 2022. The table below highlights these improvements.Process/registry value20122014201520172018201920202022qemu x xxxxxQEMU x virtio xxxVMWARE x vmware x xxxxxVIRTUAL x virtual x x vbox xxxXEN x xen x xxxxxAFEA.vmt xqemu-ga.exe xxqga.exe xxwindanr.exe xxvboxservice.exe xxvboxtray.exe xxvmtoolsd.exe xxprl_tools.exe xx\REGISTRY\MACHINE\System\CurrentControlSet\Enum\IDE xxx\REGISTRY\MACHINE\System\CurrentControlSet\Enum\SCSI xxxvmci.s xxvmusbm xxvmmous xxvm3dmp xxvmrawd xxvmmemc xxvboxgu xxvboxsf xxvboxmo xxvboxvi xxvboxdi xxvioser xxsbiedll x xxxxxaswhook xxsnxhk xxdbghelp x x sample x ffffcce24 x Table 4: The year SmokeLoader introduced detection for a particular security product.Furthermore, in the latest versions of SmokeLoader, the malware relies on Windows native APIs, specifically NtQuerySystemInformation and NtQueryInformationProcess, to query the kernel flags SystemCodeIntegrityInformation and ProcessDebugPort.Algorithm changesIn versions 2019 and 2020 of SmokeLoader, a different XOR-based algorithm is implemented to decrypt the list of C2 servers. The decryption key used is derived from the CRC32b value of the encrypted C2 address. The following code provides a Python implementation of the decryption algorithm:def smoke2019_2020_decrypt(enc, key):
dec = b’’
for c in enc:
for i in key: c = c ^ i
dec += (c ^ 0xE4).to_bytes(1, ‘little’)
return decIn version 2022, SmokeLoader implemented an RC4 algorithm to protect the C2 URLs. Instead, a DWORD within the structure of the encrypted C2 contains the RC4 key, while another DWORD holds the CRC32b value of the URL. This can be defined as the following C structure:struct EncryptedC2 {
unsigned char C2_length;
unsigned int RC4_key;
unsigned char C2_encrypted_data[C2_LENGTH];
unsigned int C2_CRC32b;
}In versions 2020 and 2022, SmokeLoader introduced the LZSA algorithm for decompressing the main module. This replaced the previous algorithm, LZNT1. Additionally, the PROPagate method used for injecting the main module into the explorer process was no longer utilized in these versions. Instead, SmokeLoader creates a shared section as it did in previous versions and creates a remote thread by invoking the native API RtlCreateUserThread.ConclusionSmokeLoader is a sophisticated and intricate modular malware downloader that has been prevalent for many years. The developers of this malware family have consistently enhanced its capabilities by introducing new features and employing obfuscation techniques to impede analysis efforts. While the most recent known version of SmokeLoader dates back to 2022, it has been extensively deployed in numerous campaigns throughout recent years. However, it is important to note that the absence of newer versions does not rule out the possibility of future iterations emerging in the near future. Following Operation Endgame, there has been an overall decline in SmokeLoader activity. However, this lull will likely be short-lived as various threat actors who have leveraged SmokeLoader regroup.Zscaler CoverageIn addition to sandbox detections, Zscaler’s multilayered cloud security platform detects indicators related to SmokeLoader at various levels with the following threat names:Win32.Downloader.SmokeloaderIndicators Of Compromise (IOCs)VersionSample SHA2562012857fc7aafbbf0d4c850c1b1585a72420600bdabe269f343c0c817614aa6c94cd2014e92d1c2c1e145c1d6c42dd402e75f46e5edfb2bab5539c4d103d345b5ac965a3201618aa1b79bbeee6a731b897377233d54b1b2464eeb9a25dafc0debfc43af8c04f201732ba1f3b96cf77a08c041d4983d6afa7db8e1948d27d6a8dd55b7bb95e4931892018b6ec96043dba7722cac4ed24b6979fc71a758bdf18ca44353c19194c172bf62120185727c2cd54b8408ca0f8e943cad61027a2c3d51da64f2f1224a6b9acc4820f8e2019fc20b03299b8ae91e72e104ee4f18e40125b2b061f1509d1c5b3f9fac31049342019d5efd66f54dce6b51870e40a458fa30de366a2982ab2f83dddff5cb3349f654d2020070a94ee0cd9ac1b1ed467353f5731e09cab136315447c04f53bc52d4fe3f8cc20207377efde4e4e86650ab8495f57ab4a76d4f8efe31e2962305b8c42a6cee704542022c78bc4fb8955940b3ac9b52cb16744a61f8bdaf673fd64fc106465241c56cc6c

Article Link: SmokeLoader History, Part 2 | ThreatLabz