{
	"id": "63ed167d-0dab-456d-947f-48cd5297ff3e",
	"created_at": "2026-04-06T00:21:34.158882Z",
	"updated_at": "2026-04-10T13:12:06.206014Z",
	"deleted_at": null,
	"sha1_hash": "e6778fdd79d8571c2eb00df2870bcaa6c965436b",
	"title": "Technical Analysis of Xloader Versions 6 and 7 P2 | ThreatLabz",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 164852,
	"plain_text": "Technical Analysis of Xloader Versions 6 and 7 P2 | ThreatLabz\r\nBy ThreatLabz\r\nPublished: 2025-02-13 · Archived: 2026-04-05 14:30:24 UTC\r\nC2 decryption\r\n \r\nDecoy C2 servers\r\nXloader shares many characteristics as Formbook, its predecessor, including the use of a decoy C2 list and a real\r\nC2 server, which are encrypted differently and stored separately within the binary. The purpose of the decoys is to\r\ngenerate network traffic to legitimate domains to disguise real C2 traffic. This approach has been used by other\r\nmalware families in the past such as Pushdo. Note that the so-called decoy list can also include actual C2 servers,\r\nbut for simplicity, we'll continue to refer to these as the \"decoy list\" and \"real\" C2 server in this blog, since the\r\nformer still primarily contains legitimate domains.\r\nThe figure below shows a high-level description of the process that Xloader uses to decrypt the decoy C2s.\r\nFigure 1: The functions that decrypt the decoy C2 servers in Xloader 6.2.\r\nhttps://www.zscaler.com/blogs/security-research/technical-analysis-xloader-versions-6-and-7-part-2\r\nPage 1 of 4\n\nThe Xloader decoy C2s are encrypted with three layers. The keys needed for decryption are generated by various\r\nfunctions within the malware code and are stored in global configuration structures as described below.\r\nThe first decryption key for the decoy C2 is constructed dynamically by one of the encrypted  NOPUSHEBP\r\nfunctions. Five DWORDs are combined to construct an initial 20-byte seed. This seed is then XOR’ed with a\r\nhardcoded DWORD XOR key and an additional hardcoded 1-byte XOR key. The resulting 20-byte key is stored\r\nin the global configuration structure.\r\nSimilarly, the second key of the decoy C2 is generated by another encrypted  NOPUSHEBP function. Once again, 5\r\nDWORDs are initialized on the stack and XOR’ed with a DWORD XOR key retrieved from the global\r\nconfiguration structure. This DWORD XOR key was previously calculated and stored in the global configuration\r\nstructure by another function.\r\nThe list of decoy C2s is stored among the encrypted strings with indexes that typically range from 1 to 63\r\n(inclusive). Another function implements the process to retrieve and decrypt a specific decoy C2 server based on\r\nits index using Xloader’s standard string encryption algorithm that we described in Part 1 of this blog series. The\r\nresult of removing this first layer is the encrypted second layer, which is a Base64 encoded string.\r\nThe second layer is Base64 decoded and decrypted with Xloader’s RC4 and subtraction algorithm using the first\r\nkey XOR’ed with the index of the decoy C2. The third and final layer uses Xloader’s RC4 and subtraction\r\nalgorithm using the second key.\r\nBelow is a Python implementation of Xloader’s decoy C2 decryption algorithm:\r\n# Get the necessary seeds and xor keys from the binary\r\nrc4_key_1_seed = get_rc4_key_1_seed()\r\nrc4_key_1_xor = get_rc4_key_1_xor()\r\nrc4_key_2_seed = get_rc4_key_2_seed()\r\nrc4_key_2_xor = get_rc4_key_2_xor()\r\n# Calculate final keys\r\ndecoy_C2s_key_1 = xor(rc4_key_1_seed, rc4_key_1_xor)\r\ndecoy_C2s_key_2 = xor(rc4_key_2_seed, rc4_key_2_xor)\r\n# Decrypt the decoy C2\r\nenc_C2 = decrypt_encrypted_string_by_index(target_C2_index)\r\nb64dec = base64.b64decode(enc_C2)\r\nkey1 = xor(decoy_C2s_key_1, target_C2_index)\r\ndec = rc4_sub(b64dec, key1)\r\ndecrypted_c2 = rc4_sub(dec, decoy_C2s_key_2)\r\nLegitimate C2 servers\r\nhttps://www.zscaler.com/blogs/security-research/technical-analysis-xloader-versions-6-and-7-part-2\r\nPage 2 of 4\n\nFollowing the C2 decoy list, is another encrypted string located at index  64 . This encrypted string contains the\r\nreal Xloader C2, which is decrypted using a similar algorithm but with different keys. First, the encrypted string at\r\nindex  64 is retrieved and decrypted. After decryption, the result is Base64 decoded, and a new key is\r\ndynamically built as follows:\r\n1. A 20-byte seed is constructed.\r\n2. This seed is XOR’ed with a hardcoded 1-byte XOR key.\r\n3. The seed is then XOR’ed with a hardcoded DWORD XOR key.\r\n4. Finally, the seed is XOR’ed with another hardcoded 1-byte XOR key.\r\nThe resulting 20-byte key is then used to decrypt the first encryption layer of the real C2 using RC4 and\r\nsubtraction.\r\nThe next encryption layer of the real C2 is decrypted using another function: \r\n1. A 20-byte seed is constructed. \r\n2. This seed is then XOR’ed with a hardcoded 1-byte XOR key. \r\n3. The resulting key is used to decrypt the final RC4 and subtraction layer of the real C2.\r\nBelow is a Python implementation for decrypting Xloader’s real C2:\r\n# Get the necessary seeds and xor keys from the binary\r\nrc4_key_1_seed = get_rc4_key_1_seed()\r\nrc4_key_1_xor1byte = get_rc4_key_1_xor1byte()\r\nrc4_key_1_xor4bytes = get_rc4_key_1_xor4bytes()\r\nrc4_key_2_seed = get_rc4_key_2_seed()\r\nrc4_key_2_xor = get_rc4_key_2_xor()\r\n# Calculate the final keys\r\nreal_C2_key = xor(rc4_key_1_seed, rc4_key_1_xor1byte)\r\nreal_C2_key = xor(real_C2_key, rc4_key_1_xor4bytes)\r\nreal_C2_key_2 = xor(rc4_key_2_seed, rc4_key_2_xor)\r\n# Decrypt the real C2\r\nstring_64 = decrypt_encrypted_string_by_index(64)\r\nb64dec = base64.b64decode(string_64)\r\ndec = rc4_sub(b64dec, real_C2_key)\r\ndec = rc4_sub(dec, real_C2_key_2)\r\nif dec.startswith(b'www'):\r\n return dec.decode()\r\nNote that all of the real C2 servers observed by ThreatLabz (after decryption) start with a www subdomain. In\r\ncontrast, the decoy C2 servers embedded in the malware do not start with a www subdomain, but that prefix is\r\nadded by Xloader prior to establishing network communications.\r\nC2 URL path\r\nhttps://www.zscaler.com/blogs/security-research/technical-analysis-xloader-versions-6-and-7-part-2\r\nPage 3 of 4\n\nIn Xloader versions 6 and earlier, the real C2 string included a domain and a path. However, each decoy C2 string\r\nonly consisted of a domain. Therefore, Xloader appended the real C2’s path to each decoy domain prior to\r\ngenerating network traffic.\r\nIn Xloader version 7.5, each decoy C2 and real C2 has its own URL path, and the decryption function now\r\nincludes an additional argument to return either the domain or the path of the decrypted C2 server. This process\r\nuses a 20-byte key combined with the C2’s index to decrypt each 4 character C2 path via Xloader’s RC4 and\r\nsubtraction algorithm.\r\nNetwork protocol\r\nWe previously described Xloader’s network protocol and a new encryption layer that was added to the malware’s\r\nregistration packet. In Xloader 4.3, we discovered that there was a bug that caused the registration packet to be\r\ntruncated because of the improper placement of a NULL character. However, this issue has since been resolved in\r\nversion 6, with the packet now formatted correctly.\r\nExplore more Zscaler blogs\r\nSource: https://www.zscaler.com/blogs/security-research/technical-analysis-xloader-versions-6-and-7-part-2\r\nhttps://www.zscaler.com/blogs/security-research/technical-analysis-xloader-versions-6-and-7-part-2\r\nPage 4 of 4\n\nformer still primarily The figure below contains shows a high-level legitimate domains. description of the process that Xloader uses to decrypt the decoy C2s.\nFigure 1: The functions that decrypt the decoy C2 servers in Xloader 6.2.\n   Page 1 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://www.zscaler.com/blogs/security-research/technical-analysis-xloader-versions-6-and-7-part-2"
	],
	"report_names": [
		"technical-analysis-xloader-versions-6-and-7-part-2"
	],
	"threat_actors": [],
	"ts_created_at": 1775434894,
	"ts_updated_at": 1775826726,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/e6778fdd79d8571c2eb00df2870bcaa6c965436b.pdf",
		"text": "https://archive.orkl.eu/e6778fdd79d8571c2eb00df2870bcaa6c965436b.txt",
		"img": "https://archive.orkl.eu/e6778fdd79d8571c2eb00df2870bcaa6c965436b.jpg"
	}
}