{
	"id": "b61dac7b-b14d-48e1-b1f2-7eddfd6d36e2",
	"created_at": "2026-04-06T00:14:53.956435Z",
	"updated_at": "2026-04-10T13:12:52.001237Z",
	"deleted_at": null,
	"sha1_hash": "24e4ae0088a53c995ad6558f0db7054f7452e8ac",
	"title": "BackDoor.ShadowPad.1 — Dr.Web Malware description library",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 719094,
	"plain_text": "BackDoor.ShadowPad.1 — Dr.Web Malware description library\r\nPublished: 2020-10-26 · Archived: 2026-04-05 20:36:14 UTC\r\nPacker:\r\nNSPack\r\nCompilation date:\r\n02.07.2017 05:59:15\r\nSHA1 hash:\r\n4bba897ee81240b10f9cca41ec010a26586e8c09\r\nDescription\r\nIt is a multi-module backdoor written in C and Assembler and designed to run on 32-bit and 64-bit Microsoft Windows\r\noperating systems. It is used in targeted attacks on information systems for gaining unauthorized access to data and\r\ntransferring it to C\u0026C servers. Its key feature is utilizing hardcoded plug-ins that contain the main backdoor’s functionality.\r\nOperating routine\r\nThe backdoor’s DLL library is loaded into RAM by DLL Hijacking using the genuine executable file TosBtKbd.exe from\r\nTOSHIBA CORPORATION. On the infected computer, the file was named msmsgs.exe.\r\n.\u003esigcheck -a msmsgs.exe_\r\n Verified: Signed\r\n Signing date: 5:24 24.07.2008\r\n Publisher: TOSHIBA CORPORATION\r\n Company: TOSHIBA CORPORATION.\r\n Description: TosBtKbd\r\n Product: Bluetooth Stack for Windows by TOSHIBA\r\n Prod version: 6, 2, 0, 0\r\n File version: 6, 2, 0, 0\r\n MachineType: 32-bit\r\n Binary Version: 6.2.0.0\r\n Original Name: TosBtKbd.exe\r\n Internal Name: n/a\r\n Copyright: Copyright (C) 2005-2008 TOSHIBA CORPORATION, All rights reserved.\r\n Comments: n/a\r\n Entropy: 5.287\r\nThe backdoor can be related to BackDoor.Farfli.125, since both malware programs use the same C\u0026C server —\r\nwww[.]pneword[.]net.\r\nThe sample was located on the infected computer in C:\\ProgramData\\Messenger\\ and was installed as the Messenger\r\nservice.\r\nIt is worth noting that BackDoor.Farfli.125 can execute the 0x7532 command, which is used to start a service with the same\r\nname — Messenger.\r\nStart of operation\r\nThe malicious library has two export functions:\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 1 of 21\n\nSetTosBtKbdHook\r\nUnHookTosBtKbd\r\nThe module name specified in the export table is TosBtKbd.dll.\r\nThe DLLMain function and the UnHookTosBtKbd export function are stubs.\r\nThe SetTosBtKbdHook function performs an exhaustive search through the handles in order to find objects whose names\r\ncontain TosBtKbd.exe and then closes them.\r\nint __stdcall check_handles()\r\n{\r\n ULONG v0; // ecx\r\n HMODULE v1; // eax\r\n int result; // eax\r\n int iter; // esi\r\n int v4; // eax\r\n ULONG ReturnLength; // [esp+0h] [ebp-4h] BYREF\r\n ReturnLength = v0;\r\n if ( *(_DWORD *)NtQueryObject\r\n || (v1 = GetModuleHandleA(aNtdllDll),\r\n result = (int)GetProcAddress(v1, aNtqueryobject),\r\n (*(_DWORD *)NtQueryObject = result) != 0) )\r\n {\r\n iter = 0;\r\n while ( 1 )\r\n {\r\n if ( NtQueryObject((HANDLE)(4 * iter), ObjectNameInformation, \u0026object__name_info, 0x1000u, \u0026ReturnLength) \u003e= 0 )\r\n {\r\n v4 = lstrlenW(object__name_info.Name.Buffer);\r\n do\r\n --v4;\r\n while ( v4 \u003e 0 \u0026\u0026 object__name_info.Name.Buffer[v4] != 92 );\r\n if ( !lstrcmpiW(\u0026object__name_info.Name.Buffer[v4 + 1], String2) )\r\n break;\r\n }\r\n if ( ++iter \u003e= 100000 )\r\n return 0;\r\n }\r\n result = CloseHandle((HANDLE)(4 * iter));\r\n }\r\n return result;\r\n}\r\nAfter that, the shellcode stored in the backdoor body is decrypted using SetTosBtKbdHook.\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 2 of 21\n\nShellcode decryption algorithm:\r\ndef LOBYTE(v):\r\n return v \u0026 0xFF\r\ndef dump_shellcode(addr, size, key):\r\n buffer = get_bytes(addr, size)\r\n result = b\"\"\r\n for x in buffer:\r\n result += bytes([x ^ LOBYTE(key)])\r\n key = ((key * 0x6A730000) - (((key \u003e\u003e 0x10) * 0x39F3958D)) - 0x5C0BB335) \u0026 0xFFFFFFFF\r\n i = 0\r\n for x in result:\r\n patch_byte(addr + i, x)\r\n i += 1\r\nThe decrypted shellcode utilizes obfuscation by using two consecutive conditional JMP instructions at a single address.\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 3 of 21\n\nAfter bypassing obfuscation, the function becomes correct:\r\nThe shellcode is designed for loading the main payload, which is a disassembled PE module without the MZ and PE\r\nheaders. A custom header consisting of separate parts of standard headers is used for the loading.\r\nstruct section\r\n{\r\n DWORD RVA;\r\n DWORD raw_data_offset;\r\n DWORD raw_data_len;\r\n};\r\nstruct module_header\r\n{\r\n DWORD key;\r\n DWORD key_check;\r\n DWORD import_table_RVA;\r\n DWORD original_ImageBase;\r\n DWORD relocation_table_RVA;\r\n DWORD relocation_table_size;\r\n DWORD IAT_RVA;\r\n DWORD IAT_size;\r\n DWORD EP_RVA;\r\n WORD HDR32_MAGIC;\r\n WORD word;\r\n DWORD number_of_sections;\r\n DWORD timestamp;\r\n section section_1;\r\n section section_2;\r\n section section_3;\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 4 of 21\n\nsection section_4;\r\n};\r\nThe header is stored in the shellcode after the first block of instructions.\r\nThe module_loader function then loads the payload directly. First, through the PEB structure, the backdoor obtains the\r\naddresses of the following functions from kernel32:\r\nLoadLibraryA\r\nGetProcAddress\r\nVirtualAlloc\r\nSleep\r\nKernel32 library name and the specified APIs are searched by the hash of the name, which is calculated by the algorithm:\r\ndef rol(val, r_bits, max_bits=32):\r\n return (val \u003c\u003c r_bits%max_bits) \u0026 (2**max_bits-1) | ((val \u0026 (2**max_bits-1)) \u003e\u003e (max_bits-(r_bits%max_bits)))\r\ndef ror(val, r_bits, max_bits=32):\r\n return ((val \u0026 (2**max_bits-1)) \u003e\u003e r_bits%max_bits) | (val \u003c\u003c (max_bits-(r_bits%max_bits)) \u0026 (2**max_bits-1))\r\ndef libnamehash(lib_name):\r\n result = 0\r\n b = lib_name.encode()\r\n for x in b:\r\n result = ror(result, 8)\r\n x |= 0x20\r\n result = (result + x) \u0026 0xFFFFFFFF\r\n result ^= 0x7C35D9A3\r\n return result\r\ndef procnamehash(proc_name):\r\n result = 0\r\n b = proc_name.encode()\r\n for x in n:\r\n result = ror(result, 8)\r\n result = (result + x) \u0026 0xFFFFFFFF\r\n result ^= 0x7C35D9A3\r\n return result\r\nAfter receiving the API addresses, the backdoor checks the integrity of the header values using an algorithm based on the\r\nXOR operation — module_header.key ^ module_header.key_check. The value must be 0x7C35D9A3 and it is the same\r\nvalue used when hashing function names from kernel32. After that, it checks the value of the signature\r\nmodule_header.HDR32_MAGIC signature that must be equal to 0x10B. The backdoor then allocates an executable buffer of\r\nthe module_header.import_table_RVA size and adds 0x4000 for the module.\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 5 of 21\n\nAfter that, it fills a block with the size of 0x1000 bytes at the beginning of the module_header.section_1.RVA allocated\r\nbuffer. That buffer is where the PE header of the loaded module should have been located.\r\nThe ECX register initially contains the address of the allocated executable buffer.\r\nThe backdoor then loads the module sections according to their RVA (Relative Virtual Address). Section data is stored in the\r\nshellcode after the header, and the offset to the (section.raw_data_offset) data is counted from the beginning of the header.\r\nAfter the sections, the program processes relocations that are stored as IMAGE_BASE_RELOCATION structures, but each\r\nWORD, which is responsible for the relocation type and for the offset from the beginning of the block, is encrypted. The\r\ninitial key is taken from module_header.key, and it changes after each iteration. It is worth noting that the key obtained after\r\nall iterations will be used for processing import functions.\r\nRelocations processing algorithm:\r\nimport struct\r\ndef relocations(image_address, original_image_base, relocation_table_RVA):\r\n global key\r\n relocation_table_addr = image_address + relocation_table_RVA\r\n reloc_hdr_data = get_bytes(relocation_table_addr, 8)\r\n block_address, size_of_block = struct.unpack('\u003cII', reloc_hdr_data)\r\n while size_of_block:\r\n if ((size_of_block - 8) \u003e\u003e 1) \u003e 0:\r\n block = get_bytes(relocation_table_addr + 8, size_of_block - 8)\r\n i = 0\r\n while i \u003c ((size_of_block - 8) \u003e\u003e 1):\r\n reloc = struct.unpack('\u003cH', block[i*2:i*2+2])[0]\r\n reloc_type = ((reloc ^ key) \u0026 0xFFFF) \u003e\u003e 0x0C\r\n offset = (reloc ^ key) \u0026 0xFFF\r\n offset_high = (((key \u003e\u003e 0x10) + reloc) \u0026 0xFFFFFFFF) | ((key \u003c\u003c 0x10) \u0026 0xFFFFFFFF)\r\n key = offset_high\r\n if reloc_type == 3:\r\n patch_addr = offset + image_address + block_address\r\n delta = (image_address - original_image_base) \u0026 0xFFFFFFFF\r\n value = get_wide_dword(patch_addr)\r\n patch_dword(patch_addr, (value + delta) \u0026 0xFFFFFFFF)\r\n elif reloc_type == 0x0A:\r\n patch_addr = image_address + offset + + block_address\r\n delta = (image_address - original_image_base) \u0026 0xFFFFFFFF\r\n old_low = get_wide_dword(patch_addr)\r\n old_high = get_wide_dword(patch_addr + 4)\r\n patch_dword(patch_addr, (old_low + offset) \u0026 0xFFFFFFFF)\r\n patch_dword(patch_addr + 4, (old_high + offset_high) \u0026 0xFFFFFFFF)\r\n i += 1\r\n relocation_table_addr += size_of_block\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 6 of 21\n\nreloc_hdr_data = get_bytes(relocation_table_addr, 8)\r\n block_address, size_of_block = struct.unpack('\u003cII', reloc_hdr_data)\r\nAfter all the relocations are processed, the structure is filled with null values.\r\nNext, BackDoor.ShadowPad.1 starts processing the import functions. In general, the procedure is standard, but the names\r\nof libraries and functions are encrypted. The key that was modified after processing the relocations is used, and is also\r\nchanged after each encryption iteration. After processing the next import function, its address is not placed directly in the\r\ncell specified relative to IMAGE_IMPORT_DESCRIPTOR.FirstThunk. Instead, a block of instructions is generated that\r\npasses control to the API:\r\nmov eax, \u003caddr\u003e\r\nneg eax\r\njmp eax\r\nAlgorithm for processing import functions:\r\ndef imports(image_address, IAT_RVA,):\r\nglobal key\r\nIAT_address = image_address + IAT_RVA\r\nimport_table_address = image_address + 0x1A000\r\nimport_descriptor_address = IAT_address\r\nwhile True:\r\n OriginalThunkData, TimeDateStamp, ForwarderChain, Name, FirstThunk = struct.unpack('\u003cIIIII', get_bytes(import_descript\r\n TimeDateStamp = 0\r\n ForwarderChain = 0\r\n OriginalThunkData_address = image_address + OriginalThunkData\r\n FirstThunk_address = image_address + FirstThunk\r\n libname_address = image_address + Name\r\n n1 = get_wide_byte(libname_address)\r\n libname_decrypted = bytes([(n1 ^ key) \u0026 0xFF])\r\n key = ((key \u003e\u003e 0x08) + c_byte(n1).value) | ((key \u003c\u003c 0x18) \u0026 0xFFFFFFFF)\r\n i = 1\r\n nb = get_wide_byte(libname_address + i)\r\n while libname_decrypted[-1]:\r\n libname_decrypted += bytes([(nb ^ key) \u0026 0xFF])\r\n key = ((key \u003e\u003e 0x08) + c_byte(nb).value) | ((key \u003c\u003c 0x18) \u0026 0xFFFFFFFF)\r\n i += 1\r\n nb = get_wide_byte(libname_address + i)\r\n libname_decrypted = libname_decrypted[:-1]\r\n print(\"Imports from {0}\".format(libname_decrypted[:-1]))\r\n thunk = get_wide_dword(OriginalThunkData_address)\r\n it_ptr = 0\r\n j = 0\r\n while thunk:\r\n name_address = image_address + thunk + 2\r\n nb1 = get_wide_byte(name_address)\r\n func_name = bytes([(nb1 ^ key) \u0026 0xFF])\r\n key = ((key \u003e\u003e 0x08) + c_byte(nb1).value) | ((key \u003c\u003c 0x18) \u0026 0xFFFFFFFF)\r\n i = 1\r\n nb = get_wide_byte(name_address + i)\r\n while func_name[-1]:\r\n func_name += bytes([(nb ^ key) \u0026 0xFF])\r\n key = ((key \u003e\u003e 0x08) + c_byte(nb).value) | ((key \u003c\u003c 0x18) \u0026 0xFFFFFFFF)\r\n i += 1\r\n nb = get_wide_byte(name_address + i)\r\n func_name = func_name[:-1]\r\n print(\"Function {0}\".format(func_name))\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 7 of 21\n\nj_type = key % 5\r\n if j_type == 0:\r\n patch_byte(import_table_address, 0xE8)\r\n elif j_type == 1:\r\n patch_byte(import_table_address, 0xE9)\r\n elif j_type == 2:\r\n patch_byte(import_table_address, 0xFF)\r\n elif j_type == 3:\r\n patch_byte(import_table_address, 0x48)\r\n elif j_type == 4:\r\n patch_byte(import_table_address, 0x75)\r\n else:\r\n patch_byte(import_table_address, 0x00)\r\n import_table_address += 1\r\n patch_dword(FirstThunk_address + it_ptr, import_table_address) #addr to trampoline\r\n func_addr = binascii.crc32(func_name) \u0026 0xFFFFFFFF\r\n patch_byte(import_table_address, 0xB8)\r\n patch_byte(import_table_address + 1, func_addr)\r\n patch_word(import_table_address + 5, 0xD8F7)\r\n patch_word(import_table_address + 7, 0xE0FF)\r\n import_table_address += 9\r\n j += 1\r\n it_ptr = j \u003c\u003c 2\r\n thunk = get_wide_dword(OriginalThunkData_address + it_ptr)\r\n import_descriptor_address += 0x14\r\n if not get_wide_dword(import_descriptor_address):\r\n break\r\nThe import table is also filled with null values after processing.\r\nThe control is then passed to the loaded module. Arguments are passed as:\r\nAddress of the beginning of the buffer where the module is loaded,\r\nValue 1 (code),\r\nPointer to the shellarg structure.\r\nAt the entry point, the loaded module checks the code passed from the loader:\r\n1 — the main functionality,\r\n0x64, 0x65 — no action provided,\r\n0x66 — returns the code 0x64 in the third argument,\r\n0x67 — decrypts and returns the Root string (hereinafter Root — the name of the module),\r\n0x68 — in the third argument returns a pointer to the table of functions implemented in this module.\r\nDecryption algorithm:\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 8 of 21\n\ndef decrypt_str(addr):\r\nkey = get_wide_word(addr)\r\nresult = b\"\"\r\ni = 2\r\nb = get_wide_byte(addr + i)\r\nwhile i \u003c 0xFFA:\r\n result += bytes([b ^ (key \u0026 0xFF)])\r\n key = ((( key \u003e\u003e 0x10) * 0x1447208B) + (key * 0x208B0000) - 0x4875A15) \u0026 0xFFFFFFFF\r\n i += 1\r\n b = get_wide_byte(addr + i)\r\n if not result[-1]:\r\n break\r\nresult = result[:-1]\r\nreturn result\r\nIt is worth noting that the code snippets contained in this module, as well as some objects, are typical of the\r\nBackDoor.PlugX family.\r\nWhen called with the code 1, the module proceeds to perform the main functions. At first, the program registers a top-level\r\nexception handler. When receiving control, the handler generates a debug string with information about the exception.\r\nThe program then outputs it using the OutputDebugString function, and writes it to the log file located in\r\n%ALLUSERPROFILE%\\error.log.\r\nException handlers are also registered in the BackDoor.PlugX family. In particular, in BackDoor.PlugX.38 a string with\r\ninformation about the exception is formed, but the format differs slightly:\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 9 of 21\n\nAfter registering the handler, a table of auxiliary functions is formed that is used for interaction between modules. Next,\r\nRoot proceeds to load the additional built-in modules.\r\nEach module is stored in an encrypted form and also compressed using the QuickLZ algorithm. At the beginning, the\r\nmodule has a header size of 0x14 bytes. The header is decoded during the first step. Encryption algorithm:\r\nimport struct\r\n \r\ndef LOBYTE(v):\r\n return v \u0026 0x000000FF\r\n \r\ndef BYTE1(v):\r\n return (v \u0026 0x0000FF00) \u003e\u003e 8\r\n \r\ndef BYTE2(v):\r\n return (v \u0026 0x00FF0000) \u003e\u003e 16\r\n \r\ndef HIBYTE(v):\r\n return (v \u0026 0xFF000000) \u003e\u003e 24\r\n \r\ndef decrypt_module(data, data_len, init_key):\r\n key = []\r\n for i in range(4):\r\n key.append(init_key)\r\n k = 0\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 10 of 21\n\nresult = b\"\"\r\n if data_len \u003e 0:\r\n i = 0\r\n while i \u003c data_len:\r\n if i \u0026 3 == 0:\r\n t = key[0]\r\n key[0] = (0x9150017B - (t * 0xD45A840)) \u0026 0xFFFFFFFF\r\n elif i \u0026 3 == 1:\r\n t = key[1]\r\n key[1] = (0x95D6A3A8 - (t * 0x645EE710)) \u0026 0xFFFFFFFF\r\n elif i \u0026 3 == 2:\r\n t = key[2]\r\n key[2] = (0xD608D41B - (t * 0x1ED33670)) \u0026 0xFFFFFFFF\r\n elif i \u0026 3 == 3:\r\n t = key[3]\r\n key[3] = (0xD94925D3 - (t * 0x68208D35)) \u0026 0xFFFFFFFF\r\n k = (k - LOBYTE(key[i \u0026 3])) \u0026 0xFF\r\n k = k ^ BYTE1(key[i \u0026 3])\r\n k = (k - BYTE2(key[i \u0026 3])) \u0026 0xFF\r\n k = k ^ HIBYTE(key[i \u0026 3])\r\n result += bytes([data[i] ^ k])\r\n i += 1\r\n return result\r\nThe initial value of the encryption key is stored in the module header. The structure looks as follows:\r\nstruct plugin_header\r\n{\r\n DWORD key;\r\n DWORD flags;\r\n DWORD dword;\r\n DWORD compressed_len;\r\n DWORD decompressed_len;\r\n};\r\nAfter decrypting the header, the backdoor checks the value of flags. If the 0x8000 flag is set, it means that the module\r\nconsists of only one header. Then the first byte’s zero bit value is checked in the decrypted block. If the zero bit has the\r\nvalue 1, it means the module body is compressed by the QuickLZ algorithm.\r\nAfter unpacking, the malware checks the size of the resulting data with the values in the header and proceeds directly to\r\nloading the module. To do so, it allocates an executable memory buffer to which it copies the load function and then passes\r\ncontrol to it. Each module has the same format as the Root module, so it has its own header and encrypted import functions\r\nand relocations; therefore, loading occurs in the same way. After the module is loaded, the loader function calls its entry\r\npoint with the code 1. Each module, like Root, initializes its function table using this code. Then Root calls the entry point of\r\nthe loaded module sequentially with the codes 0x64, 0x66, and 0x68. This way, the backdoor initializes the module and\r\npasses it pointers to the necessary objects.\r\nModules are represented as objects combined in a linked list. Referring to a specific module is performed using the code the\r\nplug-in puts in its object after calling its entry point with the code 0x66.\r\nstruct loaded_module\r\n{\r\n LIST_ENTRY list;\r\n DWORD run_count;\r\n DWORD timestamp;\r\n DWORD code_id;\r\n DWORD field_14;\r\n BOOL loaded;\r\n BOOL unk;\r\n BOOL module_is_PE;\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 11 of 21\n\nDWORD module_size;\r\n LPVOID module_base;\r\n Root_helper *func_tab;//pointer to the function table of the Root Module\r\n}\r\nWhen referring to the module entry point with the code 0x67, a string is decrypted and returned, which can be designated as\r\nthe module name:\r\n1 — Plugins\r\n2 — Online\r\n3 — Config\r\n4 — Install\r\n5 — TCP\r\n6 — HTTP\r\n7 — UDP\r\n8 — DNS\r\nIf one converts the timestamp fields from the headers of each plugin to dates, one gets the correct date and time values:\r\nPlugins — 2017-07-02 05:52:53\r\nOnline — 2017-07-02 05:53:08\r\nConfig — 2017-07-02 05:52:58\r\nInstall — 2017-07-02 05:53:30\r\nTCP — 2017-07-02 05:51:36\r\nHTTP — 2017-07-02 05:51:44\r\nUDP — 2017-07-02 05:51:50\r\nDNS — 2017-07-02 05:51:55\r\nAfter loading all the Root modules, the malware searches the list for the Install module and calls the second of the two\r\nfunctions located in its function table.\r\nInstall\r\nFirst of all, the backdoor gets the SeTcbPrivilege and SeDebugPrivilege privileges. Then it obtains the configuration using\r\nthe Config module. To access functions, the adapter functions of the following type are used:\r\nThrough the object that stores the list of loaded modules, the backdoor finds the necessary one using the code, then the\r\nnecessary function is called through the table.\r\nDuring the first step of the configuration initialization, the buffer stored in the Root module is checked. If the first four bytes\r\nof this buffer are X, this means the backdoor needs to create a default configuration. Otherwise, this buffer is an encoded\r\nconfiguration. The configuration is stored in the same format as plug-ins — it is compressed using the QuickLZ algorithm\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 12 of 21\n\nand encrypted using the same algorithm used for plug-in encryption. 0x858 bytes are reserved for the decrypted and\r\nunpacked configuration. Its structure can be represented as follows:\r\nstruct config\r\n{\r\n WORD off_id; //lpBvQbt7iYZE2YcwN\r\n WORD offset_1; //Messenger\r\n WORD off_bin_path; //%ALLUSERSPROFILE%\\Messenger\\msmsgs.exe\r\n WORD off_svc_name; //Messenger\r\n WORD off_svc_display_name; //Messenger\r\n WORD off_svc_description; //Messenger\r\n WORD off_reg_key_install; //SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\r\n WORD off_reg_value_name; //Messenger\r\n WORD off_inject_target_1; //%windir%\\system32\\svchost.exe\r\n WORD off_inject_target_2; //%windir%\\system32\\winlogon.exe\r\n WORD off_inject_target_3; //%windir%\\system32\\taskhost.exe\r\n WORD off_inject_target_4; //%windir%\\system32\\svchost.exe\r\n WORD off_srv_0; //HTTP://www.pneword.net:80\r\n WORD off_srv_1; //HTTP://www.pneword.net:443\r\n WORD off_srv_2; //HTTP://www.pneword.net:53\r\n WORD off_srv_3; //UDP://www.pneword.net:53\r\n WORD off_srv_4; //UDP://www.pneword.net:80\r\n WORD off_srv_5; //UDP://www.pneword.net:443\r\n WORD off_srv_6; //TCP://www.pneword.net:53\r\n WORD off_srv_7; //TCP://www.pneword.net:80\r\n WORD off_srv_8; //TCP://www.pneword.net:443\r\n WORD zero_2A;\r\n WORD zero_2C;\r\n WORD zero_2E;\r\n WORD zero_30;\r\n WORD zero_32;\r\n WORD zero_34;\r\n WORD zero_36;\r\n WORD off_proxy_1; //HTTP\\n\\n\\n\\n\\n\r\n WORD off_proxy_2; //HTTP\\n\\n\\n\\n\\n\r\n WORD off_proxy_3; //HTTP\\n\\n\\n\\n\\n\r\n WORD off_proxy_4; //HTTP\\n\\n\\n\\n\\n\r\n DWORD DNS_1; //8.8.8.8\r\n DWORD DNS_2; //8.8.8.8\r\n DWORD DNS_3; //8.8.8.8\r\n DWORD DNS_4; //8.8.8.8\r\n DWORD timeout_multiplier; //0x0A\r\n DWORD field_54; //zero\r\n //data\r\n};\r\nFields named off_* contain offsets to encrypted strings from the beginning of the configuration. The strings are encrypted\r\nwith the same algorithm as used to encrypt the names of the plug-ins. After initialization, the backdoor also attempts to get\r\nthe configuration from the file located in the %ALLUSERSPROFILE%\\\u003crnd1\u003e\\\u003crnd2\u003e\\\u003crnd3\u003e\\\u003crnd4\u003e directory.. The path\r\nand file name elements are generated during execution and depend on the serial number of the system partition.\r\nAfter initializing the configuration, the mode parameter is checked, which is stored in the shellarg structure. That structure is\r\nfilled in by the loader (shellcode) and stored in the stage_1 module.\r\nstruct shellarg\r\n{\r\n module_header *p_module_header;\r\n DWORD module_size;\r\n DWORD mode;\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 13 of 21\n\nDWORD unk;\r\n}\r\nThe algorithm provides a number of possible values for the mode parameter — 2, 3, 4, 5, 6, 7. If the value is different from\r\nthe listed ones, the backdoor is installed in the system, and then the main functions are performed.\r\nA series of values 2, 3 ,4 — to begin interaction with the C\u0026C server, bypassing the installation.\r\nA series of values 5, 6 — to work with the plug-in with the code 0x6A stored in the registry.\r\nValue 7 — using the IFileOperation interface, the source module is copied to %TEMP%, as well as to System32 or\r\nSysWOW64, depending on the system bitness. This is necessary to restart the backdoor with UAC bypass using the\r\nwusa.exe file.\r\nBackdoor installation process\r\nDuring installation, the backdoor checks the current path of the executable file by comparing it with the value of\r\noff_bin_path from the configuration (%ALLUSERSPROFILE%\\Messenger\\msmsgs.exe). If the path does not match and the\r\nbackdoor is launched for the first time, a mutex is created, the name of which is generated as follows:\r\nFormat of the mutex name for wsprintfW is Global\\%d%d%d.\r\nThen checks whether UAC is enabled. If control is disabled, the malware creates the control.exe process (from System32 or\r\nSysWOW64, depending on the system's bitness) with the CREATE_SUSPENDED flag. After that, the backdoor injects the\r\nRoot module into it, using WriteProcessMemory. Before doing this, the backdoor also implements a function that loads the\r\nmodule and transfers control to it. If UAC is enabled, this step is skipped.\r\nThe main executable file (msmsgs.exe) and TosBtKbd.dll are copied to the directory specified in the off_bin_path parameter\r\nand then installed as a service. The service name, display name, and description are contained in the configuration\r\n(parameters off_svc_name, off_svc_display_name, and off_svc_description). In this sample all three parameters have the\r\nMessenger value. If the service fails to start, the backdoor is registered in the registry. The key and parameter name for this\r\ncase are also stored in the configuration (off_reg_key_install and off_reg_value_name parameters).\r\nAfter installation, the backdoor attempts to inject the Root module into one of the processes specified in the configuration\r\n(off_inject_target_\u003c1..4\u003e). If successful, the current process terminates, and the new process (or service) proceeds to interact\r\nwith the C\u0026C server.\r\nA separate thread is created for this purpose. After that, a new registry key is created or an existing registry key is opened,\r\nwhich is used as the malware's virtual file system. The key is located in the Software\\Microsoft\\\u003ckey\u003e branch, and the\r\n\u003ckey\u003e value is also generated depending on the serial number of the system volume. The key can also be located in the\r\nHKLM and HKCU, depending on the privileges of the process. Next, the RegNotifyChangeKey function tracks changes in\r\nthis key. Each parameter is a compressed and encrypted plug-in. The backdoor extracts each value and loads it as a module,\r\nadding it to the list of available ones.\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 14 of 21\n\nThis functionality is executed in a separate thread.\r\nThe next step generates a pseudo-random sequence from 3 to 9 bytes long, which is written to the registry in the\r\nSOFTWARE\\ key located in the HKLM or HKCU. The parameter name is also generated and is unique for each computer.\r\nThis value is used as the ID of the infected device.\r\nAfter that, the backdoor extracts the address of the first C\u0026C server from the configuration. The server storage format is as\r\nfollows: \u003cprotocol\u003e://\u003caddress\u003e:\u003cport\u003e. In addition to the values that explicitly define the protocol used (HTTP, TCP,\r\nUDP), the URL value can also be specified. In this case, the backdoor refers to this URL and receives a new address of the\r\nC\u0026C server in response, using the domain generation algorithm (DGA). The algorithm generates the string:\r\nwstr *__stdcall dga(wstr *p_wstr)\r\n{\r\n unsigned int v1; // ecx\r\n unsigned int v2; // edi\r\n unsigned int v3; // esi\r\n unsigned int v4; // edx\r\n char v5; // dl\r\n wstr *v6; // eax\r\n wstr *v7; // esi\r\n wstr tmp_str; // [esp+10h] [ebp-34h] BYREF\r\n char generated_char_str[16]; // [esp+20h] [ebp-24h] BYREF\r\n struct _SYSTEMTIME SystemTime; // [esp+30h] [ebp-14h] BYREF\r\n GetSystemTime_0(\u0026SystemTime);\r\n if ( SystemTime.wDay \u003e 0xAu )\r\n {\r\n if ( SystemTime.wDay \u003e 0x14u )\r\n v1 = 0xE52F65F3 * SystemTime.wYear - 0x2527D2DD * SystemTime.wMonth - 0x4BA7EAF5;\r\n else\r\n v1 = 0xF108D240 * SystemTime.wMonth - 0x78C6249D * SystemTime.wYear - 0x17AB943D;\r\n }\r\n else\r\n {\r\n v1 = 0xF5D6C030 * SystemTime.wMonth - 0x5FBD1755 * SystemTime.wYear - 0x5540E1B0;\r\n }\r\n v2 = 0;\r\n v3 = v1 % 7;\r\n do\r\n {\r\n v4 = v1 % 0x34;\r\n if ( v1 % 0x34 \u003e= 0x1A )\r\n v5 = v4 + 39;\r\n else\r\n v5 = v4 + 97;\r\n v1 = 13 * v1 + 7;\r\n generated_char_str[v2++] = v5;\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 15 of 21\n\n}\r\n while ( v2 \u003c= v3 + 7 );\r\n generated_char_str[v3 + 8] = 0;\r\n v6 = wstr::assign_char_str_pl2(\u0026tmp_str, generated_char_str);\r\n v7 = (wstr *)wstr::init_by_wchar_pl2(p_wstr, (LPCWSTR)v6-\u003ebuffer_wchar);\r\n wstr::clean_pl2(\u0026tmp_str);\r\n return v7;\r\n}\r\nThe resulting string is combined with the string stored in the configuration, using the part before the @ symbol. The\r\nreceived URL is used for an HTTP request, which is answered with the encoded address of the C\u0026C server.\r\nAfter that, a connection object is created that corresponds to the protocol specified for this server.\r\nTCP\r\nSOCKS4, SOCKS5, and HTTP proxy protocols are supported when connecting over TCP. At the beginning, a socket is\r\ncreated and a connection to the server is established in keep-alive mode. A packet with the following header format is used\r\nfor communication with the server:\r\nstruct packet_header\r\n{\r\n DWORD key;\r\n DWORD id;\r\n DWORD module_code;\r\n DWORD compressed_len;\r\n DWORD decompressed_len;\r\n};\r\nHTTP\r\nWhen using the HTTP protocol, data is sent by a POST request:\r\nData transfer over HTTP is performed by the handler function in a separate thread. The mechanism is similar to that of\r\nBackDoor.PlugX.\r\nDNS servers from the configuration are used to resolve the addresses of C\u0026C servers (in this sample all 4 addresses are\r\n8.8.8.8). The first packet sent to the server is a sequence of zeros from 0 to 0x3f bytes in length. The length is selected\r\nrandomly.\r\nThe backdoor receives a response from the server, which is then decrypted and unpacked. Then, the packet header checks\r\nthe module_code value, which contains the code of the plug-in for which the command was received. The backdoor refers to\r\nthe plug-in whose code is specified in the command and calls the function for processing commands from its table. The ID\r\nof the command itself is contained in the id field of the header.\r\nOperating with plug-ins\r\nCommand IDs for the Plugins module can have the following values id — 0x650000, 0x650001, 0x650002, 0x650003, or\r\n0x650004. In fact, the Plugins module is a plug-in manager, allowing one to register new plug-ins and delete existing ones.\r\nCommand\r\nID\r\nDescription\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 16 of 21\n\n0x650003 Deletes the specified plug-in from the storage in the registry.\r\n0x650000\r\nSends information about available plug-ins.\r\nValue Size, byte\r\nplug-in name variable length null-terminated string\r\nnumber of plug-in calls 4\r\nDateTimeStamp 4\r\nplug-in code 4\r\nloaded_module.field_14 (unknown) 4\r\nstatus (loaded or not) 4\r\ninitialized 4\r\nsize 4\r\nbase address 8\r\n0x650001\r\nBody of the command contains a new plug-in. The plug-in format is the same as the built-in ones. The\r\nbackdoor compresses it with the QuickLZ algorithm, encrypts it and stores it in the registry storage, then\r\npauses the current thread so the plug-in processing thread loads a new plug-in from the registry storage.\r\n0x650002\r\nThe command contains the name of the DLL that the backdoor attempts to load, and then sequentially\r\ncalls its entry point with dwReason 0x64, 0x66, 0x68.\r\n0x650004\r\nThe command contains the module code. If a plug-in with the specified code is present in the list, the\r\nbackdoor deinitializes it.\r\nOnline\r\nThe command IDs for the Online plug-in can have the values 0x680002, 0x680003, 0x680004, or 0x680005.\r\nCommand\r\nID\r\nDescription\r\n0x680002 Starts processing commands for plug-ins in a separate thread and initializes a new connection to the current server.\r\n0x680003 Sends system information. It can be represented as the structure:\r\nstruct date\r\n{\r\n BYTE year; //+0x30\r\n BYTE month;\r\n BYTE day;\r\n BYTE hour;\r\n BYTE minute;\r\n BYTE second;\r\n BYTE space;\r\n}\r\n \r\nstruct sysinfo\r\n{\r\n byte id[8];\r\n DWORD datestamp1; //20150810\r\n DWORD datestamp2; //20170330\r\n BYTE year; //+0x30\r\n BYTE month;\r\n BYTE day;\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 17 of 21\n\nBYTE hour;\r\n BYTE minute;\r\n BYTE second;\r\n BYTE space;\r\n DWORDmodule_code;\r\n WORDmodule_timestamp;//the lower 2 bytes of the loaded_module.timestamp field of the connection module\r\n DWORDIP_address;\r\n LARGE_INTEGER total_physical_memory;\r\n DWORDcpu_0_MHZ;\r\n DWORDnumber_of_processors;\r\n DWORDdwOemID;\r\n LARGE_INTEGER total_disk_space[number_of_disks];//iterates all disks starting from C:\r\n DWORDpels_width;//screen width in pixels\r\n DWORDpels_height;//screen height in pixels\r\n DWORDLCID;\r\n LARGE_INTEGER perfomance_frequency;//pseudo-random value generated using QueryPerformanceCounter and QueryPerformance\r\n DWORDcurrent_PID;\r\n DWORDos_version_major;\r\n DWORDos_version_minor;\r\n DWORDos_version_build_number;\r\n DWORDos_version_product_type;\r\n DWORDsm_Server_R2_build_number;//GetSystemMetrics(SM_SERVERR2)\r\n //the strings below - null-terminated\r\n charhostname[x];\r\n chardomain_name[x];\r\n chardomain__username[x];//separated \"/\"\r\n charmodule_file_name[x];\r\n charosver_info_szCSDVersion[x];\r\n charstr_from_config_offset1[x];//Messenger\r\n}\r\nThe id value is the unique identifier of the infected computer stored in the registry.\r\nIt is worth noting that the values of the datestamp1 and datestamp2 fields are set to 20150810 and 20170330, respectively. Sim\r\nconstants in the form of dates were also used in PlugX backdoor plug-ins.\r\n0x680004 Sends a packet with a random length body (from 0 to 0x1F bytes). The packet body is filled with 0.\r\n0x680005 Sends an empty packet (header only) and then calls Sleep(1000) 3 times in a row.\r\nConfig\r\nThis is a plug-in for working with the configuration.\r\nCommand ID Description\r\n0x660000 Sends the current configuration to the server.\r\n0x660001 Receives and applies the new configuration.\r\n0x660002 Deletes the saved configuration file.\r\nInstall\r\nCommand\r\nID\r\nDescription\r\n0x670000 Installs the backdoor as a service or installs it in the registry.\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 18 of 21\n\n0x670001\r\nCalls Sleep(1000) three times in a row, then checks the shellarg.mode parameter: if its value is 4, it\r\nthen terminates the current process.\r\nArtifacts\r\nIn the historical WHOIS record of the С\u0026С server domain, one can observe the Registrar's email address:\r\nddggcc@189[.]cn.\r\nThe same address is found in the icefirebest[.]com and www[.]arestc[.]net domain records, which were contained in the\r\nconfigurations of PlugX backdoor samples installed on the same computer.\r\nDomain Name: ICEFIREBEST.COM\r\nRegistry Domain ID: 2042439159_DOMAIN_COM-VRSN\r\nRegistrar WHOIS Server: whois.1api.net\r\nRegistrar URL: http://www.1api.net\r\nUpdated Date: 2016-07-28T16:55:13Z\r\nCreation Date: 2016-07-13T01:39:31Z\r\nRegistrar Registration Expiration Date: 2017-07-13T01:39:31Z\r\nRegistrar: 1API GmbH\r\nRegistrar IANA ID: 1387\r\nRegistrar Abuse Contact Email: abuse@1api.net\r\nRegistrar Abuse Contact Phone: +49.68416984x200\r\nDomain Status: ok - http://www.icann.org/epp#OK\r\nRegistry Registrant ID:\r\nRegistrant Name: edward davis\r\nRegistrant Organization: Edward Davis\r\nRegistrant Street: Tianhe District Sports West Road 111\r\nRegistrant City: HONG KONG\r\nRegistrant State/Province: Hongkong\r\nRegistrant Postal Code: 510000\r\nRegistrant Country: HK\r\nRegistrant Phone: +86.2029171680\r\nRegistrant Phone Ext:\r\nRegistrant Fax: +86.2029171680\r\nRegistrant Fax Ext:\r\nRegistrant Email: ddggcc@189.cn\r\nRegistry Admin ID:\r\nAdmin Name: edward davis\r\nAdmin Organization: Edward Davis\r\nAdmin Street: Tianhe District Sports West Road 111\r\nAdmin City: HONG KONG\r\nAdmin State/Province: Hongkong\r\nAdmin Postal Code: 510000\r\nAdmin Country: HK\r\nAdmin Phone: +86.2029171680\r\nAdmin Phone Ext:\r\nAdmin Fax: +86.2029171680\r\nAdmin Fax Ext:\r\nAdmin Email: ddggcc@189.cn\r\nRegistry Tech ID:\r\nTech Name: edward davis\r\nTech Organization: Edward Davis\r\nTech Street: Tianhe District Sports West Road 111\r\nTech City: HONG KONG\r\nTech State/Province: Hongkong\r\nTech Postal Code: 510000\r\nTech Country: HK\r\nTech Phone: +86.2029171680\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 19 of 21\n\nTech Phone Ext:\r\nTech Fax: +86.2029171680\r\nTech Fax Ext:\r\nTech Email: ddggcc@189.cn\r\nName Server: ns1.ispapi.net 194.50.187.134\r\nName Server: ns2.ispapi.net 194.0.182.1\r\nName Server: ns3.ispapi.net 193.227.117.124\r\nDNSSEC: unsigned\r\nURL of the ICANN WHOIS Data Problem Reporting System:\r\nhttp://wdprs[.]internic[.]net/\r\nDomain Name: ARESTC.NET\r\nRegistry Domain ID: 2196389400_DOMAIN_NET-VRSN\r\nRegistrar WHOIS Server: whois.1api.net\r\nRegistrar URL: http://www.1api.net\r\nUpdated Date: 2017-12-06T08:43:04Z\r\nCreation Date: 2017-12-06T08:43:04Z\r\nRegistrar Registration Expiration Date: 2018-12-06T08:43:04Z\r\nRegistrar: 1API GmbH\r\nRegistrar IANA ID: 1387\r\nRegistrar Abuse Contact Email: abuse@1api.net\r\nRegistrar Abuse Contact Phone: +49.68416984x200\r\nDomain Status: ok - http://www.icann.org/epp#OK\r\nRegistry Registrant ID:\r\nRegistrant Name: li yiyi\r\nRegistrant Organization: li yiyi\r\nRegistrant Street: Tianhe District Sports West Road 111\r\nRegistrant City: GuangZhou\r\nRegistrant State/Province: Guangdong\r\nRegistrant Postal Code: 510000\r\nRegistrant Country: CN\r\nRegistrant Phone: +86.2029179999\r\nRegistrant Phone Ext:\r\nRegistrant Fax: +86.2029179999\r\nRegistrant Fax Ext:\r\nRegistrant Email: ddggcc@189.cn\r\nRegistry Admin ID:\r\nAdmin Name: li yiyi\r\nAdmin Organization: li yiyi\r\nAdmin Street: Tianhe District Sports West Road 111\r\nAdmin City: GuangZhou\r\nAdmin State/Province: Guangdong\r\nAdmin Postal Code: 510000\r\nAdmin Country: CN\r\nAdmin Phone: +86.2029179999\r\nAdmin Phone Ext:\r\nAdmin Fax: +86.2029179999\r\nAdmin Fax Ext:\r\nAdmin Email: ddggcc@189.cn\r\nRegistry Tech ID:\r\nTech Name: li yiyi\r\nTech Organization: li yiyi\r\nTech Street: Tianhe District Sports West Road 111\r\nTech City: GuangZhou\r\nTech State/Province: Guangdong\r\nTech Postal Code: 510000\r\nTech Country: CN\r\nTech Phone: +86.2029179999\r\nTech Phone Ext:\r\nTech Fax: +86.2029179999\r\nTech Fax Ext:\r\nTech Email: ddggcc@189.cn\r\nName Server: ns1.ispapi.net 194.50.187.134\r\nName Server: ns2.ispapi.net 194.0.182.1\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 20 of 21\n\nName Server: ns3.ispapi.net 193.227.117.124\r\nDNSSEC: unsigned\r\nURL of the ICANN WHOIS Data Problem Reporting System:\r\nhttp://wdprs[.]internic[.]net/\r\nSource: https://vms.drweb.com/virus/?i=21995048\r\nhttps://vms.drweb.com/virus/?i=21995048\r\nPage 21 of 21",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://vms.drweb.com/virus/?i=21995048"
	],
	"report_names": [
		"?i=21995048"
	],
	"threat_actors": [],
	"ts_created_at": 1775434493,
	"ts_updated_at": 1775826772,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/24e4ae0088a53c995ad6558f0db7054f7452e8ac.pdf",
		"text": "https://archive.orkl.eu/24e4ae0088a53c995ad6558f0db7054f7452e8ac.txt",
		"img": "https://archive.orkl.eu/24e4ae0088a53c995ad6558f0db7054f7452e8ac.jpg"
	}
}