Поддержка
Круглосуточная поддержка

Позвоните

Бесплатно по России:
8-800-333-79-32

ЧаВо | Форум

Ваши запросы

  • Все: -
  • Незакрытые: -
  • Последний: -

Позвоните

Бесплатно по России:
8-800-333-79-32

Свяжитесь с нами Незакрытые запросы: 

Профиль

Профиль

BackDoor.ShadowPad.1

Добавлен в вирусную базу Dr.Web: 2020-06-25

Описание добавлено:

Упаковщик:

NSPack

Дата компиляции:

02.07.2017 05:59:15

SHA1-хеш:

4bba897ee81240b10f9cca41ec010a26586e8c09

Описание

Многокомпонентный троян-бэкдор, написанный с использованием языков С и Assembler, предназначенный для работы в 32- и 64-разрядных операционных системах семейства Microsoft Windows. Используется для целевых атак на информационные системы и несанкционированного доступа к данным для их передачи на управляющие серверы. Основная функциональность бэкдора реализована при помощи встроенных в его тело модулей — плагинов.

Принцип действия

DLL-модуль бэкдора загружается в оперативную память методом DLL Hijacking с помощью подлинного исполняемого файла TosBtKbd.exe от издателя TOSHIBA CORPORATION. На зараженном компьютере файл располагался под именем msmsgs.exe.

.>sigcheck -a msmsgs.exe_
    Verified:    Signed
    Signing date:    5:24 24.07.2008
    Publisher:    TOSHIBA CORPORATION
    Company:    TOSHIBA CORPORATION.
    Description:    TosBtKbd
    Product:    Bluetooth Stack for Windows by TOSHIBA
    Prod version:    6, 2, 0, 0
    File version:    6, 2, 0, 0
    MachineType:    32-bit
    Binary Version:    6.2.0.0
    Original Name:    TosBtKbd.exe
    Internal Name:    n/a
    Copyright:    Copyright (C) 2005-2008 TOSHIBA CORPORATION, All rights reserved.
    Comments:    n/a
    Entropy:    5.287

Бэкдор может быть связан с BackDoor.Farfli.125, так как обе вредоносные программы используют один и тот же управляющий сервер — www[.]pneword[.]net.

Рассмотренный образец находился на зараженном компьютере в директории C:\ProgramData\Messenger\ и был установлен в качестве службы Messenger.

Стоит отметить, что в BackDoor.Farfli.125 предусмотрена команда 0x7532, по которой бэкдор пытается установить службу с аналогичным названием — Messenger.

Начало работы

Вредоносная библиотека имеет две экспортируемые функции:

SetTosBtKbdHook
UnHookTosBtKbd

Имя модуля, указанное в таблице экспорта, — TosBtKbd.dll.

Функция DLLMain и экспортируемая функция UnHookTosBtKbd являются заглушками.

Функция SetTosBtKbdHook перебирает дескрипторы в поиске объектов, чьи имена содержат TosBtKbd.exe, а затем закрывает их.

int __stdcall check_handles()
{
  ULONG v0; // ecx
  HMODULE v1; // eax
  int result; // eax
  int iter; // esi
  int v4; // eax
  ULONG ReturnLength; // [esp+0h] [ebp-4h] BYREF
  ReturnLength = v0;
  if ( *(_DWORD *)NtQueryObject
    || (v1 = GetModuleHandleA(aNtdllDll),
        result = (int)GetProcAddress(v1, aNtqueryobject),
        (*(_DWORD *)NtQueryObject = result) != 0) )
  {
    iter = 0;
    while ( 1 )
    {
      if ( NtQueryObject((HANDLE)(4 * iter), ObjectNameInformation, &object__name_info, 0x1000u, &ReturnLength) >= 0 )
      {
        v4 = lstrlenW(object__name_info.Name.Buffer);
        do
          --v4;
        while ( v4 > 0 && object__name_info.Name.Buffer[v4] != 92 );
        if ( !lstrcmpiW(&object__name_info.Name.Buffer[v4 + 1], String2) )
          break;
      }
      if ( ++iter >= 100000 )
        return 0;
    }
    result = CloseHandle((HANDLE)(4 * iter));
  }
  return result;
}

После этого при помощи SetTosBtKbdHook расшифровывается шелл-код, который хранится в теле бэкдора.

screen BackDoor.ShadowPad.1 #drweb

Алгоритм расшифровки шелл-кода:

def LOBYTE(v):
  return v & 0xFF
def dump_shellcode(addr, size, key):
  buffer = get_bytes(addr, size)
  result = b""
  for x in buffer:
      result += bytes([x ^ LOBYTE(key)])
      key = ((key * 0x6A730000) - (((key >> 0x10) * 0x39F3958D)) - 0x5C0BB335) & 0xFFFFFFFF
  i = 0
  for x in result:
      patch_byte(addr + i, x)
      i += 1

Расшифрованный шелл-код сопротивляется анализу с помощью двух последовательных условных JMP-инструкций в одну точку.

screen BackDoor.ShadowPad.1 #drweb

После обхода обфускации функция приобретает корректный вид:

screen BackDoor.ShadowPad.1 #drweb

Шелл-код предназначен для загрузки основной полезной нагрузки, которая представляет собой разобранный PE-модуль без заголовков MZ и PE. Для загрузки используется специальный заголовок, состоящий из отдельных частей стандартных заголовков.

