Упаковщик: нет
Дата компиляции: 2020-14-10
- SHA1-хеш: ff82dcadb969307f93d73bbed1b1f46233da762f
Описание
Загрузчик бэкдора PlugX, написан на языке C.
Принцип действия
После загрузки из основного модуля (msrers.exe) функцией LoadLibraryW троян загружает библиотеку kernel32.dll с помощью фунцкии LoadLibraryA и получает адрес экспортируемой функции GetModuleFileNameA:
Затем он получает имя основного модуля с помощью ранее полученной функции GetModuleFileNameA и проверяет, содержится ли в имени подстрока "ers." (msrers.exe):
По хешу 0xEF64A41E получает функцию VirtualProtect для изменения прав доступа памяти на PAGE_EXECUTE_READWRITE по адресу 0x416362 (msrers.exe):
Следующим фрагментом будет модифицирован код по адресу 0x416362 (msrers.exe):
push 0xFFFFFFFF
push 0x100010B0 ; func_addr
ret
Место в основном модуле, которое будет модифицировано:
Далее вызывается функция, которая получает базу kernel32.dll, а также адреса функций по хешам.
Скрипт для получения функции по хешу:
import pefile
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
max_bits = 32
library_path_list = [...] # absolute path dlls
def get_func_addr(hash):
for i in xrange(len(library_path_list)):
library = library_path_list[i].split('\\')
name_dll = library[len(library) - 1]
pe = pefile.PE(library_path_list[i])
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
func_name = exp.name
hash_name_func = 0
for j in func_name:
hash_name_func = ord(j) + ror(hash_name_func, 0x07, max_bits)
if (hash_name_func == hash):
print '0x{:08x} -> {} -> {}'.format(hash, name_dll, exp.name)
return
Полученные функции
Имя функции | Хеш |
---|---|
VirtualProtect | 0xEF64A41E |
GetLastError | 0x12F461BB |
CloseHandle | 0xFF0D6657 |
ReadFile | 0x130F36B2 |
VirtualAlloc | 0x1EDE5967 |
GetFileSize | 0xAC0A138E |
CreateFileA | 0x94E43293 |
lstrcat | 0x3E8F97C3 |
GetModuleFileNameA | 0xB4FFAFED |
В дальнейшем для вызова этих функций используется следующая структура:
struct api_addr {
DWORD (__stdcall *GetModuleFileNameA)(HMODULE, LPSTR, DWORD);
LPSTR (__stdcall *lstrcat)(LPSTR, LPCSTR);
HANDLE (__stdcall *CreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
DWORD (__stdcall *GetFileSize)(HANDLE, LPDWORD);
LPVOID (__stdcall *VirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
BOOL (__stdcall *ReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
BOOL (__stdcall *CloseHandle)(HANDLE);
DWORD (__stdcall *GetLastError)();
};
Троян получает имя dll (TmDbgLog.dll) и добавляет к нему расширение ".TSC". Далее открывает для чтения файл TmDbgLog.dll.TSC и расшифровывает его содержимое, которое оказывается шелл-кодом.
После расшифровки шелл-кода (TmDbgLog.dll) троян приступает к его выполнению:
Так выглядит скрипт для расшифровки шелл-кода:
enc = bytearray(open('TmDbgLog.dll.TSC', 'rb').read())
dec = bytearray()
for i in xrange(len(enc)):
dec.append(((enc[i] ^ 0xbb) - 1) & 0xff)
open('TmDbgLog.dll.TSC.dec', 'wb').write(dec)
Перед дешифрованием и запуском полезной нагрузки шелл-код собирает следующую структуру:
struct st_mw {
DWORD magic;
DWORD *shell_base;
DWORD shell_size;
DWORD *enc_payload;
DWORD enc_payload_size;
DWORD *enc_config;
DWORD enc_config_size;
DWORD *payload_entry;
};
Так выглядит зашифрованный конфиг:
Дешифрование конфига будет выполнено уже непосредственно в полезной нагрузке:
import struct
enc = open('enc_cfg', 'rb').read()
key, = struct.unpack('I', enc[0:4])
key1 = key
key2 = key
key3 = key
dec = bytearray()
for i in xrange(len(enc)):
key = (key + (key >> 3) - 0x11111111) & 0xFFFFFFFF
key1 = (key1 + (key1 >> 5) - 0x22222222) & 0xFFFFFFFF
key2 = (key2 + 0x33333333 - (key2 << 7)) & 0xFFFFFFFF
key3 = (key3 + 0x44444444 - (key3 << 9)) & 0xFFFFFFFF
dec.append(ord(enc[i]) ^ (key + key1 + key2 + key3) & 0xFF)
open('dec_cfg', 'wb').write(dec)
И будет выглядеть следующим образом:
Зашифрованная полезная нагрузка:
Скрипт для дешифрования полезной нагрузки:
import struct
import ctypes
enc = open('enc_payload', 'rb').read()
key, = struct.unpack('I', enc[0:4])
key1 = key
key2 = key
key3 = key
dec = bytearray()
for i in xrange(len(enc)):
key = (key + (key >> 3) + 0x55555556) & 0xFFFFFFFF
key1 = (key1 + (key1 >> 5) + 0x44444445) & 0xFFFFFFFF
key2 = (key2 + 0xCCCCCCCC - (key2 << 7)) & 0xFFFFFFFF
key3 = (key3 + 0xDDDDDDDD - (key3 << 9)) & 0xFFFFFFFF
dec.append(ord(enc[i]) ^ (key + key1 + key2 + key3) & 0xFF)
d = bytes(dec)
uncompress_size, = struct.unpack('I', d[8:12])
buf_decompressed = ctypes.create_string_buffer(uncompress_size)
final_size = ctypes.c_ulong(0)
ctypes.windll.ntdll.RtlDecompressBuffer(2, buf_decompressed, ctypes.sizeof(buf_decompressed), ctypes.c_char_p(d[0x10:]), len(d), ctypes.byref(final_size))
open('dec_payload', 'wb').write(buf_decompressed)
После дешифрования полезной нагрузки шелл-код передает трояну управление, при этом в качестве одного из параметров выступает ранее собранная структура st_mw:
Дальше троян работает так же, как бэкдор BackDoor.PlugX.28.