Library
My library

+ Add to library

Contact us
24/7 Tech support | Rules regarding submitting

Send a message

Your tickets

Profile

BackDoor.PlugX.28

Added to the Dr.Web virus database: 2019-05-27

Virus description added:

Packer: absent

Compilation date: 16:43:21 02.02.2015

SHA1 hash:

  • f6bf976a2fdef5a5a44c60cbfb0c8fcbdc0bae02

Description

It is a multi-module backdoor written in C++ and designed to operate in 64-bit Microsoft Windows operating systems. Once installed by the loader, it operates in an infected computer’s RAM. It is used in targeted attacks on information systems for gaining unauthorized access to the data and for transferring it to C&C servers. Its key feature is utilizing plug-ins that contain the main backdoor’s functionality.

Operating routine

The trojan is loaded by BackDoor.PlugX.27. Calling conventions vary from function to function and are often non-standard: arguments are passed through arbitrary registers and / or via the stack, which may indicate the malicious program was compiled with an optimization.

Numerous objects are defined and used for the trojan’s operation. Abstract objects implement the data transmission interface and are used for data transferring. Thus, the function is not bound to the internal implementation of the connection object, whether it is a TCP socket, RAW socket, HTTP connection, or pipe. Object class can be determined in the code, as well as defined by the server type in the configuration or by data received from known servers.

Almost all strings of the trojan’s code are encrypted. Decryption algorithm:

import idaapi
import struct
 
def dec(d):
    s = ''
    k = struct.unpack('<I', d[:4])[0]
    d = d[4:]
    a = k ^ 0x13377BA
    b = k ^ 0x1B1
    for i in range(len(d)):
        a = (a + 4337) &&nbsp;0xffffffff
        b = (b - 28867) &&nbsp;0xffffffff
         
        a0 = (a &&nbsp;0x000000ff)
        a1 = (a &&nbsp;0x0000ff00) >> 8
        a2 = (a &&nbsp;0x00ff0000) >> 16
        a3 = (a &&nbsp;0xff000000) >> 24
        b0 = (b &&nbsp;0x000000ff)
        b1 = (b &&nbsp;0x0000ff00) >> 8
        b2 = (b &&nbsp;0x00ff0000) >> 16
        b3 = (b &&nbsp;0xff000000) >> 24       
                         
        s += chr(ord(d[i]) ^ (((b2 ^ (((b0 ^ (((a2 ^ ((a0 - a1)&0xff)) - a3)&0xff)) - b1)&0xff)) - b3) &&nbsp;0xff))
         
    return s
     
def decrypt(addr, size):
    d = ''
    for i in range(size):
        d += chr(idaapi.get_byte(addr + i))
     
    s = dec(d)
    print s
     
    for i in range(len(s)):
        idaapi.patch_byte(addr + i, ord(s[i]))
    idaapi.patch_dword(addr + i + 1, 0)

Preparing procedures

BackDoor.PlugX28 can obtain configuration by several ways. The loader passes the argument that is the pointer to the shellarg[/strings] structure:

#pragma pack(push,1)
struct st_data
{
  _DWORD size;
  _BYTE *data;
};
  
struct shellarg
{
  _DWORD shellcode_ep;
  _DWORD field_4;
  st_data* mod;
  _DWORD comp_size;
  st_data* cfg;
  _DWORD field_14;
  _DWORD op_mode;
};
#pragma pack(pop)

The trojan then checks the value pointed to by shellarg->cfg.

  • if first 8 bytes at this address equal XXXXXXXX, then the backdoor prepares so called basic configuration, which is used by default;
  • otherwise, backdoor uses decrypted and decompressed configuration, which is received from the loader.

This second option also involves checking the availability of the configuration file stored in the trojan’s working directory. The configuration’s filename, like many other filenames, is generated by the following algorithm:

int __usercall gen_string@<eax>(DWORD seed@<eax>, s *result, LPCWSTR base)
{
  DWORD v3; // edi
  DWORD v4; // eax
  signed int v5; // ecx
  signed int i; // edi
  DWORD v7; // eax
  WCHAR Buffer; // [esp+10h] [ebp-250h]
  __int16 v10; // [esp+16h] [ebp-24Ah]
  __int16 name[34]; // [esp+210h] [ebp-50h]
  DWORD FileSystemFlags; // [esp+254h] [ebp-Ch]
  DWORD MaximumComponentLength; // [esp+258h] [ebp-8h]
  DWORD serial; // [esp+25Ch] [ebp-4h]
  v3 = a1;
  GetSystemDirectoryW(&Buffer, 0x200u);
  v10 = 0;
  if ( GetVolumeInformationW(
         &Buffer,
         &Buffer,
         0x200u,
         &serial,
         &MaximumComponentLength,
         &FileSystemFlags,
         &Buffer,
         0x200u) )
  {
    v4 = 0;
  }
  else
  {
    v4 = GetLastError();
  }
  if ( v4 )
    serial = v3;
  else
    serial ^= v3;
  v5 = (serial & 0xF) + 3;
  for ( i = 0; i < v5; serial = 8 * (v7 - (serial >> 3) + 20140121) - ((v7 - (serial >> 3) + 20140121) >> 7) - 20140121 )
  {
    v7 = serial << 7;
    name[i++] = serial % 0x1A + 'a';
  }
  name[v5] = 0;
  string::wcopy(a2, base);
  string::wconcat(a2, (LPCWSTR)name);
  return 0;
}

The seed value for the configuration’s filename is 0x4358 ("CX").