struct section
{
  DWORD RVA;
  DWORD raw_data_offset;
  DWORD raw_data_len;
};
struct module_header
{
  DWORD key;
  DWORD key_check;
  DWORD import_table_RVA;
  DWORD original_ImageBase;
  DWORD relocation_table_RVA;
  DWORD relocation_table_size;
  DWORD IAT_RVA;
  DWORD IAT_size;
  DWORD EP_RVA;
  WORD HDR32_MAGIC;
  WORD word;
  DWORD number_of_sections;
  DWORD timestamp;
  section section_1;
  section section_2;
  section section_3;
  section section_4;
};

Заголовок хранится в шелл-коде после первого блока инструкций.

screen BackDoor.ShadowPad.1 #drweb

Затем функция module_loader непосредственно загружает полезную нагрузку. Вначале через структуру PEB бэкдор получает адреса следующих функций из kernel32:

LoadLibraryA
GetProcAddress
VirtualAlloc
Sleep

Имя библиотеки Kernel32 и указанные API программа ищет по хешу имени, который вычисляется по алгоритму:

def rol(val, r_bits, max_bits=32):
  return (val << r_bits%max_bits) & (2**max_bits-1) | ((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def ror(val, r_bits, max_bits=32):
  return ((val & (2**max_bits-1)) >> r_bits%max_bits) | (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
def libnamehash(lib_name):
  result = 0
  b = lib_name.encode()
  for x in b:
      result = ror(result, 8)
      x |= 0x20
      result = (result + x) & 0xFFFFFFFF
      result ^= 0x7C35D9A3
  return result
def procnamehash(proc_name):
  result = 0
  b = proc_name.encode()
  for x in n:
      result = ror(result, 8)
      result = (result + x) & 0xFFFFFFFF
      result ^= 0x7C35D9A3
  return result

После получения адресов API бэкдор проверяет целостность значений из заголовка алгоритмом на основе XOR-операции — module_header.key ^ module_header.key_check. Значение должно быть равно 0x7C35D9A3; то же значение, что используется при хешировании имен функций из kernel32. После этого проверяет значение сигнатуры module_header.HDR32_MAGIC — оно должно быть равно 0x10B. Затем выделяет исполняемый буфер размером module_header.import_table_RVA и прибавляет 0x4000 под модуль.

После этого заполняет блок размером 0x1000 байт в начале выделенного буфера module_header.section_1.RVA — места, где должен был располагаться PE-заголовок загруженного модуля.

screen BackDoor.ShadowPad.1 #drweb

В регистре ECX при этом изначально лежит адрес выделенного исполняемого буфера.

Затем бэкдор загружает секции модуля в соответствии с их RVA (Relative Virtual Address). Данные секций хранятся в шелл-коде после заголовка, смещение к данным (section.raw_data_offset) отсчитывается от начала заголовка.

После секций программа обрабатывает релоки, которые хранятся в виде структур IMAGE_BASE_RELOCATION, однако каждый WORD, который отвечает за тип релока и смещение от начала блока, зашифрован. Начальный ключ берется из module_header.key, после каждой итерации он изменяется. Стоит отметить, что полученный после всех итераций ключ будет использоваться при обработке импортируемых функций.

Алгоритм обработки релоков:

import struct
def relocations(image_address, original_image_base, relocation_table_RVA):
    global key
    relocation_table_addr = image_address + relocation_table_RVA
    reloc_hdr_data = get_bytes(relocation_table_addr, 8)
    block_address, size_of_block = struct.unpack('<II', reloc_hdr_data)
    while size_of_block:
        if ((size_of_block - 8) >> 1) > 0:
            block = get_bytes(relocation_table_addr + 8, size_of_block - 8)
            i = 0
            while i < ((size_of_block - 8) >> 1):
                reloc = struct.unpack('<H', block[i*2:i*2+2])[0]
                reloc_type = ((reloc ^ key) & 0xFFFF) >> 0x0C
                offset = (reloc ^ key) & 0xFFF
                offset_high = (((key >> 0x10) + reloc) & 0xFFFFFFFF) | ((key << 0x10) & 0xFFFFFFFF)
                key = offset_high
                if reloc_type == 3:
                    patch_addr = offset + image_address + block_address
                    delta = (image_address - original_image_base) & 0xFFFFFFFF
                    value = get_wide_dword(patch_addr)
                    patch_dword(patch_addr, (value + delta) & 0xFFFFFFFF)
                elif reloc_type == 0x0A:
                    patch_addr = image_address + offset + + block_address
                    delta = (image_address - original_image_base) & 0xFFFFFFFF
                    old_low = get_wide_dword(patch_addr)
                    old_high = get_wide_dword(patch_addr + 4)
                    patch_dword(patch_addr, (old_low + offset) & 0xFFFFFFFF)
                    patch_dword(patch_addr + 4, (old_high + offset_high) & 0xFFFFFFFF)
                i += 1
        relocation_table_addr += size_of_block
        reloc_hdr_data = get_bytes(relocation_table_addr, 8)
        block_address, size_of_block = struct.unpack('<II', reloc_hdr_data)

После того как все релоки обработаны, структура заполняется нулями.

Далее BackDoor.ShadowPad.1 приступает к обработке импортируемых функций. В целом процедура соответствует стандартной, однако имена библиотек и функций зашифрованы. Используется ключ, модифицированный после обработки релоков, и также после каждой итерации шифрования он изменяется. После обработки очередной импортируемой функции ее адрес не помещается непосредственно в ячейку, заданную относительно IMAGE_IMPORT_DESCRIPTOR.FirstThunk. Вместо этого формируется блок инструкций, передающий управление на API вида:

mov eax, <addr>
neg eax
jmp eax

Алгоритм обработки импортов:

def imports(image_address, IAT_RVA,):
global key
IAT_address = image_address + IAT_RVA
import_table_address = image_address + 0x1A000
import_descriptor_address = IAT_address
while True:
    OriginalThunkData, TimeDateStamp, ForwarderChain, Name, FirstThunk = struct.unpack('<IIIII', get_bytes(import_descriptor_address, 0x14))
    TimeDateStamp = 0
    ForwarderChain = 0
    OriginalThunkData_address = image_address + OriginalThunkData
    FirstThunk_address = image_address + FirstThunk
    libname_address = image_address + Name
    n1 = get_wide_byte(libname_address)
    libname_decrypted = bytes([(n1 ^ key) & 0xFF])
    key = ((key >> 0x08) + c_byte(n1).value) | ((key << 0x18) & 0xFFFFFFFF)
    i = 1
    nb = get_wide_byte(libname_address + i)
    while libname_decrypted[-1]:
        libname_decrypted += bytes([(nb ^ key) & 0xFF])
        key = ((key >> 0x08) + c_byte(nb).value) | ((key << 0x18) & 0xFFFFFFFF)
        i += 1
        nb = get_wide_byte(libname_address + i)
    libname_decrypted = libname_decrypted[:-1]
    print("Imports from {0}".format(libname_decrypted[:-1]))
    thunk = get_wide_dword(OriginalThunkData_address)
    it_ptr = 0
    j = 0
    while thunk:
        name_address = image_address + thunk + 2
        nb1 = get_wide_byte(name_address)
        func_name = bytes([(nb1 ^ key) & 0xFF])
        key = ((key >> 0x08) + c_byte(nb1).value) | ((key << 0x18) & 0xFFFFFFFF)
        i = 1
        nb = get_wide_byte(name_address + i)
        while func_name[-1]:
            func_name += bytes([(nb ^ key) & 0xFF])
            key = ((key >> 0x08) + c_byte(nb).value) | ((key << 0x18) & 0xFFFFFFFF)
            i += 1
            nb = get_wide_byte(name_address + i)
        func_name = func_name[:-1]
        print("Function {0}".format(func_name))
        j_type = key % 5
        if j_type == 0:
            patch_byte(import_table_address, 0xE8)
        elif j_type == 1:
            patch_byte(import_table_address, 0xE9)
        elif j_type == 2:
            patch_byte(import_table_address, 0xFF)
        elif j_type == 3:
            patch_byte(import_table_address, 0x48)
        elif j_type == 4:
            patch_byte(import_table_address, 0x75)
        else:
            patch_byte(import_table_address, 0x00)
        import_table_address += 1
        patch_dword(FirstThunk_address + it_ptr, import_table_address) #addr to trampoline
        func_addr = binascii.crc32(func_name) & 0xFFFFFFFF
        patch_byte(import_table_address, 0xB8)
        patch_byte(import_table_address + 1, func_addr)
        patch_word(import_table_address + 5, 0xD8F7)
        patch_word(import_table_address + 7, 0xE0FF)
        import_table_address += 9
        j += 1
        it_ptr = j << 2
        thunk = get_wide_dword(OriginalThunkData_address + it_ptr)
    import_descriptor_address += 0x14
    if not get_wide_dword(import_descriptor_address):
        break

Таблица импортов также заполняется нулями после обработки.

Далее управление передается загруженному модулю. В качестве аргументов передаются:

  • адрес начала буфера, в который загружен модуль,
  • значение 1 (код),
  • указатель на структуру shellarg.

В точке входа загруженный модуль проверяет код, переданный от загрузчика:

screen BackDoor.ShadowPad.1 #drweb

  • 1 — выполнение основных функций,
  • 0x64, 0x65 — нет действия,
  • 0x66 — возвращает код 0x64 в 3 аргументе,
  • 0x67 — расшифровывает и возвращает строку Root (в дальнейшем Root — имя модуля),
  • 0x68 — возвращает в 3 аргументе указатель на таблицу функций, реализованных в данном модуле.

Алгоритм расшифровки строк:

def decrypt_str(addr):
key = get_wide_word(addr)
result = b""
i = 2
b = get_wide_byte(addr + i)
while i < 0xFFA:
    result += bytes([b ^ (key & 0xFF)])
    key = ((( key >> 0x10) * 0x1447208B) + (key * 0x208B0000) - 0x4875A15) & 0xFFFFFFFF
    i += 1
    b = get_wide_byte(addr + i)
    if not result[-1]:
        break
result = result[:-1]
return result

Стоит отметить, что содержащиеся в этом модуле фрагменты кода, а также некоторые объекты характерны для семейства бэкдоров BackDoor.PlugX.

При вызове с кодом 1 модуль переходит к выполнению основных функций. Вначале программа регистрирует обработчик исключений верхнего уровня. При получении управления обработчик формирует отладочную строку с информацией об исключении.

screen BackDoor.ShadowPad.1 #drweb

Затем программа выводит ее с помощью функции OutputDebugString, а также записывает ее в журнал, расположенный в %ALLUSERPROFILE%\error.log.

В бэкдорах семейства BackDoor.PlugX также регистрируются обработчики исключений. В частности, в BackDoor.PlugX.38 формируется строка с информацией об исключении, при этом незначительно отличается формат:

screen BackDoor.ShadowPad.1 #drweb

screen BackDoor.ShadowPad.1 #drweb

После регистрации обработчика формируется таблица вспомогательных функций, используемая для взаимодействия между модулями. Далее Root переходит к загрузке встроенных дополнительных модулей.

screen BackDoor.ShadowPad.1 #drweb

Каждый модуль хранится сжатым по алгоритму QuickLZ, а также зашифрованным. В начале модуль имеет заголовок размером 0x14 байт. На первом шаге заголовок расшифровывается. Алгоритм шифрования:

import struct
 
def LOBYTE(v):
    return v & 0x000000FF
  
def BYTE1(v):
    return (v & 0x0000FF00) >> 8
  
def BYTE2(v):
    return (v & 0x00FF0000) >> 16
  
def HIBYTE(v):
    return (v & 0xFF000000) >> 24
  
def decrypt_module(data, data_len, init_key):
    key = []
    for i in range(4):
        key.append(init_key)
    k = 0
    result = b""
    if data_len > 0:
        i = 0
        while i < data_len:
            if i & 3 == 0:
                t = key[0]
                key[0] = (0x9150017B - (t * 0xD45A840)) & 0xFFFFFFFF
            elif i & 3 == 1:
                t = key[1]
                key[1] = (0x95D6A3A8 - (t * 0x645EE710)) & 0xFFFFFFFF
            elif i & 3 == 2:
                t = key[2]
                key[2] = (0xD608D41B - (t * 0x1ED33670)) & 0xFFFFFFFF
            elif i & 3 == 3:
                t = key[3]
                key[3] = (0xD94925D3 - (t * 0x68208D35)) & 0xFFFFFFFF
            k = (k - LOBYTE(key[i & 3])) & 0xFF
            k = k ^ BYTE1(key[i & 3])
            k = (k - BYTE2(key[i & 3])) & 0xFF
            k = k ^ HIBYTE(key[i & 3])
            result += bytes([data[i] ^ k])
            i += 1
    return result

Начальное значения ключа шифрования хранится в заголовке модуля. Структура заголовка имеет следующий вид:

struct plugin_header
{
  DWORD key;
  DWORD flags;
  DWORD dword;
  DWORD compressed_len;
  DWORD decompressed_len;
};

После расшифровки заголовка бэкдор проверяет значение flags. Если в нем установлен флаг 0x8000, это означает, что модуль состоит из одного лишь заголовка. Затем проверяется значение нулевого бита первого байта расшифрованного блока. Если нулевой бит имеет значение 1, то это означает, что тело модуля упаковано алгоритмом QuickLZ.

После распаковки сверяет размеры получившихся данных со значениями в заголовке и переходит непосредственно к загрузке модуля. Для этого выделяет исполняемый буфер памяти, в который копирует функцию загрузки, затем передает на нее управление. Каждый модуль имеет тот же формат, что и модуль Root, то есть имеет собственный заголовок и зашифрованные импорты и релоки, поэтому загрузка происходит аналогичным образом. После того как модуль загружен, функция-загрузчик вызывает его точку входа с кодом 1. Каждый модуль, аналогично Root, инициализирует таблицу своих функций по этому коду. Затем Root вызывает точку входа загруженного модуля последовательно с кодами 0x64, 0x66, 0x68. Таким образом бэкдор инициализирует модуль и передает ему указатели на необходимые объекты.

Модули представляются объектами, объединенными в связный список. Обращение к конкретному модулю выполняется с помощью кода, который плагин помещает в свой объект после вызова его точки входа с к кодом 0x66.

struct loaded_module
{
  LIST_ENTRY list;
  DWORD run_count;
  DWORD timestamp;
  DWORD code_id;
  DWORD field_14;
  BOOL loaded;
  BOOL unk;
  BOOL module_is_PE;
  DWORD module_size;
  LPVOID module_base;
  Root_helper *func_tab; //указатель на таблицу функций модуля Root
}

При обращении к точке входа модуля с кодом 0x67 расшифровывается и возвращается строка, которую можно обозначить как имя модуля:

  • 1 — Plugins
  • 2 — Online
  • 3 — Config
  • 4 — Install
  • 5 — TCP
  • 6 — HTTP
  • 7 — UDP
  • 8 — DNS

Если перевести поля временной метки из заголовков каждого плагина в даты, то получаются корректные значения даты и времени:

  • Plugins — 2017-07-02 05:52:53
  • Online — 2017-07-02 05:53:08
  • Config — 2017-07-02 05:52:58
  • Install — 2017-07-02 05:53:30
  • TCP — 2017-07-02 05:51:36
  • HTTP — 2017-07-02 05:51:44
  • UDP — 2017-07-02 05:51:50
  • DNS — 2017-07-02 05:51:55

После загрузки всех модулей Root ищет в списке модуль Install и вызывает вторую из двух функций, размещенных в его таблице функций.

Install

В первую очередь бэкдор получает привилегии SeTcbPrivilege и SeDebugPrivilege. Затем получает конфигурацию с помощью модуля Config. Для обращения к функциям используются функции-переходники следующего типа:

screen BackDoor.ShadowPad.1 #drweb

Через объект, который хранит список загруженных модулей, по коду находится необходимый, затем через таблицу вызывается нужная функция.

При инициализации конфигурации на первом этапе проверяется буфер, хранящийся в модуле Root. Если первые четыре байта этого буфера равны X, это значит, что бэкдору необходимо сформировать конфигурацию по умолчанию. В ином случае данный буфер является закодированной конфигурацией. Конфигурация хранится в аналогичном плагинам виде — сжатая при помощи алгоритма QuickLZ и зашифрованная тем же алгоритмом, что и плагины. Под расшифрованную и распакованную конфигурацию резервируется 0x858 байт. Ее структуру можно представить следующим образом:

struct config
{
    WORD off_id; //lpBvQbt7iYZE2YcwN
    WORD offset_1; //Messenger
    WORD off_bin_path; //%ALLUSERSPROFILE%\Messenger\msmsgs.exe
    WORD off_svc_name; //Messenger
    WORD off_svc_display_name; //Messenger
    WORD off_svc_description; //Messenger
    WORD off_reg_key_install; //SOFTWARE\Microsoft\Windows\CurrentVersion\Run
    WORD off_reg_value_name;  //Messenger
    WORD off_inject_target_1; //%windir%\system32\svchost.exe
    WORD off_inject_target_2; //%windir%\system32\winlogon.exe
    WORD off_inject_target_3; //%windir%\system32\taskhost.exe
    WORD off_inject_target_4; //%windir%\system32\svchost.exe
    WORD off_srv_0; //HTTP://www.pneword.net:80
    WORD off_srv_1; //HTTP://www.pneword.net:443
    WORD off_srv_2; //HTTP://www.pneword.net:53
    WORD off_srv_3; //UDP://www.pneword.net:53
    WORD off_srv_4; //UDP://www.pneword.net:80
    WORD off_srv_5; //UDP://www.pneword.net:443
    WORD off_srv_6; //TCP://www.pneword.net:53
    WORD off_srv_7; //TCP://www.pneword.net:80
    WORD off_srv_8; //TCP://www.pneword.net:443
    WORD zero_2A;
    WORD zero_2C;
    WORD zero_2E;
    WORD zero_30;
    WORD zero_32;
    WORD zero_34;
    WORD zero_36;
    WORD off_proxy_1; //HTTP\n\n\n\n\n
    WORD off_proxy_2; //HTTP\n\n\n\n\n
    WORD off_proxy_3; //HTTP\n\n\n\n\n
    WORD off_proxy_4; //HTTP\n\n\n\n\n
    DWORD DNS_1; //8.8.8.8
    DWORD DNS_2; //8.8.8.8
    DWORD DNS_3; //8.8.8.8
    DWORD DNS_4; //8.8.8.8
    DWORD timeout_multiplier; //0x0A
    DWORD field_54; //zero
    //data
};

Поля с именами off_* содержат смещения к зашифрованным строкам от начала конфигурации. Алгоритм шифрования строк тот же, что используется для шифрования имен плагинов. После инициализации бэкдор также пытается получить конфигурацию из файла, расположенного в директории %ALLUSERSPROFILE%\<rnd1>\<rnd2>\<rnd3>\<rnd4>. Элементы пути и имя файла генерируются в процессе выполнения и зависят от серийного номера системного раздела.

После инициализации конфигурации проверяется параметр mode, хранящийся в структуре shellarg, которая заполняется загрузчиком (шелл-кодом) и хранится в модуле stage_1.

struct shellarg
{
    module_header *p_module_header;
    DWORD module_size;
    DWORD mode;
    DWORD unk;
}

Алгоритмом предусмотрен ряд возможных значений параметра mode2, 3, 4, 5, 6, 7. При значении, отличном от перечисленных, запускается установка бэкдора в систему, затем происходит переход к выполнению основных функций.

Ряд значений 2, 3 ,4 — переход к взаимодействию с сервером, минуя установку.

Ряд значений 5, 6 — работа с плагином, с кодом 0x6A, хранящимся в реестре.

Значение 7 — с помощью интерфейса IFileOperation исходный модуль копируется в %TEMP%, а также в System32 или SysWOW64, в зависимости от разрядности системы. Это необходимо для перезапуска бэкдора с обходом UAC с помощью файла wusa.exe.

Установка в систему

При установке бэкдор проверяет текущий путь исполняемого файла, сравнивая его со значением off_bin_path из конфигурации (%ALLUSERSPROFILE%\Messenger\msmsgs.exe). Если путь не совпадает и при этом бэкдор запущен впервые, то создается мьютекс, имя которого генерируется следующим образом:

screen BackDoor.ShadowPad.1 #drweb

Формат имени мьютекса для wsprintfWGlobal\%d%d%d.

Затем проверяет, включен ли контроль учетных записей UAC. Если контроль отключен, то бэкдор создает процесс control.exe (из System32 или SysWOW64, в зависимости от разрядности системы) с флагом CREATE_SUSPENDED. Затем с помощью WriteProcessMemory внедряет в него модуль Root. Перед этим бэкдор также внедряет функцию, которая загрузит модуль и передаст на него управление. Если же UAC включен, то этот этап пропускается.

Основной исполняемый файл (msmsgs.exe) и файл TosBtKbd.dll копируются в директорию, заданную в параметре off_bin_path и затем устанавливаются как служба. Имя службы, отображаемое имя и описание содержатся в конфигурации (параметры off_svc_name, off_svc_display_name, off_svc_description). В рассмотренном образце все три параметра имеют значение Messenger. Если создать службу не удалось, бэкдор прописывается в реестре. Ключ и имя параметра для данного случая также хранятся в конфигурации (параметры off_reg_key_install, off_reg_value_name).

После установки бэкдор пытается выполнить инжект модуля Root в один из процессов указанных в конфигурации (off_inject_target_<1..4>). В случае успеха текущий процесс завершается, а новый процесс (или служба) переходит к взаимодействию с управляющим сервером.

Для этого создается отдельный поток. После этого создается новый или открывается существующий ключ реестра, используемый в качестве виртуальной файловой системы вредоносной программы. Ключ располагается в ветке реестра Software\Microsoft\<key>, при этом значение <key> тоже генерируется в зависимости от серийного номера системного тома. Ключ также может располагаться в разделах HKLM и HKCU, в зависимости от привилегий процесса. Далее с помощью функции RegNotifyChangeKey отслеживаются изменения в этом ключе. Каждый параметр является сжатым и зашифрованным плагином. Бэкдор извлекает каждое значение и загружает его как модуль, добавляя в список к имеющимся.

screen BackDoor.ShadowPad.1 #drweb

Представленная функциональность выполняется в отдельном потоке.

На следующем шаге генерируется псевдослучайная последовательность длиной от 3 до 9 байтов, которая записывается в реестр в ключе SOFTWARE\, расположенном в разделах HKLM или HKCU. Имя параметра также генерируется и является уникальным для каждого компьютера. Это значение используется в качестве идентификатора зараженного устройства.

Далее бэкдор извлекает из конфигурации адрес первого управляющего сервера. Формат хранения серверов представлен следующим образом: <protocol>://<address>:<port>. Помимо значений, явно определяющих используемый протокол (HTTP, TCP, UDP), может также указываться значение URL. В этом случае бэкдор обращается по этому URL и в ответ получает новый адрес управляющего сервера, при этом используется алгоритм генерации домена (DGA). С помощью алгоритма генерируется строка:

wstr *__stdcall dga(wstr *p_wstr)
{
  unsigned int v1; // ecx
  unsigned int v2; // edi
  unsigned int v3; // esi
  unsigned int v4; // edx
  char v5; // dl
  wstr *v6; // eax
  wstr *v7; // esi
  wstr tmp_str; // [esp+10h] [ebp-34h] BYREF
  char generated_char_str[16]; // [esp+20h] [ebp-24h] BYREF
  struct _SYSTEMTIME SystemTime; // [esp+30h] [ebp-14h] BYREF
  GetSystemTime_0(&SystemTime);
  if ( SystemTime.wDay > 0xAu )
  {
    if ( SystemTime.wDay > 0x14u )
      v1 = 0xE52F65F3 * SystemTime.wYear - 0x2527D2DD * SystemTime.wMonth - 0x4BA7EAF5;
    else
      v1 = 0xF108D240 * SystemTime.wMonth - 0x78C6249D * SystemTime.wYear - 0x17AB943D;
  }
  else
  {
    v1 = 0xF5D6C030 * SystemTime.wMonth - 0x5FBD1755 * SystemTime.wYear - 0x5540E1B0;
  }
  v2 = 0;
  v3 = v1 % 7;
  do
  {
    v4 = v1 % 0x34;
    if ( v1 % 0x34 >= 0x1A )
      v5 = v4 + 39;
    else
      v5 = v4 + 97;
    v1 = 13 * v1 + 7;
    generated_char_str[v2++] = v5;
  }
  while ( v2 <= v3 + 7 );
  generated_char_str[v3 + 8] = 0;
  v6 = wstr::assign_char_str_pl2(&tmp_str, generated_char_str);
  v7 = (wstr *)wstr::init_by_wchar_pl2(p_wstr, (LPCWSTR)v6->buffer_wchar);
  wstr::clean_pl2(&tmp_str);
  return v7;
}

Полученная строка объединяется со строкой, хранимой в конфигурации, при этом используется часть до символа @. По полученному URL выполняется HTTP-запрос, в ответ на который приходит закодированный адрес управляющего сервера.

Затем создается объект соединения, соответствующий указанному для данного сервера протоколу.

TCP

При подключении по TCP имеется поддержка протоколов SOCKS4, SOCKS5 и HTTP-прокси. Вначале создается сокет и устанавливается соединение с сервером в режиме keep-alive. Для обмена с сервером используется пакет с заголовком следующего формата:

struct packet_header
{
    DWORD key;
    DWORD id;
    DWORD module_code;
    DWORD compressed_len;
    DWORD decompressed_len;
};

HTTP

При использовании протокола HTTP данные отправляются POST-запросом:

screen BackDoor.ShadowPad.1 #drweb

Передача данных по HTTP выполняется функцией-обработчиком в отдельном потоке. Механизм похож на таковой у BackDoor.PlugX.

Для разрешения адресов управляющих серверов используются DNS-серверы из конфигурации (в рассмотренном образце все 4 адреса - 8.8.8.8). Первый пакет, отправляемый на сервер, представляет собой последовательность нулей длиной от 0 до 0x3f байт. Длина выбирается случайным образом.

От сервера поступает ответ, который расшифровывается и распаковывается. Затем в заголовке пакета проверяется значение module_code, содержащее код плагина, для которого поступила команда. Бэкдор обращается к плагину, код которого указан в команде, и вызывает функцию обработки команд из его таблицы. Идентификатор самой команды содержится в поле id заголовка.

Pабота с плагинами

Идентификаторы команд для модуля Plugins могут иметь следующие значения id0x650000, 0x650001, 0x650002, 0x650003, 0x650004. По сути модуль Plugins является менеджером плагинов, позволяя регистрировать новые плагины и удалять имеющиеся.

ID Команды Описание
0x650003 Удаляет заданный плагин из хранилища в реестре.
0x650000 Отправляет информацию об имеющихся плагинах.
Значение Размер, байт
имя плагина перем., завершается 0
кол-во вызовов плагина 4
DateTimeStamp 4
код плагина 4
loaded_module.field_14 (unknown) 4
состояние (загружен или нет) 4
инициализирован 4
размер 4
базовый адрес 8
0x650001 В теле команды содержится новый плагин. Формат плагина такой же, как и у встроенных. Бэкдор упаковывает его алгоритмом QuickLZ, шифрует и сохраняет в хранилище в реестре, после чего приостанавливает текущий поток, чтобы поток обработки плагинов загрузил новый плагин из хранилища в реестре.
0x650002 В команде содержится имя DLL, которую бэкдор пытается загрузить, после чего последовательно вызывает ее точку входа с dwReason 0x64, 0x66, 0x68.
0x650004 В команде содержится код модуля. Если плагин с заданным кодом присутствует в списке, бэкдор деинициализирует его.

Online

Идентификаторы команд для плагина Online могут иметь значения 0x680002, 0x680003, 0x680004, 0x680005.

ID Команды Описание
0x680002 Запускает в отдельном потоке обработку команд для плагинов с инициализацией нового подключения к текущему серверу.
0x680003 Отправляет информацию о системе. Можно представить в виде структуры:
struct date
{
    BYTE year; //+0x30
    BYTE month;
    BYTE day;
    BYTE hour;
    BYTE minute;
    BYTE second;
    BYTE space;
}
  
struct sysinfo
{
    byte id[8];
    DWORD datestamp1; //20150810
    DWORD datestamp2; //20170330
    BYTE year; //+0x30
    BYTE month;
    BYTE day;
    BYTE hour;
    BYTE minute;
    BYTE second;
    BYTE space;
    DWORD module_code; //код модуля из команды
    WORD module_timestamp; //младшие 2 байта поля loaded_module.timestamp модуля подключения
    DWORD IP_address;
    LARGE_INTEGER total_physical_memory;
    DWORD cpu_0_MHZ;
    DWORD number_of_processors;
    DWORD dwOemID;
    LARGE_INTEGER total_disk_space[number_of_disks]; //перебирает все диски, начиная с C:
    DWORD pels_width; //ширина экрана в пикселях
    DWORD pels_height; //высота экрана в пикселях
    DWORD LCID;
    LARGE_INTEGER perfomance_frequency; //псевдослучайное значение, сгенерированное с помощью QueryPerformanceCounter и QueryPerformanceFrequency
    DWORD current_PID;
    DWORD os_version_major;
    DWORD os_version_minor;
    DWORD os_version_build_number;
    DWORD os_version_product_type;
    DWORD sm_Server_R2_build_number; //GetSystemMetrics(SM_SERVERR2)
    //строки ниже - null-terminated
    char hostname[x];
    char domain_name[x];
    char domain__username[x]; //разделены "/"
    char module_file_name[x];
    char osver_info_szCSDVersion[x];
    char str_from_config_offset1[x]; //Messenger
}

Значение id — уникальный идентификатор зараженного компьютера, хранимый в реестре.

Стоит заметить, что значения полей datestamp1 и datestamp2 зашиты и равны 20150810 и 20170330 соответственно. Подобные константы в виде дат использовались также в плагинах бэкдоров PlugX.

0x680004 Отправляет пакетом с телом случайной длины (от 0 до 0x1F байт). Тело пакета заполнено нулями.
0x680005 Отправляет пустой пакет (только заголовок) после чего 3 раза подряд вызывает Sleep(1000).

Config

Плагин для работы с конфигурацией.

ID Команды Описание
0x660000 Отправляет на сервер текущую конфигурацию.
0x660001 Получает и применяет новую конфигурацию.
0x660002 Удаляет файл с сохраненной конфигурацией.

Install

ID Команды Описание
0x670000 Выполняет установку бэкдора в качестве службы или устанавливает в реестр.
0x670001 Трижды вызывает Sleep(1000), после чего проверяет параметр shellarg.mode, если его значение равно 4, то завершает текущий процесс.

Артефакты

В исторической WHOIS-записи домена управляющего сервера можно увидеть электронный адрес регистратора: ddggcc@189[.]cn.

Этот же адрес находится в записях доменов icefirebest[.]com и www[.]arestc[.]net, которые содержались в конфигурациях образцов бэкдоров PlugX, установленных на том же компьютере.

Domain Name: ICEFIREBEST.COM
Registry Domain ID: 2042439159_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.1api.net
Registrar URL: http://www.1api.net
Updated Date: 2016-07-28T16:55:13Z
Creation Date: 2016-07-13T01:39:31Z
Registrar Registration Expiration Date: 2017-07-13T01:39:31Z
Registrar: 1API GmbH
Registrar IANA ID: 1387
Registrar Abuse Contact Email: abuse@1api.net
Registrar Abuse Contact Phone: +49.68416984x200
Domain Status: ok - http://www.icann.org/epp#OK
Registry Registrant ID:
Registrant Name: edward davis
Registrant Organization: Edward Davis
Registrant Street: Tianhe District Sports West Road 111
Registrant City: HONG KONG
Registrant State/Province: Hongkong
Registrant Postal Code: 510000
Registrant Country: HK
Registrant Phone: +86.2029171680
Registrant Phone Ext:
Registrant Fax: +86.2029171680
Registrant Fax Ext:
Registrant Email: ddggcc@189.cn
Registry Admin ID:
Admin Name: edward davis
Admin Organization: Edward Davis
Admin Street: Tianhe District Sports West Road 111
Admin City: HONG KONG
Admin State/Province: Hongkong
Admin Postal Code: 510000
Admin Country: HK
Admin Phone: +86.2029171680
Admin Phone Ext:
Admin Fax: +86.2029171680
Admin Fax Ext:
Admin Email: ddggcc@189.cn
Registry Tech ID:
Tech Name: edward davis
Tech Organization: Edward Davis
Tech Street: Tianhe District Sports West Road 111
Tech City: HONG KONG
Tech State/Province: Hongkong
Tech Postal Code: 510000
Tech Country: HK
Tech Phone: +86.2029171680
Tech Phone Ext:
Tech Fax: +86.2029171680
Tech Fax Ext:
Tech Email: ddggcc@189.cn
Name Server: ns1.ispapi.net 194.50.187.134
Name Server: ns2.ispapi.net 194.0.182.1
Name Server: ns3.ispapi.net 193.227.117.124
DNSSEC: unsigned
URL of the ICANN WHOIS Data Problem Reporting System:
http://wdprs[.]internic[.]net/
Domain Name: ARESTC.NET
Registry Domain ID: 2196389400_DOMAIN_NET-VRSN
Registrar WHOIS Server: whois.1api.net
Registrar URL: http://www.1api.net
Updated Date: 2017-12-06T08:43:04Z
Creation Date: 2017-12-06T08:43:04Z
Registrar Registration Expiration Date: 2018-12-06T08:43:04Z
Registrar: 1API GmbH
Registrar IANA ID: 1387
Registrar Abuse Contact Email: abuse@1api.net
Registrar Abuse Contact Phone: +49.68416984x200
Domain Status: ok - http://www.icann.org/epp#OK
Registry Registrant ID:
Registrant Name: li yiyi
Registrant Organization: li yiyi
Registrant Street: Tianhe District Sports West Road 111
Registrant City: GuangZhou
Registrant State/Province: Guangdong
Registrant Postal Code: 510000
Registrant Country: CN
Registrant Phone: +86.2029179999
Registrant Phone Ext:
Registrant Fax: +86.2029179999
Registrant Fax Ext:
Registrant Email: ddggcc@189.cn
Registry Admin ID:
Admin Name: li yiyi
Admin Organization: li yiyi
Admin Street: Tianhe District Sports West Road 111
Admin City: GuangZhou
Admin State/Province: Guangdong
Admin Postal Code: 510000
Admin Country: CN
Admin Phone: +86.2029179999
Admin Phone Ext:
Admin Fax: +86.2029179999
Admin Fax Ext:
Admin Email: ddggcc@189.cn
Registry Tech ID:
Tech Name: li yiyi
Tech Organization: li yiyi
Tech Street: Tianhe District Sports West Road 111
Tech City: GuangZhou
Tech State/Province: Guangdong
Tech Postal Code: 510000
Tech Country: CN
Tech Phone: +86.2029179999
Tech Phone Ext:
Tech Fax: +86.2029179999
Tech Fax Ext:
Tech Email: ddggcc@189.cn
Name Server: ns1.ispapi.net 194.50.187.134
Name Server: ns2.ispapi.net 194.0.182.1
Name Server: ns3.ispapi.net 193.227.117.124
DNSSEC: unsigned
URL of the ICANN WHOIS Data Problem Reporting System:
http://wdprs[.]internic[.]net/

Рекомендации по лечению

  1. В случае если операционная система способна загрузиться (в штатном режиме или режиме защиты от сбоев), скачайте лечащую утилиту Dr.Web CureIt! и выполните с ее помощью полную проверку вашего компьютера, а также используемых вами переносных носителей информации.
  2. Если загрузка операционной системы невозможна, измените настройки BIOS вашего компьютера, чтобы обеспечить возможность загрузки ПК с компакт-диска или USB-накопителя. Скачайте образ аварийного диска восстановления системы Dr.Web® LiveDisk или утилиту записи Dr.Web® LiveDisk на USB-накопитель, подготовьте соответствующий носитель. Загрузив компьютер с использованием данного носителя, выполните его полную проверку и лечение обнаруженных угроз.
Скачать Dr.Web

По серийному номеру

Выполните полную проверку системы с использованием Антивируса Dr.Web Light для macOS. Данный продукт можно загрузить с официального сайта Apple App Store.

На загруженной ОС выполните полную проверку всех дисковых разделов с использованием продукта Антивирус Dr.Web для Linux.

Скачать Dr.Web

По серийному номеру

  1. Если мобильное устройство функционирует в штатном режиме, загрузите и установите на него бесплатный антивирусный продукт Dr.Web для Android Light. Выполните полную проверку системы и используйте рекомендации по нейтрализации обнаруженных угроз.
  2. Если мобильное устройство заблокировано троянцем-вымогателем семейства Android.Locker (на экране отображается обвинение в нарушении закона, требование выплаты определенной денежной суммы или иное сообщение, мешающее нормальной работе с устройством), выполните следующие действия:
    • загрузите свой смартфон или планшет в безопасном режиме (в зависимости от версии операционной системы и особенностей конкретного мобильного устройства эта процедура может быть выполнена различными способами; обратитесь за уточнением к инструкции, поставляемой вместе с приобретенным аппаратом, или напрямую к его производителю);
    • после активации безопасного режима установите на зараженное устройство бесплатный антивирусный продукт Dr.Web для Android Light и произведите полную проверку системы, выполнив рекомендации по нейтрализации обнаруженных угроз;
    • выключите устройство и включите его в обычном режиме.

Подробнее о Dr.Web для Android

Демо бесплатно на 14 дней

Выдаётся при установке