In the middle of November, a friend told me of a new malware being sold on Russian forums under the name “Buer Loader”. A translated copy of the thread where it is advertised can be found here. A google search revealed no one having mentioned “Buer Loader” before, nor provided an analysis of it. However, a forum administrator had already provided an analysis of the malware, in which the following screenshot of strings was provided.
With this, we can now hunt for Buer Loader samples. Based on the strings, a variety of samples that drop Buer Loader or is Buer Loader were found. Their hashes are listed below:
MalwareHunterTeam also found a sample, though he did not refer to it by name. Strings for the file was posted by James_inthe_box.
A large number of samples, such as 0dd7e132fb5e9dd241ae103110d085bc4d1ef7396ca6c84a3b91dc44f3aff50f which was spotted on November 12th multiple times, are packed with Themida. We thankfully found one that wasn’t, with the hash of 6c694df8bde06ffebb8a259bebbae8d123effd58c9dd86564f7f70307443ccd0.
The file in question is a VB6 file, and can be found on Hybrid-Analysis.
After starting, the process executes a shellcode that is stored on the heap. Due to the process not having DEP enabled, the shellcode runs fine.
The shellcode does a typical process hollowing. The original image is unmapped below.
Next NtWriteVirtualMemory is called using DllCallFunction to write the malicious payload.
Dumping it from memory and trimming the overlay, we have a 27kb executable file that appears to be compiled with Visual Studio 2017. This would seem to be our original Buer Loader file. The TimeDateStamp indicates that it was compiled on Thu, 29 Aug 2019 05:48:03 UTC.
The file starts out with checking for debugger by reading PEB->BeingDebugged. If this check is passed, it checks for virtualization, and then enter the real code.
Here, the code uses sidt/sgdt to detect the presence of virtualization. More details on that can be found here.
The bot then enters the “real” main function.
Here, APIs are resolved and strings are decrypted. String decryption is done in a slightly peculiar manner, rather than passing a string directly to the decryption function the pointer to the WORD before it is passed. The first WORD is then ignored, and the rest is decrypted. In order to facilitate easy IDA reference searches, I opted to create a simple struct so that both the call to decrypt and the reference to the strings are in one place.
Interestingly, IDA did not detect the prototype of decrypt_str (and several other functions) correctly, and ignored the parameter passed in ECX. When the file was originally loaded, the original prototype was “unsigned int __cdecl decrypt_str(int length)”. Changing it to “void __usercall decrypt_str(int length, strdec_header *encryptedStr)” is necessary for IDA to decompile the function and calls to it successfully.
I modified an IDAPython script for decrypting strings (a few strings will fail due to duplicates or unicode, but the vast majority works fine). The script can be found on GitLab.
APIs are resolved by hash. The hashing algorithm is the typical ror13 algorithm that is often used in shellcodes.
After resolving the APIs and decrypting strings, the file checks to see whether it is operating in CIS countries. This is mandated as a part of the rule of the forum where the malware operates.
After the check is passed, the file adds itself to startup using a peculiar method. It first gathers the command required to create a task that runs the bot every 2 minutes, and then add that command to the RunOnce key.
After this, it enters the main loop and attempts to ensure persistence. To prevent the file from being deleted (or opened), it performs an interesting technique of forcing open a handle to the file inside the context of Explorer.exe. First, it gets a handle to explorer indirectly by first getting a handle with PROCESS_DUP_HANDLE privilege, and then using DuplicateHandle to create a handle with PROCESS_ALL_ACCESS. Thus far I have not seen this trick in malware but rather only in the cheating scene, perhaps indicative of the author’s involvement in such areas.
After this, it creates a handle to it’s own file with dwSharing set to 0 (thus preventing any other process from accessing the file), and duplicates the handle into the explorer process.
A rather unique choice of persistence that I have not observed before. Interestingly, it would appear that this effectively blocks Hybrid Analysis from reading the file (despite their analysis operating primarily at ring 0), with reports not displaying the file icon. Possibly part of their analysis currently runs from usermode and as a result was blocked by this.
At this point in the analysis, I found out that ProofPoint published an analysis of the loader a few hours before. As such, I’ll refer to their description of the HTTP requests and focus instead on how commands are handled.
The command handling function is decompiled relatively unclean, due to it’s size and the amount of switches and conditions IDA did not do a terrific job, however the decompilation serves it’s purposes. A few things of note:
- A lot of commands result in the process exiting, and as such SpawnInstanceOfSelf is called beforehand to create another instance of Buer before the command is executed. It is unclear why the loader could not perform the hollowing and continue execution.
- my_string_compare is equivalent to lstrcmpW and returns 0 if the string matches.
- Strings are duplicated a lot for unknown reasons.
Memload attempts a very basic process hollowing if the file successfully spawns another instance of itself. API callchain: CreateProcessW->GetThreadContext->ZwUnmapViewOfSection (optional)->VirtualAllocEx->WriteProcessMemory->NtQueryIformationProcess->SetThreadContext->ResumeThread->CloseHandle->ExitProcess.
Depending on the option set and whether it is running under WoW64 or not, LoadDllMem will either “inject” the DLL into itself (by using GetCurrentProcess/INVALID_HANDLE_VALUE as the handle) or repeat the trick of stealing explorer’s handle from itself. The injection is fairly standard, if 64 bit is set it will use heaven’s gate and it will use the normal API otherwise.
To initialize the DLL, a bootstrap shellcode is injected and called. A structure with pointers to the DLL and function pointers are passed to it.
The update mechanism of Buer Loader is relatively simple, and there is not much to say about it.
In conclusion, Buer is a new loader on the Russian malware scene and is relatively complex (especially when contrasted against certain bots such as Amadey). It still show inconsistencies that indicate a developer who is not experienced with low level development however, and it’s anti-analysis methods (such as API hashing or string encryption) are easily defeated with the use of IDAPython.