{
	"id": "fe0bfcf3-375e-4120-8fe1-b43097b9ab74",
	"created_at": "2026-04-06T00:20:08.311731Z",
	"updated_at": "2026-04-10T03:20:38.040217Z",
	"deleted_at": null,
	"sha1_hash": "7fcdd983a047b396f040b15d5428ed4d819b5b4e",
	"title": "SmokeLoader History | ThreatLabz",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1099447,
	"plain_text": "SmokeLoader History | ThreatLabz\r\nBy ThreatLabz\r\nPublished: 2024-06-11 · Archived: 2026-04-05 15:14:35 UTC\r\n2014: Ancient Modularizations\r\nThe following section covers new features and modifications to SmokeLoader version 2014, which include a\r\nmulti-stage loading process, an updated algorithm for generating the bot ID, a separate encrypted C2 list, and\r\nmore.\r\nDuring the analysis of a sample dating back to 2014, we discovered the introduction of the string s2k14 that is\r\nused as the name of a file mapping. We believe s2k14 is a reference to SmokeLoader version 2014. The figure\r\nbelow shows this string referenced in the code.\r\nFigure 5: SmokeLoader version 2014 string for a file mapping name called s2k14 .\r\nOne of the most interesting features in this version of SmokeLoader is the malware was split into several loading\r\nstages. The introduction of a stager component marked a significant change that became standard in all subsequent\r\nversions. Each version since 2014 consists of a stager, a main module, and plugins that implement additional\r\nfeatures.\r\nIn SmokeLoader version 2014, the ./mods/ folder in the panel includes a ./mods/plugins file that combines\r\nmultiple plugins into a single file. The prior ./mods/grab information stealing module from previous\r\nSmokeLoader versions was split into multiple stealing modules like an FTP/mail stealer module, browser stealer\r\nmodule, and keylogger module, and then packaged in this plugins file. This modification to the plugins persists\r\nfrom this version onward until the most recent version of SmokeLoader.\r\naPLib stager\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 1 of 11\n\nThe stager introduced in SmokeLoader version 2014 is quite simple. The stager performs the following actions:\r\nDecrypts a section of data using a single byte XOR key. \r\nDecompresses the data using aPLib. \r\nMaps the main module in a buffer allocated in the same process context.\r\nExecutes some simple anti-analysis measures by checking the Process Environment Block (PEB) such as\r\nthe BeingDebugged and NtGlobalFlags fields.\r\nThen, the stager transfers execution to the main module, creates an instance of svchost.exe , and injects\r\nSmokeLoader into this newly created svchost.exe process using APC queue code injection.\r\nThe figure below shows how the 2014 version of the SmokeLoader aPLib stager works.\r\nFigure 6: SmokeLoader version 2014 code unpacking and injecting into svchost.exe .\r\nSmokeLoader’s stager underwent significant evolution in subsequent versions, incorporating advanced\r\nobfuscation techniques and additional anti-analysis measures. Nevertheless, even in this version, we can observe\r\nthe presence of rudimentary obfuscation tricks.\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 2 of 11\n\nFor instance, SmokeLoader employs non-polymorphic decryption loops to unravel layers of XOR encryption for\r\nfunctions that are invoked, as shown in the figure below.\r\nFigure 7: SmokeLoader version 2014 stager function decryption.\r\nPersistence\r\nThe SmokeLoader seller has provided threat actors with an option to build a sample with (or without) persistence.\r\nSmokeLoader’s approach to achieve persistence on the victim's system has undergone numerous changes over\r\ntime. In earlier versions (2011-2017), SmokeLoader would leverage common Run registry keys and create a\r\nstartup shortcut as a fallback option (if setting the registry values failed). In addition, SmokeLoader would\r\nestablish two dedicated threads responsible for safeguarding the modified registry keys.\r\nBot ID\r\nIn the initial version of SmokeLoader, dating from approximately 2011 to 2012, we observed that the bot ID was\r\ngenerated by taking a simple MD5 hash of the victim machine's computer name. Over time, the algorithm to\r\ngenerate the bot ID has undergone slight modifications. Notably, in version 2014, SmokeLoader employed a\r\nCRC32 and XOR based algorithm.\r\nStarting from 2014, all versions of SmokeLoader calculate the ID using both the computer name and the volume\r\ninformation, as shown in the figure below. \r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 3 of 11\n\nFigure 8: SmokeLoader version 2014 bot ID generation.\r\nAnti-analysis tricks and plain text strings\r\nInterestingly, SmokeLoader version 2014’s main module stored the malware’s strings in plaintext as shown in the\r\nfigure below. This is a departure from the initial version where the strings were encrypted.\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 4 of 11\n\nFigure 9: SmokeLoader version 2014 plaintext strings.\r\nThis is the first version of the malware that searches for sbiedll , dbghelp , qemu , virtual , vmware , and\r\nxen strings to check for libraries and processes related to malware analysis environments. If an analysis\r\nenvironment is detected, SmokeLoader terminates itself to evade detection.\r\nEncrypted C2s\r\nThe algorithm used to decrypt the list of encrypted C2s is one of the SmokeLoader components that has\r\nundergone the most changes across versions.\r\nWhile the strings in the main module of SmokeLoader version 2014 are stored in plaintext, the list of C2 servers is\r\nencrypted. To decrypt the list, a custom XOR-based decryption algorithm is employed. The code contains a table\r\nof pointers, with each pointer referencing a string that is prepended by a byte that is used as an XOR key, which is\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 5 of 11\n\nfollowed by three unused bytes. The next byte is the size of the encrypted C2 URL and the remaining bytes are the\r\nencrypted C2 URL. The Python code below demonstrates the C2 decryption algorithm used in SmokeLoader\r\nversion 2014.\r\ndef smoke2014_c2_xor_decrypt(enc_data):\r\n key = enc_data[0]\r\n size = enc_data[4]\r\n enc = enc_data[5:]\r\n dec = b''\r\n for i in range(0, len(enc)-1, 2):\r\n dec += (0xff\u0026((enc[i] ^ key) -\r\n (enc[i+1] ^ key))).to_bytes(1, 'little')\r\n return dec\r\nAnti-C2 patching mechanism\r\nAn interesting addition to SmokeLoader version 2014 is the implementation of what appears to be a simple copy-protection mechanism as shown in the figure below. \r\nFigure 10: Simple copy-protection mechanism implemented in SmokeLoader version 2014 version.\r\nThe malware calculates the CRC32 value of the C2 URL string and compares it with a predefined expected value\r\nat various points in the code. This mechanism is likely designed to prevent other hackers from creating a builder\r\nthat patches samples with new C2s, and therefore reduce potential sales of SmokeLoader.\r\nCommunication\r\nThe communication protocol for SmokeLoader version 2014 is similar to prior versions. SmokeLoader uses a\r\nsimple text-based protocol that is encrypted and sent to a C2 server. The syntax for the protocol is the following:\r\narg1=value1\u0026arg2=value2…\u0026argN=valueN\r\nSmokeLoader’s version 2014 panel recognizes the following arguments:\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 6 of 11\n\nArgument Description\r\ncmd\r\nThe C2 panel accepts a set of commands. Depending on the specified command additional\r\narguments must be specified.\r\nlogin This argument is the bot ID and its length must be 40 bytes.\r\ninfo Additional information given with some commands.\r\nver Operating system version.\r\nbits Victim’s Windows operating system architecture.\r\nfile Mainly used together with the  getload command to request updates or tasks.\r\nrun\r\nUsed in different commands for different purposes. For example, to ask for an update or to\r\nindicate that the update was successfully executed.\r\nport Used together with the  getsocks command to specify the proxy’s port.\r\nprocname Process name included with the  procmon command.\r\ndoubles Additional flag that may be sent with the  getload command.\r\nremoved Additional flag that may be sent with the  getload command.\r\npersonal Additional flag that may be sent with the  getload command.\r\nshell\r\nIf the  getshell command is sent to the server, this argument contains the results of the\r\nexecuted commands.\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 7 of 11\n\nArgument Description\r\ngrab\r\nUsed together with the  formgrab ,  ftpgrab , and  keylog commands. This argument\r\ncontains the stolen information.\r\nfiledata If a file is submitted, the  filedata argument contains the content of the file.\r\nTable 2: SmokeLoader version 2014 network protocol.\r\nThe panel is able to handle the following commands (i.e., the command name specified in the cmd argument):\r\nCommand (cmd) Description\r\ngetload  \r\n*with additional\r\narguments\r\nOne of the main commands and differs depending on specified arguments:\r\nfile: If the  getload command is included with the file argument, the panel\r\nhandles the command in different ways depending on the value of the  file\r\nargument:\r\nIf the  file  argument's value is  u and the  run argument is not set, the\r\nbot asks for an update. The server could return the update executable or a\r\nURL to download the update from.\r\nIf the  file  argument's value is  u and the  run argument is set, the bot\r\nconfirms the successful execution of the update.\r\nIf the  file  argument's value is not  u and the  run argument is not set,\r\nthe bot asks for the next task. The server tracks in its database the last task\r\ngiven to each bot. When this command is received, the server returns the\r\nnext task (if any).\r\nIf the  file  argument's value is not  u and the  run argument is set,\r\nSmokeLoader confirms whether the last task was executed correctly.\r\ndoubles: If the bot specifies this argument together with the  getload\r\ncommand, the panel sets the  doub  flag in the database for the associated victim\r\nID. The purpose of this flag is unknown.\r\nremoved: The bot can specify a  removed  argument together with the  getload\r\ncommand to confirm an uninstall request was received from the server. The panel\r\ndeletes the bot ID from the database upon receipt.\r\npersonal: A  personal  argument can be given together with\r\nthe  getload  command to ask for personal tasks. The argument should contain\r\nthe ID of the personal task. If the configured task is set as  local in the\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 8 of 11\n\nCommand (cmd) Description\r\ndatabase, the server would return a file in the response to be executed by the bot.\r\nOtherwise, a URL is provided and the bot downloads and executes the content\r\nfrom the given URL.\r\ngetload\r\n*without\r\narguments\r\nIf this command is received without arguments, it could be interpreted as a  hello\r\nor  knock query, and used by the bot to start the conversation with the server. When a\r\nserver receives a  getload command without arguments, the response could vary\r\ndepending on the database configuration.\r\nIf there is a pending update for the bot, the server responds with the string\r\n“ Smku ”.\r\nIf there is a personal task for the bot, the server responds with the string\r\n“ Smki ”.\r\nIf there is a pending removal request for the bot, the server responds with the\r\nstring “ Smkr ”.\r\nIn the remaining cases, the server responds with the total number of configured\r\ntasks followed by the configuration’s rules for each plugin. Each configuration\r\nitem starts with the “ |:| ” string followed by the name of the ruleset and the\r\nplugin’s rules:\r\n|:|socks_rules=\r\n|:|hosts_rules=\r\n|:|shell_rules=\r\n|:|fakedns_rules=\r\n|:|filesearch_rules=\r\n|:|procmon_rules=\r\n|:|ddos_rules=\r\n|:|keylog_rules=\r\ngetsocks\r\nUsed by the bot to inform the server that it has enabled the SOCKS proxy feature. The\r\nserver will attempt to validate the bot proxy is active by connecting to the bot’s IP\r\naddress on the specified port.\r\ngethosts Confirms that the hosts specified in the  hosts_rules have been successfully spoofed.\r\ngetshell\r\nThe bot submits results from executed shell commands to the server. The shell argument\r\ncontains the results.\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 9 of 11\n\nCommand (cmd) Description\r\nformgrab\r\nSubmits the results from the form grabber plugin to the server. The grab argument\r\nmust contain a base64 encoded string that, once decoded, contains a comma separated\r\nlist of grabbed data.\r\nftpgrab\r\nSubmits the results from the ftp grabber plugin to the server. The grab argument must\r\ncontain a base64 encoded string with the stolen data.\r\ngrab\r\nSubmits stolen information to the server. The argument data contains the stolen\r\ninformation.\r\navinfo\r\nSubmits information about installed security products to the server. The information is\r\nsubmitted in the  info argument. The submitted string is split by the delimiter  777 .\r\nThe first substring contains information about the installed antivirus. The second\r\nsubstring contains information about installed firewalls.\r\nprocmon\r\nIf one of the processes configured with the rules in the  procmon_rules configuration\r\nitem is found on the victim machine, the bot notifies the server about the presence of the\r\nprocess, submitting the name of the process in the  procname argument. The server\r\ncould respond with a file to be executed or a URL to download the file from.\r\nddos\r\nConfirms the DDoS attack configured with the  ddos_rules has been successfully\r\nperformed.\r\nkeylog\r\nSubmits the information captured by the keylogger plugin to the server. The grab\r\nargument must contain a base64 encoded string with captured data.\r\ngetfilesearch\r\nIf the HTTP query is application/bin, and the command is  getfilesearch , the bot\r\nsubmits to the server the content of the files that were found by the  filesearch plugin\r\naccording to the rules specified in the  filesearch_rules configuration item. The\r\ncontent of the file is given in the  filedata argument. \r\nTable 3: The commands supported by SmokeLoader’s 2014 C2 server.\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 10 of 11\n\nSmokeLoader version 2012 sent commands and arguments as plaintext using HTTP GET requests. In version\r\n2014, the network protocol was updated to send the command and argument data via HTTP POST requests. The\r\nPOST request body consists of an initial DWORD containing the size of the data, followed by a DWORD that\r\nfunctions as an RC4 key required to decrypt the remaining data.\r\nExplore more Zscaler blogs\r\nSource: https://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nhttps://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.zscaler.com/blogs/security-research/brief-history-smokeloader-part-1"
	],
	"report_names": [
		"brief-history-smokeloader-part-1"
	],
	"threat_actors": [],
	"ts_created_at": 1775434808,
	"ts_updated_at": 1775791238,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/7fcdd983a047b396f040b15d5428ed4d819b5b4e.pdf",
		"text": "https://archive.orkl.eu/7fcdd983a047b396f040b15d5428ed4d819b5b4e.txt",
		"img": "https://archive.orkl.eu/7fcdd983a047b396f040b15d5428ed4d819b5b4e.jpg"
	}
}