1/18 June 21, 2020 Deep Analysis of SmokeLoader n1ght-w0lf.github.io/malware analysis/smokeloader/ Abdallah Elshinbary Malware Analysis & Reverse Engineering Adventures 13 minute read SmokeLoader is a well known bot that is been around since 2011. It’s mainly used to drop other malware families. SmokeLoader has been under development and is constantly changing with multiple novel features added throughout the years. Sample SHA256: fc20b03299b8ae91e72e104ee4f18e40125b2b061f1509d1c5b3f9fac3104934 https://n1ght-w0lf.github.io/malware%20analysis/smokeloader/ https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/0.png 2/18 Stage 1 This stage starts off by allocating memory for shellcode using LocalAlloc() (not VirtualAlloc), then it fills this memory with the shellcode (86 KB). Next, it changes the protection of the allocated memory region to PAGE_EXECUTE_READWRITE using VirtualProtect() , then it writes the shellcode and executes it. Shellcode The shellcode starts by getting the addresses of LoadLibraryA and GetProcAddress to resolve APIs dynamically, but first let’s see how it does that. First it passes some hash values to a sub-routine that returns the address of the requested function. https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/1.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/2.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/3.png 3/18 After some digging, I found out that the algorithm for calculating the hashes is pretty simple. int calc_hash(char* name) { int x, hash = 0; for(int i=0; i.tmp" then loads it using LdrLoadDll() and resolves its imports from it. Custom Imports SmokeLoader stores a hash table of its imports, it uses the same PEB traversal technique explained earlier to walk through the DLLs’ export table and compare the hash of each API name with the stored hashes. The hashing function is an implementation of djb2 hashing algorithms: int calc_hash(char *api_name) { int hash=0x1505; for(int i=0; i<=strlen(api_name); i++) // null byte included hash = ((hash << 5) + hash) + api_name[i]; return hash; } Here is a list of imported functions and their corresponding hashes: Expand to see more ntdll.dll LdrLoadDll (0x64033f83) NtClose (0xfd507add) NtTerminateProcess (0xf779110f) RtlInitUnicodeString (0x60a350a9) RtlMoveMemory (0x845136e7) https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/15.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/16.png 9/18 RtlZeroMemory (0x8a3d4cb0) kernel32.dll CopyFileW (0x306cceb7) CreateEventW (0xfd4027f2) CreateFileMappingW (0x5b3f901c) CreateThread (0x60277e71) DeleteFileW (0xb7e96d0f) ExpandEnvironmentStringsW (0x057074bb) GetModuleFileNameA (0x8acccaed) GetModuleFileNameW (0x8acccdc3) GetModuleHandleA (0x9cbd2a58) GetSystemDirectoryA (0xaebc5060) GetTempFileNameW (0x9a376a33) GetTempPathW (0x7e28b9df) GetVolumeInformationA (0xf25ce6a4) LocalAlloc (0xeda647bb) LocalFree (0x742c61b2) MapViewOfFile (0x4db4c713) Sleep (0xd156a5be) WaitForSingleObject (0x8681d8fa) lstrcatW (0x2ab51a99) lstrcmpA (0x2abb9b4b) user32.dll EnumChildWindows (0x9a8897c9) EnumPropsA (0x8f0f57cf) GetForegroundWindow (0x5a6c9878) GetKeyboardLayoutList (0x04e9de30) GetShellWindow (0xd454e895) GetWindowThreadProcessId (0x576a5801) SendMessageA (0x41ecd315) SendNotifyMessageA (0xc6123bae) SetPropA (0x90bc10d3) wsprintfW (0x0bafd3f9) advapi32.dll GetTokenInformation (0x696464ac) OpenProcessToken (0x74f5e377) shell32.dll ShellExecuteExW (0xf8e40384) And here is the list of the imported functions from the copied ntdll (for anti-hooking): Expand to see more 4DD3.tmp NtAllocateVirtualMemory (0x5a0c2ccc) NtCreateSection (0xd5f23ad0) NtEnumerateKey (0xb6306996) NtFreeVirtualMemory (0x2a6fa509) NtMapViewOfSection (0x870246aa) NtOpenKey (0xc29efe42) NtOpenProcess (0x507bcb58) NtQueryInformationProcess (0xd6d488a2) NtQueryKey (0xa9475346) NtQuerySystemInformation (0xb83de8a8) NtUnmapViewOfSection (0x8352aa4d) NtWriteVirtualMemory (0x546899d2) RtlDecompressBuffer (0xdeb36606) 10/18 towlower (0xf7660ba8) wcsstr (0xbb629f0b) Anti VM SmokeLoader enumerates all the subkeys of these keys: System\CurrentControlSet\Enum\IDE System\CurrentControlSet\Enum\SCSI Then it transforms them into lowercase and searches for these strings in the enumerated keys names: qemu virtio vmware vbox xen If one of them is found, the binary exits. Process Injection SmokeLoader uses PROPagate injection method to inject the next stage into explorer.exe . First it decompresses the next stage using RtlDecompressBuffer() . Then there is a call to NtOpenProcess() to open explorer.exe for the injection. https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/17.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/18.png http://www.hexacorn.com/blog/2017/10/26/propagate-a-new-code-injection-trick/ https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/19.png 11/18 The injection process starts by creating two shared sections between the current process and explorer process (one section for the modified property and the other for the next stage’s code), then SmokeLoader maps the created sections to the current process and explorer process memory space (so any changes in the sections will be reflected in explorer process). Note that both sections have "RWX" protection which might raise some red flags by security solutions. We can see that explorer got a handle to these two sections (this is similar to classic code injection but with much more stealth). SmokeLoader then writes the next stage to one of the sections and the modified property (which will call the next stage’s code) to the other section. https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/20.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/21.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/22.png https://n1ght-w0lf.github.io/assets/images/malware-analysis/smokeloader/23.png 12/18 Finally, it sets the modified property using SetPropA() and sends a message to explorer window using SendNotifyMessageA() , this will result in the injected code being executed in the context of explorer.exe . Stage 3 This is the final stage of SmokeLoader, it starts by doing some anti-analysis checks. Checking Running Processes This stage loops through the running process, it calculates each process name’s hash and compares it against some hardcoded hashes. Here is the algorithm for calculating the hash of a process name: uint ROL(uint x, uint bits) { return x<>(32-bits); } int calc_hash(char *proc_name) { int hash = 0; for(int i=0; i