{
	"id": "af0c6360-7211-462e-9041-d717baa5d91b",
	"created_at": "2026-04-06T00:20:18.162414Z",
	"updated_at": "2026-04-10T03:21:25.436216Z",
	"deleted_at": null,
	"sha1_hash": "b0db413c2167baab161ac63c8cf0b066be561d05",
	"title": "Deep Analysis of SmokeLoader",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 607254,
	"plain_text": "Deep Analysis of SmokeLoader\r\nBy Abdallah Elshinbary\r\nPublished: 2020-06-21 · Archived: 2026-04-05 16:33:08 UTC\r\nSmokeLoader is a well known bot that is been around since 2011. It’s mainly used to drop other malware families.\r\nSmokeLoader has been under development and is constantly changing with multiple novel features added\r\nthroughout the years.\r\nSample SHA256: fc20b03299b8ae91e72e104ee4f18e40125b2b061f1509d1c5b3f9fac3104934\r\nStage 1Permalink\r\nThis stage starts off by allocating memory for shellcode using LocalAlloc() (not VirtualAlloc), then it fills\r\nthis memory with the shellcode (86 KB).\r\nNext, it changes the protection of the allocated memory region to PAGE_EXECUTE_READWRITE using\r\nVirtualProtect() , then it writes the shellcode and executes it.\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 1 of 18\n\nShellcodePermalink\r\nThe shellcode starts by getting the addresses of LoadLibraryA and GetProcAddress to resolve APIs\r\ndynamically, but first let’s see how it does that.\r\nFirst it passes some hash values to a sub-routine that returns the address of the requested function.\r\nAfter some digging, I found out that the algorithm for calculating the hashes is pretty simple.\r\nint calc_hash(char* name) {\r\n int x, hash = 0;\r\n for(int i=0; i\u003cstrlen(name); i++) {\r\n x = name[i] | 0x60;\r\n hash = 2 * (x + hash);\r\n }\r\n return hash;\r\n}\r\nThe shellcode uses PEB traversal technique for finding a function.\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 2 of 18\n\nProcess Environment Block (PEB) is a user-mode data structure that can be used by applications (and\r\nby extend by malware) to get information such as the list of loaded modules, process startup arguments,\r\nheap address among other useful capabilities.\r\nThe shellcode traverses the PEB structure at FS[:30] and iterating through loaded modules to search for the\r\nrequested module (kernel32 in this case). It hashes the name of each module using the algorithm above and\r\ncompares it with the supplied hash.\r\nNext, it iterates over the export table of the module to find the requested function, similar to the previous step.\r\nThe next step is to resolve APIs using LoadLibraryA and GetProcAddress , the shellcode uses stack strings to\r\ncomplicate the analysis.\r\nHere is the list of imported functions:\r\nExpand to see more\r\n  ntdll.dll\r\n      NtUnmapViewOfSection\r\n      NtWriteVirtualMemory\r\n  kernel32.dll\r\n      CloseHandle\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 3 of 18\n\nCreateFileA\r\n      CreateProcessA\r\n      ExitProcess\r\n      GetCommandLineA\r\nProcess HollowingPermalink\r\nThe shellcode creates a new processes of SmokeLoader in a suspended state.\r\nNext, it hollows out the memory at 0x400000 using ZwUnmapViewOfSection() and then allocates it again using\r\nVirtualAllocEx() with RWX permissions.\r\nFinally, it writes the next stage executable to the allocated memory region using two calls to\r\nZwWriteVirtualMemory() , the first one to write the MZ header and the other for the rest of the executable.\r\nStage 2Permalink\r\nAfter dumping the second stage from memory, I got a warm welcome from SmokeLoader :(\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 4 of 18\n\nThis stage is full of anti-analysis tricks, so let’s dive in.\r\nOpaque PredicatesPermalink\r\nThe first anti-analysis trick is Opaque Predicates, it’s a commonly used technique in program obfuscation,\r\nintended to add complexity to the control flow. There are many patterns of this technique so I will stick with the\r\none used here.\r\nThis obfuscation simply takes an absolute jump (JMP) and transforms it into two conditional jumps (JZ/JNZ).\r\nDepending on the value of the Zero flag (ZF) , the execution will follow the first or second branch.\r\nHowever, disassemblers are tricked into thinking that there is a fall-through branch if the second jump is not taken\r\n(which is impossible as one of them must be taken) and tries to disassemble the unreachable instructions (often\r\ninvalid) resulting in garbage code.\r\nThe deobfuscation is so simple, we just need to patch the first conditional jump to an absolute jump and nop out\r\nthe second jump, we can use IDAPython to achieve this:\r\nimport idc\r\nea = 0\r\nwhile True:\r\n ea = min(idc.find_binary(ea, idc.SEARCH_NEXT | idc.SEARCH_DOWN, \"74 ? 75 ?\"), # JZ / JNZ\r\n idc.find_binary(ea, idc.SEARCH_NEXT | idc.SEARCH_DOWN, \"75 ? 74 ?\")) # JNZ / JZ\r\n if ea == idc.BADADDR:\r\n break\r\n idc.patch_byte(ea, 0xEB) # JMP\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 5 of 18\n\nidc.patch_byte(ea+2, 0x90) # NOP\r\n idc.patch_byte(ea+3, 0x90) # NOP\r\nAnti DebuggingPermalink\r\nThis stage first checks OSMajorVersion at PEB[0xA4] if it’s greater than 6 (Windows Vista and higher), it’s also\r\nreading BeingDebugged at PEB[0x2] to check for attached debuggers.\r\nWhat’s interesting here is that these checks are used to calculate the return address. If the OSMajroVersion is less\r\nthan 6 or there’s an attached debugger, it will jump to an invalid memory location. That’s clever.\r\nAnother neat trick is that instead of using direct jumps, the code pushes the jump address stored at eax into the\r\nstack then returns to it.\r\nEncrypted FunctionsPermalink\r\nMost of the functions are encrypted. After deobfuscating the opaque predicates, I found the encryption function\r\nwhich is pretty simple.\r\nThe function takes an offset and a size, it XORes the chunk at that offset with a single byte (0xA6) .\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 6 of 18\n\nWe can use IDAPython again to decrypt the encrypted chunks:\r\nimport idc\r\nimport idautils\r\ndef xor_chunk(offset, n):\r\nea = 0x400000 + offset\r\nfor i in range(n):\r\nbyte = ord(idc.get_bytes(ea+i, 1))\r\nbyte ^= 0xA6\r\nidc.patch_byte(ea+i, byte)\r\nxor_chunk_addr = 0x401294 # address of the xoring function\r\nfor xref in idautils.CodeRefsTo(xor_chunk_addr, 0):\r\nmov_addr = list(idautils.CodeRefsTo(xref, 0))[0] - 5\r\nn = idc.get_operand_value(mov_addr, 1)\r\noffset = (xref + 5) - 0x400000\r\nxor_chunk(offset, n)\r\nAfter the decryption:\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 7 of 18\n\nOne thing to note here, SmokeLoader tries to keep as many encrypted code as possible. So once it’s done with the\r\ndecrypted functions, it encrypts it again.\r\nAnti HookingPermalink\r\nMany Sandboxes and Security Solutions hook user-land functions of ntdll.dll to trace system calls.\r\nSmokeLoader tries to evade this by using its own copy of ntdll. It copies ntdll.dll to \"%TEMP%\\\r\n\u003chardcoded_name\u003e.tmp\" then loads it using LdrLoadDll() and resolves its imports from it.\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 8 of 18\n\nCustom ImportsPermalink\r\nSmokeLoader stores a hash table of its imports, it uses the same PEB traversal technique explained earlier to\r\nwalk through the DLLs’ export table and compare the hash of each API name with the stored hashes.\r\nThe hashing function is an implementation of djb2 hashing algorithms:\r\nint calc_hash(char *api_name) {\r\nint hash=0x1505;\r\nfor(int i=0; i\u003c=strlen(api_name); i++) // null byte included\r\nhash = ((hash \u003c\u003c 5) + hash) + api_name[i];\r\nreturn hash;\r\n}\r\nHere is a list of imported functions and their corresponding hashes:\r\nExpand to see more\r\n  ntdll.dll\r\n      LdrLoadDll (0x64033f83)\r\n      NtClose (0xfd507add)\r\n      NtTerminateProcess (0xf779110f)\r\n      RtlInitUnicodeString (0x60a350a9)\r\n      RtlMoveMemory (0x845136e7)\r\n      RtlZeroMemory (0x8a3d4cb0)\r\n  kernel32.dll\r\n      CopyFileW (0x306cceb7)\r\n      CreateEventW (0xfd4027f2)\r\nAnd here is the list of the imported functions from the copied ntdll (for anti-hooking):\r\nExpand to see more\r\n  4DD3.tmp\r\n      NtAllocateVirtualMemory (0x5a0c2ccc)\r\n      NtCreateSection (0xd5f23ad0)\r\n      NtEnumerateKey (0xb6306996)\r\n      NtFreeVirtualMemory (0x2a6fa509)\r\n      NtMapViewOfSection (0x870246aa)\r\n      NtOpenKey (0xc29efe42)\r\n      NtOpenProcess (0x507bcb58)\r\n      NtQueryInformationProcess (0xd6d488a2)\r\n      NtQueryKey (0xa9475346)\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 9 of 18\n\nAnti VMPermalink\r\nSmokeLoader enumerates all the subkeys of these keys:\r\nSystem\\CurrentControlSet\\Enum\\IDE\r\nSystem\\CurrentControlSet\\Enum\\SCSI\r\nThen it transforms them into lowercase and searches for these strings in the enumerated keys names:\r\nqemu\r\nvirtio\r\nvmware\r\nvbox\r\nxen\r\nIf one of them is found, the binary exits.\r\nProcess InjectionPermalink\r\nSmokeLoader uses PROPagate injection method to inject the next stage into explorer.exe .\r\nFirst it decompresses the next stage using RtlDecompressBuffer() .\r\nThen there is a call to NtOpenProcess() to open explorer.exe for the injection.\r\nThe injection process starts by creating two shared sections between the current process and explorer process (one\r\nsection for the modified property and the other for the next stage’s code), then SmokeLoader maps the created\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 10 of 18\n\nsections to the current process and explorer process memory space (so any changes in the sections will be\r\nreflected in explorer process).\r\nNote that both sections have \"RWX\" protection which might raise some red flags by security solutions.\r\nWe can see that explorer got a handle to these two sections (this is similar to classic code injection but with much\r\nmore stealth).\r\nSmokeLoader then writes the next stage to one of the sections and the modified property (which will call the next\r\nstage’s code) to the other section.\r\nFinally, it sets the modified property using SetPropA() and sends a message to explorer window using\r\nSendNotifyMessageA() , this will result in the injected code being executed in the context of explorer.exe .\r\nStage 3Permalink\r\nThis is the final stage of SmokeLoader, it starts by doing some anti-analysis checks.\r\nChecking Running ProcessesPermalink\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 11 of 18\n\nThis stage loops through the running process, it calculates each process name’s hash and compares it against some\r\nhardcoded hashes.\r\nHere is the algorithm for calculating the hash of a process name:\r\nuint ROL(uint x, uint bits) {\r\nreturn x\u003c\u003cbits | x\u003e\u003e(32-bits);\r\n}\r\nint calc_hash(char *proc_name) {\r\nint hash = 0;\r\nfor(int i=0; i\u003cstrlen(proc_name); i++)\r\nhash = (proc_name[i] \u0026 0xDF) + ROL(hash ^ (proc_name[i] \u0026 0xDF), 8);\r\nreturn hash ^ 0xD781F33C;\r\n}\r\nA quick guess and I could get the processes names:\r\n0xD384255C → Autoruns.exe\r\n0x76BDCBAB → procexp.exe\r\n0xA159E6BE → procexp64.exe\r\n0x7E9CCCA5 → procmon.exe\r\n0xA24B8E63 → procmon64.exe\r\n0x63B3D1A4 → Tcpview.exe\r\n0xA28974F3 → Wireshark.exe\r\n0xA9B5F897 → ProcessHacker.exe\r\n0x6893EBAB → ollydbg.exe\r\n0xF5FD94B7 → x32dbg.exe\r\n0xCBFD99B0 → x64dbg.exe\r\n0x8993DEE5 → idaq.exe\r\n0x8993D8CF → idaw.exe\r\n0x8C083960 → idaq64.exe\r\n0xB6223960 → idaw64.exe\r\nIf one of these processes is found to be running, explorer.exe will exit.\r\nEncrypted StringsPermalink\r\nAll strings of this stage are encrypted using RC4 and they are decrypted on demand. The RC4 key =\r\n0xFA5F66D7 .\r\nThe encrypted strings are stored continuously in a big blob in this form:\r\nHere is a small script for decrypting these strings (I used Go because it has native support for RC4).\r\npackage main\r\nimport (\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 12 of 18\n\n\"fmt\"\r\n\"io/ioutil\"\r\n\"encoding/hex\"\r\n\"crypto/rc4\"\r\n)\r\nvar RC4_KEY, _ = hex.DecodeString(\"FA5F66D7\")\r\nfunc rc4_decrypt(data []byte) {\r\ncipher, _ := rc4.NewCipher(RC4_KEY)\r\ncipher.XORKeyStream(data, data)\r\nfmt.Printf(\"%s\\n\", data)\r\n}\r\nfunc main() {\r\ndata, _ := ioutil.ReadFile(\"dump\")\r\nfor i := 0; i \u003c len(data); {\r\nn := int(data[i])\r\nrc4_decrypt(data[i+1:i+n+1])\r\ni += n+1\r\n}\r\n}\r\nAnd here is the decrypted strings:\r\nExpand to see more\r\n  http://www.msftncsi.com/ncsi.txt\r\n  Software\\Microsoft\\Internet Explorer\r\n  advapi32.dll\r\n  Location:\r\n  plugin_size\r\n  \\explorer.exe\r\n  user32\r\nEncrypted C2 DomainsPermalink\r\nThe C2 domains are encrypted using simple XOR operations.\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 13 of 18\n\nThey are stored in a in this form:\r\nWe can easily decrypt the domains:\r\ndef decrypt_c2(enc, key):\r\nenc, key = bytes.fromhex(enc), bytes.fromhex(key)\r\ndec = \"\"\r\nfor c in enc:\r\nfor i in key: c = c ^ i\r\ndec += chr(c ^ 0xE4)\r\nprint(dec)\r\n# decrypt_c2(\"E7FBFBFFB5A0A0E2E0FCFBEAFCFBA2FCEAFDF9E6ECEABFBEBDBABFBAA1FDFAA0\", \"EFC11A5F\")\r\n# http://mostest-service012505.ru/\r\nC2 CommunicationsPermalink\r\nSmokeLoader sleeps for 10 seconds (1000*10) before connecting to the Internet.\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 14 of 18\n\nFirst it queries http://www.msftncsi.com/ncsi.txt (This URL is usually queried by Windows to determine if\r\nthe computer is connected to the Internet).\r\nIf there’s no response, it sleeps for 64 ms and queries it again until it receives a response.\r\nThen SmokeLoader sends a POST request to the C2 server. The payload is encrypted using RC4 before sending\r\nit.\r\nThe POST request returns a \"404 Not Found\" response but it contains a payload in the response body.\r\nUnfortunately most of the C2 domains are down so I couldn’t proceed with the analysis, but I think that’s enough\r\nwith SmokeLoader :)\r\nIOCsPermalink\r\nHashesPermalink\r\nSmokeLoader fc20b03299b8ae91e72e104ee4f18e40125b2b061f1509d1c5b3f9fac3104934\r\nFilesPermalink\r\n%TEMP%\\4dd3.dll\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 15 of 18\n\nC2 DomainsPermalink\r\nhttp://alltest-service012505[.]ru/\r\nhttp://besttest-service012505[.]ru/\r\nhttp://biotest-service012505[.]ru/\r\nhttp://clubtest-service012505[.]ru/\r\nhttp://domtest-service012505[.]ru/\r\nhttp://infotest-service012505[.]ru/\r\nhttp://kupitest-service012505[.]ru/\r\nhttp://megatest-service012505[.]ru/\r\nhttp://mirtest-service012505[.]ru/\r\nhttp://mostest-service012505[.]ru/\r\nhttp://mytest-service01242505[.]ru/\r\nhttp://mytest-service012505[.]ru/\r\nhttp://newtest-service012505[.]ru/\r\nhttp://proftest-service012505[.]ru/\r\nhttp://protest-01242505[.]tk/\r\nhttp://protest-01252505[.]ml/\r\nhttp://protest-01262505[.]ga/\r\nhttp://protest-01272505[.]cf/\r\nhttp://protest-01282505[.]gq/\r\nhttp://protest-01292505[.]com/\r\nhttp://protest-01302505[.]net/\r\nhttp://protest-01312505[.]org/\r\nhttp://protest-01322505[.]biz/\r\nhttp://protest-01332505[.]info/\r\nhttp://protest-01342505[.]eu/\r\nhttp://protest-01352505[.]nl/\r\nhttp://protest-01362505[.]mobi/\r\nhttp://protest-01372505[.]name/\r\nhttp://protest-01382505[.]me/\r\nhttp://protest-01392505[.]garden/\r\nhttp://protest-01402505[.]art/\r\nhttp://protest-01412505[.]band/\r\nhttp://protest-01422505[.]bargains/\r\nhttp://protest-01432505[.]bet/\r\nhttp://protest-01442505[.]blue/\r\nhttp://protest-01452505[.]business/\r\nhttp://protest-01462505[.]casa/\r\nhttp://protest-01472505[.]city/\r\nhttp://protest-01482505[.]click/\r\nhttp://protest-01492505[.]company/\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 16 of 18\n\nhttp://protest-01502505[.]futbol/\r\nhttp://protest-01512505[.]gallery/\r\nhttp://protest-01522505[.]game/\r\nhttp://protest-01532505[.]games/\r\nhttp://protest-01542505[.]graphics/\r\nhttp://protest-01552505[.]group/\r\nhttp://protest-02252505[.]ml/\r\nhttp://protest-02262505[.]ga/\r\nhttp://protest-02272505[.]cf/\r\nhttp://protest-02282505[.]gq/\r\nhttp://protest-03252505[.]ml/\r\nhttp://protest-03262505[.]ga/\r\nhttp://protest-03272505[.]cf/\r\nhttp://protest-03282505[.]gq/\r\nhttp://protest-05242505[.]tk/\r\nhttp://protest-06242505[.]tk/\r\nhttp://protest-service01242505[.]ru/\r\nhttp://protest-service012505[.]ru/\r\nhttp://rustest-service012505[.]ru/\r\nhttp://rutest-service01242505[.]ru/\r\nhttp://rutest-service012505[.]ru/\r\nhttp://shoptest-service012505[.]ru/\r\nhttp://supertest-service012505[.]ru/\r\nhttp://test-service01242505[.]ru/\r\nhttp://test-service012505[.]com/\r\nhttp://test-service012505[.]eu/\r\nhttp://test-service012505[.]fun/\r\nhttp://test-service012505[.]host/\r\nhttp://test-service012505[.]info/\r\nhttp://test-service012505[.]net/\r\nhttp://test-service012505[.]net2505[.]ru/\r\nhttp://test-service012505[.]online/\r\nhttp://test-service012505[.]org2505[.]ru/\r\nhttp://test-service012505[.]pp2505[.]ru/\r\nhttp://test-service012505[.]press/\r\nhttp://test-service012505[.]pro/\r\nhttp://test-service012505[.]pw/\r\nhttp://test-service012505[.]ru[.]com/\r\nhttp://test-service012505[.]site/\r\nhttp://test-service012505[.]space/\r\nhttp://test-service012505[.]store/\r\nhttp://test-service012505[.]su/\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 17 of 18\n\nhttp://test-service012505[.]tech/\r\nhttp://test-service012505[.]website/\r\nhttp://test-service012505[.]xyz/\r\nhttp://test-service01blog2505[.]ru/\r\nhttp://test-service01club2505[.]ru/\r\nhttp://test-service01forum2505[.]ru/\r\nhttp://test-service01info2505[.]ru/\r\nhttp://test-service01land2505[.]ru/\r\nhttp://test-service01life2505[.]ru/\r\nhttp://test-service01plus2505[.]ru/\r\nhttp://test-service01pro2505[.]ru/\r\nhttp://test-service01rus2505[.]ru/\r\nhttp://test-service01shop2505[.]ru/\r\nhttp://test-service01stroy2505[.]ru/\r\nhttp://test-service01torg2505[.]ru/\r\nhttp://toptest-service012505[.]ru/\r\nhttp://vsetest-service012505[.]ru/\r\nReferencesPermalink\r\nhttps://www.cert.pl/en/news/single/dissecting-smoke-loader/\r\nhttps://research.checkpoint.com/2019/2019-resurgence-of-smokeloader/\r\nhttps://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb\r\nhttps://www.aldeid.com/wiki/PEB-Process-Environment-Block\r\nhttp://www.hexacorn.com/blog/2017/10/26/propagate-a-new-code-injection-trick\r\nhttps://modexp.wordpress.com/2018/08/23/process-injection-propagate/\r\nhttps://docs.microsoft.com/en-us/windows/win32/api/winhttp/nf-winhttp-winhttpconnect#examples\r\nhttps://www.crowdstrike.com/blog/maze-ransomware-deobfuscation/\r\nSource: https://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nhttps://n1ght-w0lf.github.io/malware%20analysis/smokeloader/\r\nPage 18 of 18",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://n1ght-w0lf.github.io/malware%20analysis/smokeloader/"
	],
	"report_names": [
		"smokeloader"
	],
	"threat_actors": [],
	"ts_created_at": 1775434818,
	"ts_updated_at": 1775791285,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/b0db413c2167baab161ac63c8cf0b066be561d05.pdf",
		"text": "https://archive.orkl.eu/b0db413c2167baab161ac63c8cf0b066be561d05.txt",
		"img": "https://archive.orkl.eu/b0db413c2167baab161ac63c8cf0b066be561d05.jpg"
	}
}