Packer: VMProtect
Compilation date: 2018.10.21, 14:53:39.
SHA1:
- 75ec1a47404193c1a6a0b1fb61a414b7a2269d08 (Mp3enc.asi)
Description
Trojan.Belonard.2 is part of the Belonard trojan. It gets uploaded to a victim’s device by the Trojan.Belonard.1. It downloads and runs Trojan.Belonard.3.
Operating routine
In DllMain, it checks the name of the process in which the dll file is uploaded. If it’s not rundll32.exe, it creates a thread with the key [HKCU\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers] '<path to the executable file process>, and assigns it value “RUNASADMIN”. The malicious library has an exported function named “xW”, in which it immediately performs its main function.
If a disk on which the trojan is stored doesn’t have the FILE_READ_ONLY_VOLUME flag, the trojan deletes the Mssv24.asi file. If deleting the file is not possible, it renames the file to a random name with the .dat extension and deletes it. After that, it creates a mutual exclusion named "qfincshmkhftobll”.
Additionally, the program tries to read the contents of the platform\Servers\DialogGameName.res file. If no such file exists, the program creates it and writes 16 random bytes in it. Following that, the trojan changes the Created/Modified/Accessed dates of the file to the same date of the Mssv12.asi, Mssv29.asi, Mss32.dll or hl.exe files.
The program gathers the system’s data and transforms it into the following structure:
#pragma pack(push, 1)
struct st_info
{
_BYTE byte0; // 0x01
_BYTE bIsWow64Process;
_BYTE DialogGameNameResData[0x10];
_DWORD dwProductVersionMS;
_WORD ProductVersionLS; // (dwProductVersionLS & 0xffff0000) >> 16
_WORD DefaultUILang;
_DWORD TotalMemory; // in Mb
_DWORD dwNumberOfProcessors;
_WORD wProcessorArchitecture;
_WORD wProcessorLevel;
_WORD wProcessorRevision;
_QWORD ticks;
_BYTE IsTokenElevated;
_BYTE IsWinDHCPServiceRunning;
_BYTE IsWinDHCPDllExists;
_BYTE IsDavapiDllExists;
_BYTE IsSpwinresDllExists;
_BYTE IsWmcodecsDllExists;
_BYTE IsSsdp32DllExists;
char szSystemDir[];
char szSysWow64Dir[]; // absent for x86 OS
char szMp3encAsiPath[];
char szProcessExePath[];
char szCurrentDir[];
_BYTE IsMssv24AsiExists;
_BYTE IsDialogServerNameResExists;
_BYTE DialogServerNameResData[0x0e];
_BYTE IsCstrikeSaveFolderExists;
_DWORD dwCstrikeSaveFilesCount;
_BYTE IsSteamClient;
_BYTE ModSHA256[32];
}
#pragma pack(pop)
If the platform\Servers\DialogGamePage.res file is present, the malware reads the information about the previously downloaded payload from that file and adds it to the st_info.
Gathered data fits the following structure:
#pragma pack(push,1)
struct st_packet
{
_BYTE byte0; //0x00
_BYTE aeskey2[0x20]; // absent if size of resulting st_packet structure is less to 342 bytes
_BYTE aeskey[0x20];
_DWORD size;
_BYTE data[size]; // st_info struct
}
#pragma pack(pop)
The data then gets encrypted with a public RSA key embedded into the trojan. Only the first 342 bytes will be encrypted by the RSA; the rest (if present) will be encrypted by the AES in a CFB mode with a block size of 128 bits and the key taken from the st_packet->aeskey2, by making a call to EVP_BytesToKey(cipher, md_sha256, 0, &st_packet->aeskey2, 32, 5, key, iv).
Then, after a zero byte is added at the beginning of the packet, the data is sent to the C&C server: wcnclfbi.valve-ms[.]ru:28748. In response, the server sends encrypted data of the following structure:
struct st_payload
{
_BYTE hash1[32];
_DWORD totalsize;
_BYTE hash2[32];
_DWORD dword44;
_DWORD dword48;
_DWORD dword4c;
_WORD word50;
char payload_name[];
_BYTE payload_sha256[32];
_DWORD payload_size;
_BYTE payload_data[payload_size];
}
The decryption is performed with AES in a CFB mode with a block size of 128 bits. The key is taken from the st_packet->aeskey, as described earlier. The first 36 bytes of data are decrypted first, including the last DWORD value that shows the actual payload with the header. The DWORD value adds to the AES key and is hashed using SHA256. The resulting hash must match the first 32 decrypted bytes. The remaining received data is decrypted only after this. The next 36 bytes of data are decrypted in the same way, but the DWORD at offset 0x44 is no longer the size of the payload and is used only for hashing. The header of the packet has a name, which is saved along with the payload, its size and the sha256 hash.
The trojan saves the encrypted data structure into the platform\Servers\DialogGamePage.res file as follows:
struct gamepage
{
_BYTE byte0; // 0x01
char modname[];
_BYTE modsha256[32];
_BYTE byte1; // 0x03
_DWORD dword2;
_QWORD qword3;
}
The algorithms of encryption/decryption are similar to those of Trojan.Belonard.1:
def encbuf(data):
c = random.randint(11, 245)
d = random.randint(11, 245)
e = random.randint(11, 245)
f = random.randint(11, 245)
enc_r = ''
y = c
z = c
for i in range(len(data)):
y = (ord(data[i]) + f*z + e*y + d)&0xff
z = ord(data[i])
enc_r += chr(y & 0xff)
enc_r = '%c%c%c%c%s' % (d,f,e,c,enc_r)
return f,e,d,enc_r
def decbuf(f,e,d,enc):
y = ord(enc[0])
dec = ''
for i in range(1,len(enc)):
y = (ord(enc[i]) - e*ord(enc[i-1]) - f*y - d)&0xff
dec += chr(y)
return dec
The trojan saves the payload in the Mssv16.asi(Trojan.Belonard.3) file and runs its exported function through rundll32.exe.
The program has some encrypted lines of code. Here’s the decryption algorithm:
def decrypt(d):
s = ''
c = ord(d[0])
for i in range(len(d)-1):
c = (ord(d[i+1]) + 0xe2*c - 0x2f*ord(d[i]) - 0x58) & 0xff
s += chr(c)
return s