{
	"id": "9418710a-7f67-4d88-80b5-8dcd277cf716",
	"created_at": "2026-04-06T00:21:01.191566Z",
	"updated_at": "2026-04-10T03:20:23.321776Z",
	"deleted_at": null,
	"sha1_hash": "fd850acb9d31b05f8158ba30d069734f39b04611",
	"title": "YiBackdoor: Linked to IcedID and Latrodectus | ThreatLabz",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 520155,
	"plain_text": "YiBackdoor: Linked to IcedID and Latrodectus | ThreatLabz\r\nBy ThreatLabz\r\nPublished: 2025-09-23 · Archived: 2026-04-05 21:42:05 UTC\r\nTechnical Analysis\r\nIn this section, the features and capabilities of YiBackdoor are described along with the code similarities with\r\nIcedID and Latrodectus.\r\nANALYST NOTE: YiBackdoor generates and uses pseudo-random values at different stages (e.g. for generating\r\nthe registry persistence value name). The malware implements custom algorithms for deriving random values,\r\nwhich are primarily based on the bot ID (used as a seed) combined with an implementation of Microsoft’s Linear\r\nCongruential Generator (LCG). Since not all pseudo-random values are generated using a single method,\r\nThreatLabz reversed each function and ported them to Python individually. To ensure consistency and clarity\r\nthroughout this blog, the random values that are referenced can be derived using the Python script available in the\r\nThreatLabz GitHub repository.\r\nAnti-analysis\r\nYiBackdoor includes a limited set of anti-analysis techniques with most of them targeting virtualized\r\nenvironments, and by extension, malware sandboxes. The malware employs the following anti-analysis methods:\r\nDynamically loads Windows API functions by walking the loaded modules list, computing an ROR-based\r\nhash for each function name, and comparing the results with expected values to identify specific Windows\r\nAPI functions.\r\nYiBackdoor utilizes the  CPUID instruction with the parameter  0x40000000 to retrieve hypervisor\r\ninformation. The result is then compared to values that match known hypervisors, including the following:\r\nVMWare\r\nXen\r\nKVM\r\nVirtual Box\r\nMicrosoft Hyper-V\r\nParallels\r\nDecrypts strings at runtime by pushing an encrypted string onto the stack, which is then decrypted by\r\nperforming an XOR operation with a 4-byte key (that is unique for each encrypted string).\r\nMeasures the execution time of a code block to determine if the host is running on a hypervisor.\r\nSpecifically, YiBackdoor begins by calling the Windows API function  SwitchToThread followed by a call\r\nto the instruction  rdtsc . Next, YiBackdoor calls the  CPUID instruction, which triggers a VM exit, and\r\nthen calls  rdtsc again to calculate the time taken to execute the  CPUID instruction. Once the time has\r\nbeen calculated, YiBackdoor calls the  rdtsc instruction two more times and calculates the execution time\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 1 of 12\n\nagain. This process is repeated 16 times and the final calculated value must be greater than 20 to bypass the\r\ndetection. This behavior can be reproduced using the following code example.\r\n[[nodiscard]] bool isHyperVisor()\r\n{\r\n uint64_t timer1 = 0;\r\n uint64_t timer2 = 0;\r\n int loop_counter = 16;\r\n int cpuInfo[4] = { 0 };\r\n while (loop_counter)\r\n {\r\n SwitchToThread();\r\n uint64_t first_rdtsc_timer_value = __rdtsc();\r\n __cpuid(cpuInfo, 1);\r\n timer1 += __rdtsc() - first_rdtsc_timer_value;\r\n SwitchToThread();\r\n uint64_t second_rdtsc = __rdtsc();\r\n uint64_t third_rdtsc = __rdtsc();\r\n timer2 += ((third_rdtsc\r\nIt is worth noting that YiBackdoor stores the aforementioned information internally, but does not use the\r\ninformation or transmit it to the C2 server. As a result, the detection methods outlined above currently have no\r\nimpact on the code’s behavior.\r\nInitialization stage\r\nThere are several actions that YiBackdoor performs during the initialization phase including injecting code into a\r\nremote process and establishing persistence.\r\nYiBackdoor first checks for existing instances of itself by attempting to create a mutex with a host-based name. If\r\nthe mutex already exists, indicating another instance is active, YiBackdoor will terminate execution.\r\nCode injection\r\nBefore proceeding to the core functionality, YiBackdoor ensures that it is running within an injected process.\r\nYiBackdoor determines this by checking whether its current memory address falls within the memory range of\r\nany loaded DLLs. If it does, YiBackdoor creates a new svchost.exe process and injects its code into it.\r\nThe injection begins with YiBackdoor allocating memory in the remote svchost.exe target process and copying its\r\ncode into that new region. YiBackdoor patches the Windows API function  RtlExitUserProcess with assembly\r\ncode that pushes YiBackdoor’s entry point on the stack, which is then followed by a return instruction. Thus, when\r\nthe  RtlExitUserProcess function is called, the process execution flow will be redirected to the YiBackdoor’s\r\nentry point. Interestingly, the svchost.exe target process is created without any special flags (e.g., in a suspended\r\nstate). However, YiBackdoor does have enough time to inject its code between the process creation and\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 2 of 12\n\ntermination. Since the  RtlExitUserProcess function is hooked, the malware’s code executes just as the target\r\nprocess is about to terminate. This injection technique may allow YiBackdoor to evade detection by some security\r\nproducts.\r\nPersistence\r\nAfter completing the code injection phase, YiBackdoor proceeds to establish persistence on the compromised host\r\nusing the Windows Run registry key. YiBackdoor first copies itself (the malware DLL) into a newly created\r\ndirectory under a random name. Next, YiBackdoor adds regsvr32.exe malicious_path in the registry value name\r\n(derived using a pseudo-random algorithm) and self-deletes to hinder forensic analysis.\r\nBackdoor configuration\r\nYiBackdoor contains an embedded configuration stored in an encrypted state. The configuration blob is decrypted\r\nand initialized at runtime. The decryption algorithm uses a 64-byte string as the key, as shown in the decryption\r\nroutine below.\r\ndef decrypt(data: bytes, key: bytes) -\u003e bytearray:\r\n decrypted_config = bytearray()\r\n for i in range(len(data)):\r\n x = i % len(key)\r\n y = (i + 1) % len(key)\r\n cipher = key[x] + key[y]\r\n cipher = (cipher ^ data[i]) \u0026 0xFF\r\n decrypted_config.append(cipher)\r\n rotation_x = ror(n=key[x] \u003e\u003e (key[y] \u0026 7), bits=key[x] \u003e ( rotation_x \u0026 7), bits=key[y]\r\nThe decrypted configuration data includes the following information:\r\nA list of C2 servers (separated using a space delimiter) where each C2 server has a boolean flag to indicate\r\nif the requests should be in HTTP (false) or HTTPS (true). For instance, the entry  127.0.0.1:0 instructs\r\nYiBackdoor to communicate using HTTP to the C2 address 127.0.0.1.\r\nThree strings that are used for deriving the TripleDES encryption/decryption keys and the  initialization\r\nvector (IV) during the network communication process.\r\nTwo integer values that YiBackdoor converts to numerical strings, which are used to construct the C2 URI.\r\nAn unknown string identifier, which could represent a campaign or botnet ID. In the sample analyzed by\r\nThreatLabz, this value is set to the string test.\r\nThe configuration’s structure is provided below.\r\n#pragma pack(push, 1)\r\nstruct configuration\r\n{\r\n char C2s[300];\r\n char response_triple_des_key_table[192];\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 3 of 12\n\nchar request_triple_des_key_table[192];\r\n char triple_des_iv[128];\r\n uint32_t uri1;\r\n uint32_t pad;\r\n uint32_t uri2;\r\n char botnet_id[64];\r\n};\r\n#pragma pack(pop)\r\nANALYST NOTE: Before decrypting the configuration data, YiBackdoor ensures that the encrypted configuration\r\ndoes not start with the hardcoded string “YYYYYYYYYY”. If a match is found, the embedded configuration data is\r\nconsidered corrupted and the execution stops. ThreatLabz has not been able to confirm the reason for this check\r\nyet. Moreover, two of the three configuration C2s are local IP addresses, which further supports the argument that\r\nYiBackdoor is still in a development or testing phase.\r\nNetwork communication\r\nBefore initializing a network session with the C2, YiBackdoor derives the C2 URL by reading the following\r\nvalues from the decrypted configuration blob.\r\nC2 domain or IP address.\r\nTwo hardcoded strings that are used as part of the C2 URI.\r\nGenerated bot ID (calculated at runtime).\r\nThus, the C2 URL is structured as  http(s)://C2/bot_id/uri1/uri2 .\r\nNext, YiBackdoor creates a JSON packet that contains the host’s system time (UTC format) and username. The\r\nJSON packet is then encrypted using the TripleDES encryption algorithm. The creation of encryption/decryption\r\nkeys along with the IV is quite unique. The configuration blob includes three strings with each one of them used\r\nfor deriving the encryption key, decryption key, and IV. However, YiBackdoor does not use their entire values.\r\nInstead, it uses the current day of the week as an offset to calculate the starting address of the target value. Using\r\nthis approach, YiBackdoor manages to have dynamic (and different) encryption keys per day and as a result makes\r\nthe network traffic more resilient against static-based signatures. This algorithm is shown in the figure below:\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 4 of 12\n\nFigure 1: Network dynamic key derivation function for YiBackdoor.\r\nThe encrypted output is then Base64-encoded and appended to the HTTP header X-tag, and sent in an HTTP GET\r\nrequest.\r\nThe C2 response decryption process is similar. YiBackdoor verifies the presence of the HTTP header X-tag and\r\ndecrypts it. The decrypted header contains the same information that was included in the HTTP request.\r\nYiBackdoor then decrypts and parses the HTTP body data, which contains incoming commands, which are in a\r\nJSON format. \r\nNetwork commands\r\nYiBackdoor supports the commands described in the table below.\r\nCommand\r\nName\r\nCommand Parameters Description\r\nSysteminfo None Collects the following system information:\r\nWindows version.\r\nList of process names.\r\nNetwork and miscellaneous system information by\r\nexecuting the system commands provided below.\r\nchcp 65001\r\nwhoami /all\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 5 of 12\n\nCommand\r\nName\r\nCommand Parameters Description\r\narp -a\r\nipconfig /all\r\nnet view /all\r\nnltest /domain_trusts /all_trusts\r\nnet share\r\nnet localgroup\r\nwmic product get name\r\nscreen None Takes a screenshot of the compromised host’s desktop.\r\nCMD\r\nBase64-encoded\r\ncommand line to\r\nexecute.\r\nTimeout value.\r\nExecutes a system shell command using cmd.exe.\r\nPWS\r\nBase64-encoded\r\ncommand line to\r\nexecute.\r\nTimeout value.\r\nExecutes a system shell command using PowerShell.\r\nplugin\r\nPlugin name.\r\nCommand data for\r\nthe plugin to execute.\r\nPasses a command to an existing plugin to execute based on\r\nits name and reports the result to the C2 server.\r\ntask\r\nBase64-encoded and\r\nencrypted plugin\r\ndata.\r\nInitializes and executes a new plugin. If the plugin already\r\nexists, then reload the plugin using the data that was\r\nreceived.\r\nTable 1: YiBackdoor network commands.\r\nNote that the command names above use inconsistent casing (e.g., camel case, lowercase, and uppercase).\r\nThe structures (in C format) that YiBackdoor uses to parse both tasks received and network commands are shown\r\nbelow.\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 6 of 12\n\nenum Command\r\n{\r\n system_info = 0x3,\r\n screenshot = 0x4,\r\n execute_new_plugin = 0x5,\r\n execute_loaded_plugin = 0x8,\r\n execute_cmd = 0x9,\r\n execute_powershell = 0xA,\r\n};\r\nstruct custom_string\r\n{\r\n char *string;\r\n size_t size;\r\n size_t capacity;\r\n};\r\n#pragma pack(push, 1)\r\nstruct task_info\r\n{\r\n uint32_t task_id;\r\n Command cmd_id;\r\n uint32_t unknown_ID;\r\n custom_string command_parameter;\r\n custom_string plugin_name;\r\n uint32_t timeout_time;\r\n};\r\n#pragma pack(pop)\r\nCommand status\r\nYiBackdoor reports the output of each command to the C2 by sending an HTTP POST request. Each command\r\nstatus packet is in a JSON format and includes the following information:\r\nTask ID.\r\nA boolean value that represents the execution status of the command.\r\nThe output of the command.\r\nThe reported output is summarized in the table below.\r\nNetwork\r\nCommand\r\nReported Information\r\nSysteminfo Collected system information.\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 7 of 12\n\nNetwork\r\nCommand\r\nReported Information\r\nA list of loaded plugins that include the ID and name of each plugin in the\r\nformat  plugin_name-ID.bin .\r\nscreen Screenshot encoded in Base64 format.\r\ntask\r\nA list of loaded plugins that include the ID and name of each plugin in the\r\nformat  plugin_name-ID.bin .\r\nplugin Output data resulting from executing a command within the specified plugin.\r\nCMD/PWS\r\nOutput data resulting from executing a system shell command formatted in\r\nBase64.\r\nTable 2:  YiBackdoor command status messages.\r\nANALYST NOTE: The task status for the network command ‘task’ is always set to true (success) regardless of the\r\nplugin’s loading status.\r\nPlugins\r\nYiBackdoor stores each plugin that is received locally in the Windows temporary folder using a random filename\r\nwith the file extension .bin. The malware identifies a target plugin by validating the filename against its own\r\nfilename generation algorithm. The plugins are reloaded each time YiBackdoor is executed.\r\nEach plugin is stored in an encrypted format. The following Python code snippet represents the\r\nencryption/decryption algorithm.\r\n def fix_key(key: bytearray, x: int, y: int) -\u003e bytearray:\r\n temp_val = key[y:y + 4]\r\n temp_val = int.from_bytes(temp_val, byteorder=\"little\")\r\n rot_val = (temp_val \u0026 7) \u0026 0xFF\r\n temp_val = key[x:x + 4]\r\n temp_val = int.from_bytes(temp_val, byteorder=\"little\")\r\n temp_val = ror(temp_val, rot_val) \u0026 0xFFFFFFFF\r\n temp_val += 1\r\n temp_val \u0026= 0xFFFFFFFF\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 8 of 12\n\ntemp_val_x = temp_val.to_bytes(4, byteorder=\"little\")\r\n rot_val = (temp_val \u0026 7) \u0026 0xFF\r\n temp_val = key[y:y + 4]\r\n temp_val = int.from_bytes(temp_val, byteorder=\"little\")\r\n temp_val = ror(temp_val, rot_val) \u0026 0xFFFFFFFF\r\n temp_val += 1\r\n temp_val \u0026= 0xFFFFFFFF\r\n temp_val_y = temp_val.to_bytes(4, byteorder=\"little\")\r\n temp_key = key[:x] + temp_val_x + key[x + 4:]\r\n temp_key = temp_key[:y] + temp_val_y + temp_key[y + 4:]\r\n return temp_key\r\n def crypt_plugin(data: bytes, key: int) -\u003e bytes:\r\n decrypted_plugin = []\r\n for i in range(len(data)):\r\n x = (i \u0026 3)\r\n y = ((i + 1) \u0026 3)\r\n c = key[y * 4] + key[x * 4]\r\n c = (c ^ data[i]) \u0026 0xFF\r\n decrypted_plugin.append(c.to_bytes(1, byteorder=\"little\"))\r\n key = fix_key(key, x * 4, y * 4)\r\n return b''.join(decrypted_plugin)\r\nYiBackdoor manages and parses any plugins by using the structures provided below.\r\n#pragma pack(push, 1)\r\nstruct struct_plugin_execution_info\r\n{\r\n uint32_t unknown_field;\r\n uint32_t plugin_id;\r\n uint8_t do_start_plugin;\r\n char plugin_disk_name[16];\r\n IMAGE_DOS_HEADER* plugin_memory_data;\r\n};\r\n#pragma pack(pop)\r\nstruct plugin\r\n{\r\n custom_string plugin_name;\r\n void *plugin_entry_address;\r\n void *plugin_data;\r\n void *sizeof_plugin_data;\r\n struct_plugin_execution_info *plugin_execution_info;\r\n void *mapped_plugin_memory_address;\r\n};\r\nstruct plugin_manager\r\n{\r\n plugin *plugins[1];\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 9 of 12\n\nuint64_t number_of_plugins;\r\n uint64_t max_allowed_plugins;\r\n};\r\nCode similarities\r\nThreatLabz observed notable code overlaps between YiBackdoor, IcedID, and Latrodectus. IcedID is a malware\r\nfamily that consists of several different components such as a downloader (which has gone through various\r\nupdates in the past), a main module backdoor, and a main module loader. These similarities are present in both\r\ncritical and non-critical parts of YiBackdoor’s code.\r\nThe code similarities between YiBackdoor, IcedID, and Latrodectus are the following:\r\nThe use of identical alphabet charsets to derive bot-specific randomized strings. The identified charsets\r\nare  aeiou and  abcedfikmnopsutw .\r\nThe format (Base64) and length (64-bytes) of YiBackdoor’s configuration decryption key matches the RC4\r\nkeys used by Latrodectus to encrypt its network traffic.\r\nYiBackdoor hooks the Windows API function  RtlExitUserProcess as part of the remote code injection\r\nprocess. This code injection technique is quite uncommon and resembles IcedID’s extensive use of this\r\nWindows API.\r\nAlthough YiBackdoor uses a different approach to calculate the bot ID, part of the process involves the\r\nFowler–Noll–Vo (FVN) hashing algorithm, which is also present in the codebase of IcedID and\r\nLatrodectus.\r\nYiBackdoor includes a Windows GUID list that is not used during execution. The exact same array of\r\nGUIDs is present and utilized in both IcedID and Latrodectus. Hence, the GUIDs in YiBackdoor may be\r\ncode remnants from the latter two malware families.\r\nThe most significant code similarity is the decryption routines for the configuration blob and the plugins.\r\nThe plugins’ decryption routine is identical to the algorithm previously used by IcedID to decrypt the core\r\npayload and configuration data. The figure below shows the algorithm, comparing the decryption routine\r\nfrom a (GZIP) IcedID downloader sample and the plugins’ decryption routine found in YiBackdoor.\r\nFurthermore, the algorithm used to decrypt YiBackdoor’s embedded configuration blob is similar to the\r\naforementioned decryption routine found in IcedID samples.\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 10 of 12\n\nFigure 2: Comparison of YiBackdoor and IcedID GZIP decryption routines.\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 11 of 12\n\nSource: https://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nhttps://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus\r\nPage 12 of 12",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.zscaler.com/blogs/security-research/yibackdoor-new-malware-family-links-icedid-and-latrodectus"
	],
	"report_names": [
		"yibackdoor-new-malware-family-links-icedid-and-latrodectus"
	],
	"threat_actors": [],
	"ts_created_at": 1775434861,
	"ts_updated_at": 1775791223,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/fd850acb9d31b05f8158ba30d069734f39b04611.pdf",
		"text": "https://archive.orkl.eu/fd850acb9d31b05f8158ba30d069734f39b04611.txt",
		"img": "https://archive.orkl.eu/fd850acb9d31b05f8158ba30d069734f39b04611.jpg"
	}
}