To determine the paths (including working directory, the trojan can use the %AUTO% variable, which depending on the OS version, is converted to the following:

  • "<drive>:\\Documents and Settings\\All Users\\DRM" — for Windows 2000, Windows XP;
  • "<drive>:\\Documents and Settings\\All Users\\Application Data" — for Windows Server 2003;
  • "<drive>:\\ProgramData" — for later Windows versions.

With that, <drive> is executed from the Windows system directory.

The received configuration can be seen as the following ("st_config”) structure:

struct config_timestamp
{
  BYTE days;
  BYTE hours;
  BYTE minutes;
  BYTE seconds;
};
struct srv
{
  WORD type;
  WORD port;
  BYTE address[64];
};
struct proxy_info
{
  WORD type;
  WORD port;
  BYTE serv_addr_str[64];
  BYTE username_str[64];
  BYTE password[64];
};
struct st_config
{
  DWORD hide_service;
  DWORD gap_0[4];
  DWORD cleanup_files_flag;
  DWORD keylog_log_event;
  DWORD dword_0;
  DWORD skip_persistence;
  DWORD dword_1;
  DWORD sleep_timeout;
  config_timestamp timestamp;
  BYTE timetable[672];
  DWORD DNS_1;
  DWORD DNS_2;
  DWORD DNS_3;
  DWORD DNS_4;
  srv srv1_basic_type3;
  srv srv2_basic_type;
  srv srv3_basic_type_6;
  srv srv3_basic_type_7;
  srv srv5_basic_type_8;
  srv srv6_basic_type_5;
  srv srv7;
  srv srv8;
  srv srv9;
  srv srv10;
  srv srv11;
  srv srv12;
  srv srv13;
  srv srv14;
  srv srv15;
  srv srv16;
  BYTE url_1[128];
  BYTE url_2[128];
  BYTE url_3[128];
  BYTE url_4[128];
  BYTE url_5[128];
  BYTE url_6[128];
  BYTE url_7[128];
  BYTE url_8[128];
  BYTE url_9[128];
  BYTE url_10[128];
  BYTE url_11[128];
  BYTE url_12[128];
  BYTE url_13[128];
  BYTE url_14[128];
  BYTE url_15[128];
  BYTE url_16[128];
  proxy_info proxy_data_1;
  proxy_info proxy_data_2;
  proxy_info proxy_data_3;
  proxy_info proxy_data_4;
  DWORD persist_mode;
  DWORD env_var_AUTO_X[128];
  DWORD service_name[128];
  DWORD ServiceDisplayName[128];
  BYTE ServiceDescription[512];
  DWORD reg_predefined_key;
  BYTE reg_sub_key[512];
  BYTE reg_value_name[512];
  DWORD process_injection_flag;
  BYTE inject_target_dummy_proc_1[512];
  BYTE inject_target_dummy_proc_2[512];
  BYTE inject_target_dummy_proc_3[512];
  BYTE inject_target_dummy_proc_4[512];
  DWORD elevated_process_injection_flag;
  BYTE elevated_inject_target_dummy_proc_1[512];
  BYTE elevated_inject_target_dummy_proc_2[512];
  BYTE elevated_inject_target_dummy_proc_3[512];
  BYTE elevated_inject_target_dummy_proc_4[512];
  BYTE campaign_id[512];
  BYTE str_X_4[512];
  BYTE mutex_name[512];
  DWORD make_screenshot_flag;
  DWORD make_screenshot_time_interval;
  DWORD screen_scale_coefficient;
  DWORD bits_per_pixel;
  DWORD encoder_quality;
  DWORD screen_age;
  BYTE screenshots_path[512];
  DWORD subnet_scan_flag_mb;
  DWORD port_54D_1;
  DWORD raw_socket_subnet_flag;
  DWORD port_54D_2;
  DWORD type_7_subnet_flag;
  DWORD portl_54D_3;
  DWORD flag_1_6;
  DWORD port_54D_4;
  DWORD flag_1_7;
  DWORD first_IP_range_addr_beg;
  DWORD first_IP_range_addr_end;
  DWORD first_IP_range_addr_beg_2;
  DWORD first_IP_range_addr_beg_3;
  DWORD last_IP_range_addr_beg;
  DWORD last_IP_range_addr_end;
  DWORD last_IP_range_addr_beg_2;
  DWORD last_IP_range_addr_beg_3;
  BYTE mac_addr[6];
  BYTE gap_2[2];
} config;

When using default configuration, the values of certain fields are as follows:

  • trojan’s working directory: %AUTO%\\X;
  • service’s name: X;
  • service’s display name: X;
  • service’s description: X;
  • process name for the shellcode’s launch and injection: %windir%\\system32\\svchost.exe;
  • process name for launching with administrative privileges and shellcode injection: %windir%\\system32\\svchost.exe;
  • path for screenshot storage: %AUTO%\\XS;
  • mutex name: X;

Execution

The trojan obtains SeDebugPrivilege and SeTcbPrivilege privileges, then launches a dedicated thread for further activity.

It checks for the infected computer’s network adapter with hardcoded MAC address. If the adapter is present, the trojan shuts down (there is no specific address in the sample).

Trojan checks whether value exists. The list of possible values:

  • more than 4 — persistence control, normal operation afterwards;
  • 4 — WinInet.dll hooking and exit;
  • 3 — injection into Internet Explorer and exit;
  • 2 — normal operation without persistence control.

Persistence control (op_mode>4)

The trojan checks for the config.skip_persistence flag in the configuration. If the flag is set, the trojan skips the path checking, mutex creation and persistence control stages. Service initialization receives control.

The trojan then checks the current process’ working directory. If they match %AUTO%\\EHSrv.exe, malware skips installation stage.

It creates two Global\\<rndname> type mutex objects. The PID of the current process is a seed for the first mutex object’s name, while the PID of the parent process is a seed for the second mutex object’s name. After that, the trojan starts the installation process.

It checks the config.persist_mode parameter in the configuration, which determines the persistence mode:

  • 0, 1 — starting the service;
  • 2 — recording a value unto the registry.

In any case, the trojan copies its files — http_dll.dll and EHSrv.exe into the working directory (%AUTO%\\X by default) and saves the encrypted shellcode in the [HKLM\\SOFTWARE\\BINARY] 'ESETSrv’ and [HKLM\\SOFTWARE\\BINARY] 'ESETSrv’ registry keys. Malware spoofs the files’ time attributes by changing them to the ntdll.dll system file’s attributes.

To set itself as a service, the trojan creates and launches the SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS service with automatic startup. Its name, display name and the description are taken from the configuration (stored in the config.service_name, config.ServiceDisplayName, config.ServiceDescription). The lpBinaryPathName parameter of the CreateService function is set as <path>\EHSrv.exe -app.

To write itself into the registry, the trojan creates the <path>\EHSrv.exe -app registry value. The descriptor, key name and values are set in the configuration:

#drweb

The trojan then starts a new process.

This is followed by the StartServiceCtrlDispatcherW function call that initializes the service.

The config.elevated_process_injection_flag flag is checked in the configuration. If the flag is set, the trojan refers to the configuration for the extracting path to the executable file of the process that is used for shellcode injection. The name may contain environment variables. There are four names and each of them are sequentially checked up to the first non-zero value. Then the trojan creates a process with the CREATE_SUSPENDED flag in which the shellcode is injected.Upon successful injection, the process shuts down.

#drweb

In case of failure, the trojan transfers control to the main functionality.

"Wininet.dll" hooking (op_mode==4)

Presumably, this mode is provided after the trojan is injected into the Internet Explorer process.

The following functions are hooked:

HttpSendRequestA
HttpSendRequestW
HttpSendRequestExA
HttpSendRequestExW

Their purpose is to intercept HTTP requests to extract usernames and passwords for further connecting to the proxy server. Received information is recorded in the following structure:

struct proxy_info
{
  WORD type;
  WORD port;
  BYTE serv_addr_str[64];
  BYTE username_str[64];
  BYTE password[64];
};

where type parameter may take the following values:

  • 1 — socks4
  • 2 — socks5
  • 3 — http
  • 5 — https
  • 6 — ftp

In the form of this structure the data is stored both in a global variable and within a file in the backdoor’s working directory. The file’s name is generated with the 0x485A (“HZ”) seed.

Injection into the IE process (op_mode==3)

BackDoor.PlugX28 injects the shellcode into the IE process by CreateRemoteThread function. The trojan searches for IEFrame window and uses its handle to get the PID. This is preceded by initialization of the backdoor plug-ins. \\.\PIPE\<rndname> pipe name is generated. The current PID process serves as a seed for <rndname>. The configuration is then re-initialized.

First, an object is created that implements the interface for asynchronous interaction with the pipe. Then the pipe is created and initialized. A handler is created in a separate thread. It receives a pointer to the pipe connection object as a parameter. The handler receives commands through the object interface, which are executed by plug-ins. The results are returned to the pipe.

Main functionality (op_mode==2 or op_mode==4 after achieving persistence)

The trojan checks for the current users’ administrative privileges. Then it checks the config.hide_service flag in the configuration. If the flag is set and the user is not the local administrator, the trojan then searches for %WINDIR%\SYSTEM32\SERVICES.EXE among the running processes. The trojan refers to the first module in the list, reads the first section address and copies this section into its buffer. Then it searches through the buffer for a sequence of instructions that can be represented as the following regular expression:

\xA3.{4}\xA3.{4}\xA3.{4}\xA3.{4}\xE8

This matches the sequence in the ScInitDatabase() function.

#drweb

After that, the trojan reads ServiceDatabase address, which is a linked list of structures describing running services. Then it searches for the record that corresponds to the backdoor’s service name and “deletes” it by changing the pointers of the previous and following record in the list.

After hiding the service, the trojan creates a mutex object. Its name is determined in the config.mutex_name parameter of the configuration.

Then the malware creates a RAW socket for sniffing all localhost IP packets. The trojan separates TCP packets from all incoming ones and then checks them for compliance with SOCKS4, SOCKS5, and HTTP packets. It then extracts the proxy server addresses from these packets and forms proxy_info structures, which are saved as a file like the trojan does with the Wininet algorithm.

The config.elevated_process_injection_flag flag is checked in the configuration. If the flag is set, a thread starts in which running processes are equentially parsed to find one running as a local administrator. Trojan copies access token of found process and assigns HighIntegrity class to token’s copy. Then the malware creates a process environment block as a local administrator that is used to create a process with the HighIntegrity class access token. The process name is also extracted from the config.elevated_inject_target_dummy_proc_<n>", n 1..4 parameter of the configuration. All four options are parsed until the first non-zero value. The trojan creates a process with the CREATE_SUSPENDED flag and injects shellcode into it. The information about each process is stored in a special structure:

struct injected_proc
{
  DWORD session_ID;
  DWORD pid;
  DWORD hProcess;
  BYTE admin_account_name[40];
};
 
struct injected_elevated__procs
{
  injected_proc injected_process_info[32];
  DWORD hThread;
  DWORD hEvent;
};

Then the plug-ins are initialized and the backdoor becomes ready to receive and process commands from the C&C server. Before connecting to the C&C server, the proxy global settings, which are used by the WIninet functions and recorded in Firefox configuration, are extracted and saved.

It is worth noting that the server addresses are stored in the configuration as structures:

struct srv
{
  WORD type;
  WORD port;
  BYTE address[64];
};

For interaction with the server, the trojan creates an object whose type is defined by the value of srv.type. Possible types of connections:

1, 2 — pipe connection;
3 — TCP socket (usage of SOCKS4, SOCKS5, HTTP proxies is implied);
4 — HTTP connection;
5 — opening of UDP socket for sniffing, operation in DNS mode;
6, 7, 8 — RAW socket.

Supported protocols allow either the remote computer or the other process using pipe to take over server functions.

The first attempt to connect to the C&C server from the configurations is made without using a proxy. In case of failure, proxy data stored in a global variable is used. The configuration provides slots for up to 16 servers. If none of them are available, the URL is extracted from the config.url_1 field. That URL is first parsed into components (such as host, URI, and parameters), and then a GET request based on this data is generated and sent. The trojan searches for encrypted string enclosed between the DZKS and DZJS tags in the response message body. After decoding, the string represents the type, port, and address of the C&C server in the form of the srv structure. There are up to 16 such URL pointers that can be used to get the new address of the C&C server.

The C&C server’s address decoding algorithm:

int __usercall find_and_decode_string@(BYTE *decoded_response@, BYTE *response_data@, int response_data_len@)
{
  int v3; // edx
  int i; // ecx
  int v6; // esi
  int j; // edi
  int v8; // ecx
  char v9; // dl
  BYTE *v10; // edx
  int v11; // eax
  int v12; // esi
  v3 = response_data_len - 4;
  for ( i = 0; i < v3; ++i )
  {
    if ( response_data[i] == 'D'
      && response_data[i + 1] == 'Z'
      && response_data[i + 2] == 'K'
      && response_data[i + 3] == 'S' )
    {
      break;
    }
  }
  if ( i >= v3 )
    return 1168;
  v6 = i + 4;
  for ( j = i + 4;
        j < v3
     && (response_data[j] != 'D'
      || response_data[j + 1] != 'Z'
      || response_data[j + 2] != 'J'
      || response_data[j + 3] != 'S');
        ++j )
  {
    ;
  }
  if ( j > v3 )
    return 1168;
  v8 = 0;
  while ( v6 < j )
  {
    v9 = response_data[v6] + 16 * (response_data[v6 + 1] - 65);
    response_data[v8 + 1] = 0;
    response_data[v8++] = v9 - 65;
    v6 += 2;
  }
  *(_WORD *)decoded_response = *response_data + (response_data[1] << 8);
  *((_WORD *)decoded_response + 1) = response_data[2] + (response_data[3] << 8);
  if ( v8 > 0 )
  {
    v10 = decoded_response + 4;
    v11 = response_data - decoded_response;
    v12 = v8;
    do
    {
      *v10 = v10[v11];
      ++v10;
      --v12;
    }
    while ( v12 );
  }
  return 0;
}

Initial connection to C&C server

BackDoor.PlugX28 gets the current time and date via the GetLocalTime function. If it is Sunday (0), it changes it to Saturday (6) in the SYSTEMTIME structure. In other cases, it reduces the value by 1. The trojan refers to the config.timetable array to check the value of the element under the index that depends on the current time. The array’s size is _BYTE[672]. Each element represents a flag of each quarter hour in a week (24 * 7 * 4 = 672). If the element value is non-zero, execution continues; otherwise the trojan goes into standby mode.

Checking the work schedule flag:

while ( 1 )
  {
    GetLocalTime(&local_time);
    if ( local_time.wDayOfWeek )
      --local_time.wDayOfWeek;
    else
      local_time.wDayOfWeek = 6;
    if ( config.timetable[4 * (local_time.wHour + 24 * local_time.wDayOfWeek) + local_time.wMinute / 15] )
      break;
    Sleep(1000);
  }

In the sample configuration, all array elements are equal to 1. When preparing the default configuration, the array is also filled in with ones (1). After checking the schedule, the trojan reads the value of the config.timestamp field, defined as follows:

struct config_timestamp
{
  BYTE days;
  BYTE hours;
  BYTE minutes;
  BYTE seconds;
};

Then it converts the field’s value into seconds, multiplies by 0x10000000, and adds them with the current system time in FILETIME format. The trojan checks the availability of the <config.service_name> parameter in the HKCU\Software\<config.service_name> registry key. If the parameter exists, it compares its value with the system timestamp. If the timestamp’s value is greater than the stored value, execution continues. Otherwise, the trojan goes standby mode for one second before rechecking. If the parameter’s value does not exist, the calculated timestamp is placed into this parameter and compared with the system timestamp. As a result, standby mode remains active until the system timestamp is larger than the timestamp calculated at the beginning of the check, or larger than the timestamp stored in the parameter.

#drweb

result_ts is placed in the registry if necessary.

Multiplication of timestamp values is shown in the illustration:

#drweb

After timing checks, the malware creates a connection object that matches the type of connection specified for the current server. If HTTP protocol is used to communicate with the C&C server, connection processing (receiving and transmitting data) is performed in a separate thread. The first stage implies establishing a connection in a keep-alive mode and sending the first GET request. The URL is formed using the /%p%p%p format from three random DWORD values. Then the following structure is prepared:

struct prefix
{
  DWORD unknown;
  DWORD sync_ctr;
  DWORD conn_state;
  DWORD available_buffer_size;
};

This structure is only used when transmitting over HTTP protocol and performs the service function of syncing and maintaining the connection. When establishing a connection, the structure fields are filled in with the following values from the connection object’s internal fields:

  • unknown = 0;
  • sync_ctr = 1 — a counter that increases by one every sending;
  • conn_state = 20130923 — represents the connection status flag. In this case, the initial value 20130923 is used by the client-side to make a connection request;
  • available_buffer_size = 0xF010 — the initial size of the object's internal buffer for storing incoming data.

This structure is encrypted with the same algorithm used for string encryption. The output structure looks as follows:

struct http_encrypted_data
{
  DWORD key;
  BYTE  data[0x10];
}

After encryption the data is encoded in Base64 and placed in the Cookie: header, then the request is sent to the C&C server. The response contains the http_encrypted_data structure. Once decrypted, it transforms into the prefix structure. The trojan checks the prefix. conn_state value that should be equal to 20130924. This value may indicate that the server is ready to receive data. Malware authors also implied the 20130926 value that indicated the end of the connection.

Then the prefix.sync_ctr field is checked. Its value must be greater by 1 than the prefix.sync_ctr value that is sent by the client-side. This form of interaction between server and client-side is also used when sending real data. They are placed after the prefix structure.

After the connection to the server is established, a command request is prepared. To do so, the trojan generates random bytes from 0 to 0x1F and forms the structure of the packet from the header and the body.

struct packet_hdr
{
  DWORD key;
 DWORD command_id;
 DWORD len;
 DWORD errc;
};
struct packet
{
  packet_hdr header;
  BYTE data[61440] //0xF000;
};

This structure is used for sending data to the server and processing commands. The values of the (“packet_hdr”) header fields:

  • “key” — a key used for data encryption;
  • “command_id” — an ID for command or command response. The ID does not change during the response;
  • "len" — data length excluding header;
  • "errc" — error code of command execution. In most cases this field contains the (GetLastError) error code if a command could not be fully executed, or contains 0 if a command is successfully executed. In some cases, it contains additional parameters for the client-side to execute the command.

During first sent, command_id and errc values are equal to 0, and the len value is equal to the length of the random sequence (0-0x1F). packet.data contains the random sequence itself. Then the data in the ("data") packet is compressed by the LZNT1 algorithm via the RtlCompressBuffer and encrypted by a string encryption algorithm with a random key. The packet.header.len field contains the (uncompressed_len << 0x10) | compressed_len value, where uncompressed_len and compressed_len contain the data size before and after compression, respectively (without regard to the header length). Then the header is being encrypted, and a random key is placed in the packet.header.key field.

The received encrypted data is then sent to the server in the Cookie: field of the HTTP request. The prefix structure is placed before the data and the entire received sequence is encrypted. Then it is encoded using Base64 and sent in a request. The response is a command from the server. A packet with a command represents a structure similar to packet, but the format of data and; in some cases, the purpose of header.errc may change depending on the command.

Processing the C&C server’s commands

After receiving the packet, it is decrypted and unpacked. The trojan checks the value of the packet.header.command_id command ID. There are following command values:

  • 1 — collecting and sending system information;
  • 3 — operating with plug-ins;
  • 4 — connection reset;
  • 5 — self-deleting;
  • 6 — sending current configuration to the C&C server;
  • 7 — receiving new configuration;
  • 8 — sending information about processes with injected shellcode;
  • 2, 9, 10 — no actions provided;
  • >10 — operating with plug-ins;

The packet.header.command_id field of the received responses is set to the same value as received in the command.

Command 1 (system information)

The trojan compares the string in the packet.data field with the string from the config.campaign_id configuration (TEST in the default configuration). If the strings are equal, it proceeds with gathering system information, otherwise an error occurs. After that, the trojan attempts to read a file with the name generated with the 0x4343 ("CC”) seed from the working directory. If the file exists, its contents are read and encoded.

#drweb

If the file does not exist, one is created and a sequence of 8 random bytes is written to it. Then this random sequence is encoded in the same way. The resulting encoded string will be used as a response to the command. The program then collects the following information:

  • Computer name;
  • Username;
  • CPU frequency (from HKLM\HARDWARE\DESCRIPTION\SYSTEM\CENTRALPROCESSOR\0);
  • If the process is running under WoW64;
  • Domain information;
  • If the current user has local administrative privileges;
  • IP address;
  • RAM amount in kilobytes;
  • OS version;
  • Current time;
  • Screen resolution;
  • Locale settings;
  • Number of processors.

The response with the results is sent to the C&C server as a structure:

struct command_1_response
{
  packet_hdr header;
  sysinfo data;
};

where sysinfo is a structure carrying system information:

struct sysinfo
{
  DWORD date_stamp; //20150202
  DWORD zero_0;
  DWORD self_IP;
  DWORD total_PhysMem;
  DWORD cpu_MHz;
  DWORD screen_width;
  DWORD screen_height;
  DWORD winserv2003_build_num;
  DWORD default_LCID;
  DWORD tick_count;
  DWORD systeminfo_processor_architecture;
  DWORD systeminfo_number_of_processors;
  DWORD systeminfo_processor_type;
  DWORD zero_1;
  DWORD os_MajorVersion;
  DWORD os_MinorVersion;
  DWORD os_BuildNumber;
  DWORD os_PlatformId;
  WORD os_ServicePackMajor;
  WORD os_ServicePackMinor;
  WORD os_SuiteMask;
  WORD os_ProductType;
  DWORD isWow64Process;
  DWORD if_domain;
  DWORD if_admin;
  DWORD process_run_as_admin;
  WORD systime_Year;
  WORD systime_Month;
  WORD systime_Day;
  WORD systime_Hour;
  WORD systime_Minute;
  WORD systime_Second;
  DWORD server_type;
  WORD off_CCseed_file_data;  //offset from 0
  WORD off_compname_string; 
  WORD off_username_string;
  WORD off_verinfo_szCSDVersion;
  WORD off_str_X_4_from_config;
  BYTE string_CCseed_file_data[16];
  .......
  //strings
};

off_CCseed_file_data", "off_compname_string", "off_username_string", "off_verinfo_szCSDVersion", "off_str_X_4_from_config" structure members are offsets relative to the beginning of the sysinfo structure. off_str_X_4_from_config is offset to the string copied from config.str_x_4 (x in the default configuration). Then trojan prepares a packet to send the information to the C&C server. The header contains the packet ID that is equal to 1. Then the packet is compressed, encrypted, and sent to the server.

command_id == 3 (operating with plug-ins)

When a packet with command_id 3 is received, a task handler for plug-ins is launched in a separate thread and a new connection to the C&C server is created. The incoming packet with the command looks like this:

struct command_3_packet
{
  packet_hdr header;
  DWORD dword_0;
  DWORD index;
};

If the value of index is equal to 0xFFFFFFFF, task processing for plug-ins is performed in the same process. Otherwise, this value is used as an index in the array of the injected_elevated_procs structure. The required structure is obtained from the array by the specified index. Then the process ID is extracted from it, which serves as a seed for generating the pipe name. The trojan creates the pipe connection object that implements the command forwarding interface for plug-ins. These commands will be executed within another process (for example, Internet Explorer), which will be injected in case of "shellarg.op_mode" == 3, or within one of the processes specified in the configuration and run with elevated privileges ("config.elevated_inject_target_dummy_proc_<n>", n 1..4). After pipe initialization, a response is sent to the server, which represents the same packet as the command does. After that, packets containing plug-in tasks are sent between two objects — the HTTP connection and the pipe.

If the value of index is set as 0xFFFFFFFF, the received packet is sent back, and the task processing loop for plug-ins begins.

command_id == 4 — connection reset; No special actions are performed; the trojan exits the command processing cycle to connect to other servers.

command_id == 5 — self-deleting. It deletes its service’s key from the registry and deletes all files from its working directory.

command_id == 6 — sending current configuration to the C&C server; It encrypts the current configuration and sends it in the packet body.

command_id == 7 — receiving new configuration. The packet body contains the new configuration. The trojan compresses it, encrypts and saves it as a file; the filename is generated with the 0x4358 ("CX”) seed. Then it reads it and replaces the old configuration.

command_id == 8 — sending information about processes with injections. It prepares a packet with information about the processes in which the shellcode was injected, then encrypts it and sends it to the C&C server. The packet structure is as follows:

struct command_8_response
{
  packet_hdr header;
  DWORD number_of_procs;
  injected_proc injected_processes_info[number_of_procs];
};

command_id >10 — operating with plug-ins. In contrast to the "command_id" == 3 mode, in this case, it is intended to work only within the current process.

Operating with plug-ins

After the trojan receives a command with id 3 or >10 and the received packet is sent back, the C&C server responds with a packet containing a task for a plug-in. The command for the plug-in is processed separately from the main command processing cycle as well as in a separate connection.

BackDoor.PlugX28 operates with the following plug-ins:

  • DISK (2 types);
  • Keylogger;
  • Nethood;
  • Netstat;
  • Option;
  • PortMap;
  • Process;
  • Regedit;
  • Screen;
  • Service;
  • Shell;
  • SQL;
  • Telnet.

The plug-ins’ names are encrypted and used when the corresponding objects are being initialized.

Each plug-in is represented by the pluginfo object:

struct pluginfo
{
  wchar_t name[64];
  DWORD timestamp;
  PROC pfnInit;
  PROC pfnJob;
  PROC pfnFree;
};

timestamp for all plug-ins is 20130707.

Plug-ins’ objects are merged into a global object that provides access to plug-in functions.

During initialization, the pluginfo.pfnInit functions are called sequentially for each plug-in. Initialization creates an auxiliary function table. Beyond that, some additional actions are performed for the Keylogger and Screen plug-ins.

"Keylogger” initialization

After initializing the auxiliary function table, the trojan creates a separate thread for the pluginfo.pfnJob function, which inserts the hook of the WH_KEYBOARD_LL type. The filename for the event log is generated with the 0x4B4C ("KL”) seed. Time file attributes are spoofed after each entry. The log entry line has the following format:

<yyyy-mm-dd hh:mm:ss> <username> <process_path> <window_title> <event>

Entries to the event log are written sequentially. Each entry has the following format:

struct keylog_rec
{
  DWORD recsize;
  BYTE encdata[recsize];
};

"Screen” initialization

During the initialization of the Screen plug-in, the screenshot creation function is started in a separate thread. First, the gdiplus.dll library is initialized in the thread, then the config.make_screenshot_flag flag is checked in the configuration. If the flag is not set, the stream goes into standby mode, periodically checking the flag. If this flag is set, the config.screen_age value is extracted from the configuration, which sets the maximum storage period for screenshots in days. Thus, all JPEG files whose creation dates are less than the specified date are recursively deleted from the config.screenshots_path directory (%AUTO>%\\XS in the default configuration. Cleaning occurs once a day. Next, a screenshot is created, encoded in JPEG format, and saved to the <config.screenshots_path>\<username>\<screen_filename>.jpg directory. The filename for the created screenshot is written in < YYYY-MM-DD HH:MI:SS > format.

JPEG encoding settings are set in the configuration in the "config.screen_scale_coefficient", "config.encoder_quality", "config.bits_per_pixel” parameters.

Each plug-in has a separate set of command_id. When responding to a command, the same command_id is inserted into the header. The body of the packet contains strings; the offset is specified explicitly, and is counted from the beginning of the packet body. With that, the packet_hdr header is skipped.

DISK plug-in

command_id for the DISK plug-in has the 0x300X, X - 0,1,2,4,7,0xA,0xC,0xD,0xE format.

Command ID Description Input Output
0x3000 Collects information about logical drives with the A-Z drive letters, fills in an array of structures disk_info, and sends it to the C&C server. -
struct disk_info
  {
    int drive_type;
    LARGE_INTEGER total_bytes;
    LARGE_INTEGER free_bytes_available;
    LARGE_INTEGER free_bytes;
    WORD off_volume_name;
    WORD off_filesystem_name;
  }
  struct command_3000h_response
  {
    packet_hdr header;
    disk_info info[26]'
  };
0x3001 Generates a list of files and subdirectories in the specified directory, which is specified in the target_dir command parameter; sends a separate packet for each file.
struct command_3001h_request
  {
    packet_hdr header;
    BYTE target_dir[];
  };
  
struct command_3001h_response
  {
    packet_hdr header;
    BOOL has_subdir; //if is dir
    DWORD file_attributes;
    DWORD filesize_high;
    DWORD filesize_low;
    FILETIME creation_time;
    FILETIME last_access_time;
    FILETIME last_write_time;
    WORD off_file_name;
    WORD off_alternate_file_name;
    ...
    //strings
  };
  
0x3002 Generates a list of files from the directory specified in the target_dir command parameter. Filenames are set by a mask that can use the ? and * symbols to replace one or more of any symbols; sends a separate packet for each file.
struct command_3002h_request
{
  packet_hdr header;
  WORD off_target_dir;
  WORD off_filename_mask;
  ...
  //target_dir,filename_mask
};
struct command_3002h_response
{
  packet_hdr header;
  DWORD file_attributes;
  DWORD file_size_high;
  DWORD file_size_low;
  FILETIME creation_time;
  FILETIME last_access_time;
  FILETIME last_write_time;
  WORD target_path_offset;
  WORD file_name_offset;
  WORD alternate_file_name_offset;
}; 
0x3004 Reads the requested file in blocks by 0x1000 bytes with the specified offset from the beginning of the file. The filename and offset are defined in the command. First sends information about the file (time attributes, file size) with the value of the command_id field equal to 0x3004 in the response header, then starts reading the file and sends blocks with "command_id"==0x3005. Blocks of the file’s data are placed in the packet body. When completed, it sends a zero-length packet with 0x3005 in the header.
struct command_3004h_request
{
  packet_hdr header;
  BYTE pad_0[28];
  DWORD file_pointer_offset_low;
  DWORD file_pointer_offset_high;
  BYTE pad_1[8];
  BYTE target_file_name[];
};
struct command_3004h_response
{
  packet_hdr header;
  FILETIME creation_time;
  FILETIME last_access_time;
  FILETIME last_write_time;
  DWORD dword_0;
  DWORD returned_file_pointer;
  DWORD file_pointer_offset_high;
  DWORD file_size_low;
  DWORD file_size_high;
  WORD target_file_name_beg;
};
0x3007 Creates a new file or opens an existing one from the end of the file for writing. Writes data to it starting from the specified offset. Spoofs time attributes. The command with "command_id" 0x3007 specifies the file name and the offset, while the command with command_id 0x3008 specifies the write buffer.
struct command_3007h_request
{
  packet_hdr header;
  FILETIME creation_time;
  FILETIME last_access_time;
  FILETIME last_write_time;
  DWORD dword_0;
  DWORD file_pointer_offset_low;
  DWORD file_pointer_offset_high;
  DWORD dword_1;
  DWORD dword_2;
  BYTE target_file_path[];
}; 
-
0x300A Creates a folder whose path is specified in the packet body. Responds with a zero-length packet and "command_id" == 0x300A. - -
0x300C Creates a process using the command line transmitted in the command body. With that, if the "errc" field value is non-zero in the packet header, it creates the HH desktop and uses it in the STARTUP_INFO of the created process. As a response it returns PROCESS_INFORMATION of the created process.
struct command_300Сh_request
{
  packet_hdr header;
  BYTE cmdline[]
};
struct command_300Сh_response
{
  packet_hdr header;
  PROCESS_INFORMATION proc_info;
};
0x300D Executes the SHFileOperationW function with the parameters specified in the command. Responds with a zero-length packet.
struct c2_command_300Dh_disk_srv2cli
{
  packet_hdr header;
  DWORD FO_wFunc;
  WORD FOF_flags;
  WORD word_0;
  WORD source_file_name_offset;
  WORD dest_file_name_offset;
  ...
  //strings
;
-
0x300E Expands the environment variable and sends the result to the server. The variable is contained in the command body, and the result is contained in the response body. - -

DISK (2) Plug-in

The second plug-in is also called DISK, but it does not relate to logical drives. There are the following commands: 0xF010, 0xF011, 0xF012, 0xF013. 0xF010, 0xF011, 0xF012, 0xF013.

In the command trojan receives the srv structure, according to which it creates a connection object and starts relaying packets from one connection to the newly created one.

KeyLogger Plug-in

There is a 0xE000 command. The trojan reads the plug-in event log file, then sends it to the C&C server in the response body.

Nethood Plug-in

The plug-in is used to operate in the network environment.

Command ID Description Input Output
0xA000 Lists all available network resources. For each resource it fills the structure and then sends it to the C&C server. The command contains parameters of the NETRESOURCE structure used as an argument when calling the WNetOpenEnumW function.
struct command_A000h_request
{
  packet_hdr header;
  WORD netres_scope;
  WORD netres_type;
  WORD netres_display_type;
  WORD netres_usage;
  WORD off_netres_localname;
  WORD off_netres_remotename;
  WORD off_etres_comment;
  WORD off_netres_provider;
};
struct command_A000h_response
{
  packet_hdr header;
  WORD netres_scope;
  WORD netres_type;
  WORD netres_display_type;
  WORD netres_usage;
  WORD off_netres_localname;
  WORD off_netres_remotename;
  WORD off_etres_comment;
  WORD off_netres_provider;
  BYTE res_comment_str[1000];
  NETRESOURCEW net_res_struct;
};
0xA001 Disables the network resource specified in the command with the Force flag, then reconnects it. Responds with a zero-length packet.
struct command_A001h_request
{
  packet_hdr header;
  DWORD netres_scope;
  DWORD netres_type;
  DWORD netres_display_type;
  DWORD netres_usage;
  WORD netres_localname_offset;
  WORD netres_remotename_offset;
  WORD netres_comment_offset;
  WORD netres_provider_offset;
  WORD add_conn_username;
  WORD add_conn_password_offset;
  DWORD add_conn_flags;
  ...
  //strings
};
-

Netstat Plug-in

The plug-in collects and sends information about network connections.

Command ID Description Input Output
0xD000 Collects and sends information about TCP connections. Depending on the OS version, it calls one of the functions to get connection information: AllocateAndGetTcpExTableFromStack (Windows XP); GetTcpTable (Windows 2000); GetExtendedTcpTable (Windows Vista-Windows 7). -
struct command_D000h_response
{
  packet_hdr header;
  DWORD conn_state;
  DWORD local_addr;
  DWORD local_port;
  DWORD remote_addr;
  DWORD remote_port;
  DWORD owner_pid;
  BYTE proc_name[];
};
0xD001 Collects information about UDP connections. It is similar to the previous command. -
struct udp_listener_table
{
  DWORD local_addr;
  DWORD local_port;
  DWORD owner_port;
};
struct command_D001h_response
{
  packet_hdr header;
  udp_listener_table udp_tab;
  BYTE proc_name[];
};
0xD002 Changes the state of the TCP connection. The command body contains an argument for the SetTcpEntry (MIB_TCPROW) function.
struct command_D002h_request
{
  packet_hdr header;
  MIB_TCPROW tcp_row
}
-

Option plug-in

The plug-in can receive the following commands:

  • 0x2000 — to block the system with the LockWorkstation function;
  • 0x2001 — to force the user to end the session;
  • 0x2002 — to reboot;
  • 0x2003 — to shut down the system;
  • 0x2005 — to show in a separate MessageBox thread with the specified parameters:
    struct command_0x2004_request
    {
      packet_hdr header;
      DWORD uType;
      WORD off_lpCaption;
      WORD off_lpText;
    }
    

Portmap plug-in

The plug-in contains the 0xB000 command. From the C&C server it receives its address and port:

 struct command_0xB000_request
{
  packet_hdr header;
  WORD port;
  BYTE srv_addr[40];
}
It then creates a TCP connection object and connects to the received address of the C&C server. Following that, it works in tunnel connection mode, transmitting data from the C&C server to the server it has established a connection with.

Process Plug-in

Command ID Description Output
0x5000 Receives a list of running processes. Each process corresponds to a separate packet being sent.
struct command_5000h_response
{
  packet_hdr header;
  BOOL if_sfc_protected;
  BOOL is_wow64;
  DWORD pid;
  WORD off_username;
  WORD off_user_domain;
  WORD off_proc_path;
  WORD off_CompanyName;
  WORD off_FileDescription;
  WORD off_FileVersion;
  WORD off_ProductName;
  WORD off_ProductVersion;
  WORD off_icon_bitmask_bitmap;
  WORD off_icon_color_bm;
  ...
  //strings
};
0x5001 Gets a list of modules for the specified process; the target process ID is set in the header.errc field of the command.
struct command_5001h_response
{
  packet_hdr header;
  BOOL if_sfc_protected;
  DWORD dll_base;
  DWORD size_of_image;
  FILETIME creation_time;
  FILETIME last_access_time;
  FILETIME last_write_time;
  WORD off_module_path;
  WORD off_CompanyInfo;
  WORD off_FileDescription;
  WORD off_FileVersion;
  WORD off_ProductName;
  WORD off_ProductVersion;
  ...
  //strings
};
0x5002 Terminates the process; the ID is set in the header.errc field of the command. -

Regedit plug-in

The plug-in is designed to operate with system registry.

Command ID Description Input Output
0x9000 Receives nested registry keys in the specified key. The section handle is contained in the the header.errc field, while the key name is contained in the command body. Sends one nested key at a time. -
struct command_0x9000_response
{
  packet_hdr header;
  BOOL if_has_subkeys;
  BYTE subkey_name[];
}
0x9001 Creates a nested key with the name specified in the command body. The key handle is contained in the header.errc field. - -
0x9002 Deletes the nested key specified in the command body. The key handle is contained in the header.errc field. - -
0x9003 Creates a key with the specified name, then recursively fills it with values copied from another key also specified in the command. If successful, the source key is deleted. Otherwise, the trojan deletes the newly created key. The key handle is contained in the header.errc field.
struct command_0x9003_request
{
  packet_hdr header;
  WORD off_src_subkey;
  WORD off_dst_subkey;
  ...
  //strings
}
-
0x9004 Retrieves the values of the specified key. The key name is contained in the body; the handle is contained in the header.errc field. -
struct command_9004h_response
{
  packet_hdr header;
  DWORD dword_0_zero;
  DWORD value_data_type;
  DWORD value_data_len;
  WORD word_0_zero;
  WORD off_value_name;
  WORD off_value_data;
  ...
  //strings
};
0x9005 Creates a nested key and the value in it. Depending on the flag in the command, the trojan can check whether the value exists. The key handle is contained in the header.errc field.
struct command_9005h_request
{
  packet_0_hdr header;
  BOOL check_if_val_exists;
  DWORD value_data_type;
  DWORD value_data_size;
  WORD off_subkey_name;
  WORD off_value_name;
  WORD off_value_data;
  ...
  //strings
};
-
0x9006 Removes the value from the key.
struct command_9006h_request
{
  packet_hdr header;
  WORD off_subkey_name;
  WORD off_value_name;
  ...
  //strings
}
-
0x9007 Trojan checks whether value 1 exists. If it does not, the trojan checks value 2. If value 2 exists, value 1 is created and replaced with value 2. After that, value 2 is deleted.
struct command_9007h_request
{
  packet_hdr header;
  WORD off_subkey_name;
  WORD off_value_2_name;
  WORD off_value_1_name;
  ...
  //strings
}
-

Screen plug-in

Creates and sends desktop screenshots and imitates working over the RDP Protocol.

Command ID Description Input Output
0x4000 The command starts 2 separate threads that simulate working over the RDP Protocol. Screenshots of the interactive desktop are sent in the first stream. In the second thread, commands related to logging mouse and keyboard events are received and executed. Initially, the 0x4000 command is received along with a packet that indicates the required resolution of screenshots (bits per pixel). The second thread can receive one of these commands:
  • 0x4004 — focusing on the window according to the coordinates specified in the command and (optionally) by mouse click;
  • 0x4005 — sending keyboard event logs;
  • 0x4006 — sending HWND_BROADCAST message with the Ctrl+Alt+Del key combination.
struct command_4000h_request
{
  packet_hdr header;
  WORD bits_per_pixel;
}
struct command_4004h_request
{
  packet_hdr header;
  DWORD mouse_event_flags;
  DWORD mouse_event_data;
  DWORD x;
  DWORD y;
};
struct command_4005h_request
{
  packet_0_hdr header;
  BYTE vkey_code;
  BYTE key_scan_code;
  WORD reserved_0;
  BYTE keybd_event_flags;
};
struct command_4000h_screen_attr
{
  packet_hdr header;
  WORD bits_per_pixel;
  WORD horiz_res;
  WORD ver_res;
  BYTE bitmap_colos[];
}
0x4100 Creates a screenshot with the specified parameters and sends it to the C&C server.
struct command_4100h_request
{
  packet_0_hdr header;
  BYTE bFlag;
  BYTE scale_or_resolution;
  WORD horz; //if flag -> resolutione, else scale coeff
  WORD vert; //as horz
};
-
0x4200 Sends a pre-taken screenshot in JPEG format from the config.screenshots_path directory. First it sends its name, then it sends the screenshot itself as blocks by 0xE000 bytes. Then sends a zero-length packet. - -

Service Plug-in

The plug-in is designed to operate with system services.

Command ID Description Input Output
0x6000 Receives information about services and their files. -
struct command_6000h_response
{
  packet_hdr header;
  DWORD if_sfc_protected;
  DWORD current_state;
  DWORD start_type;
  DWORD controls_accepted;
  DWORD pid;
  WORD offset_service_name;
  WORD offset_display_name;
  WORD offset_service_start_name;
  WORD offset_description;
  WORD offset_binpath;
  WORD offset_CompanyName;
  WORD offset_FileDescription;
  WORD offset_FileVersion;
  WORD offset_ProductName;
  WORD offset_ProductVersion;
  ...
  //strings
};
0x6001 Alternates the launch method of the specified service struct command_6000h_response. The name of the target service is contained in the command body; the new parameter for the launch method is contained in the header.errc field. - -
0x6002 Runs the specified service; its name is contained in the command body. - -
0x6003 Sends the control code to the specified service. The name is contained in the body; the control code is contained in the header.errc field. - -
0x6004 Deletes the service specified in the command body. - -

Shell plug-in

The plug-in is designed to create a shell for the cmd.exe; plug-in command ID — command_id — 0x7002. It creates pipes for reading and writing in two separate threads, then creates a cmd.exe process and redirects I / O to pipes. The trojan receives input from the connection object to the C&C server and sends an output in response.

SQL plug-in

The plug-in is designed to operate with SQL queries.

Command ID Description Input Output
0xC000 Retrieves available SQL data sources by the odbc32!SQLDataSourcesW function. -
struct command_C000h_response
{
  packet_hdr header;
  BYTE server_name[4096];
  BYTE descriptions[];
}
0xC001 Lists available SQL drivers by the odbc32!SQLDriversW function. -
struct command_C001h_response
{
  packet_0_hdr header;
  BYTE driver_description[4096];
  BYTE driver_attributes[];
};
0xC002 Executes an arbitrary SQL query. The body of the first packet contains the connection string that is used as an argument when calling the odbc32!SQLDriverConnect function. Next, packets with header.command_id equal to 0xC003 contain the requests. In response, diagnostic data obtained by calling the SQLGetDiagRecW function is sent in packets with header.command_id equal to 0xC008; the results of the SQL query are sent in packets with header.command_id equal to 0xC004. - -

Telnet plug-in

The plug-in is designed to fully simulate working over the Telnet Protocol. Starts when 0x7100 command is received. Upon this command, the "cmd.exe /Q” process is created, a zero-length packet is sent to the server, then 2 handlers run in separate threads. The first one accepts packets with id 0x7101 and 0x7102:

  • 0x7101 — opens the console using the CONIN$ ID and enters the data received from the command. The packet body contains an array of INPUT_RECORD structures.
  • 0x7102 — sends the ID of the control event (CtrlEvent) to the console opened by the CONIN$ ID. The event code is located in the header.errc field.

The second handle in packets with id 0x7103 sends information about the console:

struct c2_command_7103h_telnet_cli2srv
{
  packet_hdr header;
  DWORD console_CP;
  DWORD consoleOutput_CP;
  DWORD console_input_mode;
  DWORD console_output_mode;
  DWORD console_display_mode;
  CONSOLE_CURSOR_INFO console_cursor_info;
  COORD console_position;
  COORD console_size;
};

In packets with id 0x7104, the trojan sends the read console buffer.

Curing recommendations

  1. If the operating system (OS) can be loaded (either normally or in safe mode), download Dr.Web Security Space and run a full scan of your computer and removable media you use. More about Dr.Web Security Space.
  2. If you cannot boot the OS, change the BIOS settings to boot your system from a CD or USB drive. Download the image of the emergency system repair disk Dr.Web® LiveDisk , mount it on a USB drive or burn it to a CD/DVD. After booting up with this media, run a full scan and cure all the detected threats.
Download Dr.Web

Download by serial number

Use Dr.Web Anti-virus for macOS to run a full scan of your Mac.

After booting up, run a full scan of all disk partitions with Dr.Web Anti-virus for Linux.

Download Dr.Web

Download by serial number

  1. If the mobile device is operating normally, download and install Dr.Web for Android. Run a full system scan and follow recommendations to neutralize the detected threats.
  2. If the mobile device has been locked by Android.Locker ransomware (the message on the screen tells you that you have broken some law or demands a set ransom amount; or you will see some other announcement that prevents you from using the handheld normally), do the following:
    • Load your smartphone or tablet in the safe mode (depending on the operating system version and specifications of the particular mobile device involved, this procedure can be performed in various ways; seek clarification from the user guide that was shipped with the device, or contact its manufacturer);
    • Once you have activated safe mode, install the Dr.Web for Android onto the infected handheld and run a full scan of the system; follow the steps recommended for neutralizing the threats that have been detected;
    • Switch off your device and turn it on as normal.

Find out more about Dr.Web for Android