Zscaler Blog
Get the latest Zscaler blog updates in your inbox
SubscribeTechnical Analysis of Xloader’s Code Obfuscation in Version 4.3
Key Takeaways
- Xloader is a popular information stealing malware family that is the successor to Formbook.
- In early 2020, Formbook was rebranded as Xloader and the threat actors moved to a malware-as-a-service (MaaS) business model, renting C2 infrastructure to customers.
- Xloader implements different obfuscation methods and several encryption layers to protect critical parts of code and data from analysis.
- The developers behind this malware family continue to update the code with improved obfuscation and encryption layers with each new version that is released.
- In January 2023, Zscaler ThreatLabz identified a new variant of Xloader that identifies itself as version 4.3 with several modifications including additional obfuscation.
Introduction
Xloader is a rebranded version of the Formbook information stealing malware, which has been sold in criminal forums since 2016. The threat actors behind this malware family have been updating and improving the code regularly. In early 2020, the malware was rebranded as Xloader. In early 2022, the threat actors released Xloader version 2.9, which introduced significant improvements to obfuscate the malware code and data including the list of command-and-control (C2) servers. In October 2022, ThreatLabz identified a new Xloader version labeled as 3.9. In January 2023, the threat actors released Xloader version 4.3. Across Xloader versions, the group has modified the malware’s obfuscation techniques including adding numerous layers of encryption with code that recursively decrypts other blocks of code until reaching the core functionality that decrypts the most sensitive data (also encrypted with multiple layers).
This blog post analyzes the encryption algorithms used by Xloader to decrypt the most critical parts of the code and the most important parameters of the malware’s configuration. The analysis is performed on the latest version of Xloader 4.3. ThreatLabz has also created an IDA Python script to decrypt Xloader’s code and data to facilitate analysis.
Technical Analysis
Basic Algorithms and Structures
Formbook and Xloader have evolved along the years with new layers of obfuscation added in each new version. However, there is a set of basic algorithms that have been used since the first versions of Formbook. These algorithms are combined in different ways to decrypt other blocks of code and data. The primary algorithms that are shared between different versions of Xloader are the following:
- Custom RC4: an RC4-based algorithm with two additional layers based on subtraction operations.
- Custom buffer decryption algorithm: a custom algorithm used by Xloader, mainly used to decrypt the first encryption layer of the PUSHEBP data blocks (described in the following sections).
- Custom SHA1: a SHA1 hash is calculated and the result is reversed DWORD by DWORD.
There is also a large global data structure that is used to store important information. When Xloader is executed, this structure is allocated and initialized with information from PUSHEBP data blocks, or from hardcoded values in the code. This structure contains data and encryption keys that are used by other parts of the code. Previous blog posts have referred to this structure as the ConfigObj, with fields that are used to store flags, encryption parameters, pointers, etc. The most important offsets in the ConfigObj structure are identified in Table 1.
Offset |
Description |
Size |
---|---|---|
0x00 |
Value 0xffffffff |
0x04 |
0x04 |
Pointer to a second PE header used for process injection (e.g., explorer.exe) |
0x04 |
0x08 |
Result of RtlGetProcessHeaps() |
0x04 |
0x48 |
Branch ID – XLNG (XORed with 0x3c) |
0x04 |
0x90 |
Pointer to an extended config (located in memory following the ConfigObj structure) |
0x04 |
0x2DC |
Decrypted content of the PUSHEBP block 2, which is an array of API hashes |
0x220 |
0x510 |
Array of library and process names hashes |
0x254 |
0x828 |
Seed of a random number generator (RNG) used by the malware |
0x4 |
0x83C |
Flag indicating that Xloader has generated the parameters necessary for the communications with the C2 |
0x4 |
0x970 |
The Xloader version number (XORed with 0x3c) |
0x4 |
0x990 |
RC4 key used to decrypt other parameters |
0x14 |
0x9A4 |
RC4 key used to decrypt other parameters (this key is the SHA1 of the decrypted content of the PUSHEBP block 5) |
0x14 |
0xCE8 |
RC4 key used to decrypt the C2s list |
0x14 |
Table 1. Important Xloader 4.3 ConfigObj fields.
Encrypted PUSHEBP Data Blocks
Throughout the Xloader code there is a set of encrypted data blocks with the structure shown in Figure 1.
Figure 1. Xloader PUSHEBP encrypted block
This structure is designed to resemble the beginning of a function, but are in fact blocks of encrypted data such as encryption keys and encrypted strings. These data blocks are decrypted using a custom buffer decryption algorithm. Table 2 shows the PUSHEBP encrypted blocks that were found in Xloader 4.3.
PUSHEBP Block Number |
Description |
Size |
---|---|---|
PUSHEBP Block 1 |
Encrypted strings |
0xA82 |
PUSHEBP Block 2 |
API CRCs |
0x222 |
PUSHEBP Block 3 |
Encryption key involved in C2 communications |
0x15 |
PUSHEBP Block 4 |
Encryption key used to decrypt other data |
0x14 |
PUSHEBP Block 5 |
Hardcoded C2 |
0x78 |
PUSHEBP Block 6 |
API CRCs |
0x310 |
Table 2. PUSHEBP encrypted block contents
Encrypted PUSHEBP Functions
Formbook and Xloader also contain functions that decrypt code. An example function to decrypt code (prior to Xloader 2.9) is shown in Figure 2.
Figure 2. Encrypted code in earlier versions of Xloader and Formbook
This code starts with the well-known function preamble push ebp / mov ebp, esp, followed by a tag identifying the encrypted code (0x49909090 in Figure 2), the encrypted code, and an ending tag 0x90909090.
In older versions, the code was decrypted using a custom RC4 algorithm with a key stored in the ConfigObj structure. In Xloader version 2.9, the code retained the custom RC4 algorithm and added a layer of encryption with a second key built on the stack, as shown in Figure 3.
Figure 3. Decryptor of the PUSHEBP functions in Xloader version 2.9
In Xloader version 4.3, there are still PUSHEBP encrypted functions. However, the tags identifying the start and the end of the encrypted code have changed, and now they appear to be random bytes. Figure 4 shows an example of an encrypted function in Xloader 4.3.
Figure 4. Encrypted PUSHEBP function (Xloader version 4.3)
Figure 5 shows the code that decrypts a PUSHEBP function (e.g., the function DecryptCriticalCodeType1_Set_909090909090), which accepts two encrypted tags and an ID value. Inside the decryptor, another 0x14 byte key is constructed dynamically in the sub-function init_key_encrypted_funcs, XORed with a DWORD (XOR key 1) and XORed again with the ID value passed as an argument and another hardcoded DWORD (XOR key 2). The resulting 0x14 byte key will be used to decrypt the encrypted code using Xloader’s custom RC4 algorithm. The same RC4 key is also used to decrypt the encrypted TAG1 and TAG2, which are passed as arguments to the decryptor to derive the starting and ending tags that delimit the encrypted PUSHEBP function.
Figure 5. PUSHEBP function decryption code (Xloader version 4.3)
After the code is decrypted, the delimiter tags are replaced by 90 90 90 90 90 90 (NOP) opcodes. Figure 6 shows an encrypted function before and after being decrypted.
Figure 6. Example PUSHEBP function decrypted (Xloader version 4.3)
Encrypted NO-PUSHEBP Functions
In Xloader version 4.3, a new type of encrypted function without the push ebp / mov ebp esp preamble has also been introduced. The limits of the encrypted code are located by searching for two tags that identify the start and the end of the block. Figure 7 shows the code responsible for determining the limits of a NO-PUSHEBP encrypted function.
Figure 7. NO-PUSHEBP decryption code limit identification and layer 1 decryption (Xloader version 4.3)
The custom Xloader RC4 algorithm is again used to decrypt the encrypted code with two layers and two different keys. The encryption key for the first layer is calculated in another function and stored in the global structure ConfigObj (the value is the result of Xloader’s custom SHA1 algorithm of the decrypted content of the PUSHEBP data block number 5). The encryption key for the second layer is built on the fly: an initial key is built on the stack and XORed with a DWORD (XOR key), producing the final key (Xloader never hardcodes exact values including for encryption keys and delimiter tags). Figure 8 shows the code involved in the decryption of the second layer for one of the encrypted NO-PUSHEBP functions.
Figure 8. NO-PUSHEBP layer 2 decryption (Xloader version 4.3)
After the code is decrypted, the tag before the encrypted code is replaced by the opcodes EC 8B 55 (push ebp / mov ebp esp function preamble). The tag after the encrypted code is replaced by 90 90 90 90 (NOP) opcodes.
Encrypted Configuration
The most important parameters of Xloader’s configuration are stored in the PUSHEBP encrypted data blocks or calculated from hardcoded constants (that are also obfuscated).
Encrypted Strings
The encrypted strings in Xloader are stored in the PUSHEBP data block 1. All the PUSHEBP data blocks have to be decrypted with the custom buffer decryption algorithm as explained before. Once the block is decrypted, the result is a sequential list of items that have the following format:
struct encrypted_string { BYTE length; BYTE content[length]; }
Each string is decrypted with the custom Xloader RC4 algorithm and an encryption key stored at offset 0x990 in the ConfigObj. This RC4 key is generated in the function shown in Figure 9.
Figure 9. Generation of the RC4 key for encrypted strings (Xloader version 4.3)
ThreatLabz has reproduced this algorithm to decrypt the encrypted strings in Xloader 4.3 in Python. The code is available in our GitHub repository here.
Encrypted C2s
The Xloader configuration contains a C2 that is stored separately from another list of C2 domains. The C2 that is stored separately was thought to be Xloader’s real C2 and the other C2s were used as decoys. However, in more recent versions of Xloader, real C2s are likely hidden among the list of decoy C2s. In fact, the author behind Xloader has made significant efforts to protect the list of C2s that were previously thought to be decoys.
Hardcoded C2
The code shown in Figure 10 is responsible for decrypting the hardcoded Xloader C2.
Figure 10. Hardcoded C2 decryption (Xloader version 4.3)
The code in Figure 10 combines a set of operations based on Xloader’s various encryption algorithms and the data stored in the PUSHEBP data blocks to generate the encryption key necessary to decrypt the hardcoded C2 (which is stored in the PUSHEBP data block 5).
C2 List
As previously mentioned, there is another list of C2s that may contain decoy C2s and real C2s. In Formbook and in earlier versions of Xloader, these were stored as an encrypted string with no additional layers of encryption. In Xloader 2.9, the developers introduced an additional custom RC4 layer and Base64 encoding for the C2 list as shown in Figure 11.
Figure 11. Additional encryption layer for the C2 list (Xloader version 2.9)
In Figure 11, the function StringsDecryptor2 decrypts the first layer of the encrypted strings. In version 2.9, an additional Base64 layer is decoded followed by a layer of custom RC4 decryption. In Xloader version 4.3, they have added an additional encryption layer to this C2 list. Figure 12 shows the code responsible for decrypting these new layers.
Figure 12. New encryption layer for Xloader’s C2 list (Xloader version 4.3)
In the new version, the C2 list is first Base64 decoded and a custom RC4 layer is decrypted. A table of 4 byte keys is built on the stack. Each position of the table corresponds to a C2. Once decrypted, this custom RC4 layer is Base64 encoded again. After the new additional decryption layer is complete, Xloader decrypts the same layers as version 2.9: decoding the Base64 layer again and decrypting an additional custom RC4 layer with a key stored in a sub-structure of the ConfigObj. The way that this key (for the last RC4 layer) is generated has also changed in Xloader 4.3. Figure 13 shows the code generating the RC4 key for the last encryption layer of the C2 list.
Figure 13. Key generation for the final encryption layer of the C2 list (Xloader version 4.3)
As shown in Figure 13, the key is built on the stack and it is XORed with a value from the ConfigObj that was initialized previously in a different part of the code. Once this last layer is decrypted, the plaintext C2s are obtained.
Branch ID and Version Number
In previous versions, the Xloader branch ID and version number were sent in the registration packet to the C2. The format of the registration packet (before the last two RC4 layers) was the following:
XLNG |
Bot ID |
Version Number |
Operating System |
Base64(Username) |
XLNG is the tag for the Xloader branch (FBNG was the branch ID for Formbook).
In Xloader version 4.3, the registration packet sent to the C2 includes an additional encryption layer as shown in Figure 14.
Figure 14. Xloader 4.3 Registration packet with additional PKT2 layer
This new encryption layer is marked with the tag PKT2. Communications are performed in the context of explorer.exe (previously injected). However, this registration packet is built in the first injected process (a hollow process) and copied to the context of explorer together with the rest of the injected code. That first injected process exits after injecting into explorer, so the registration packet under the last encryption layer marked with the PKT2 tag is no longer in plaintext after the first injected process terminates.
The PKT2 packet is built in one of the NO-PUSHEBP encrypted functions. That function is decrypted and executed in the context of the first injected process. The code first builds a string with the same format as the registration packet in previous Xloader versions as shown in Figure 15.
Figure 15. Registration packet with the new PKT2 encryption layer
However, as we can see in Figure 15, Xloader 4.3 introduces a NULL character separating the bot ID and the malware version number. This added NULL byte is likely a coding error.
Figure 16 shows how the first registration packet is constructed (marked with XLNG tag) and encrypted with RC4 and encoded with Base64, and then concatenated to the PKT2 tag to generate the final registration packet.
Figure 16. Xloader version 4.3 registration packet construction
However, because of the coding error previously mentioned (an extra NULL character after the bot ID) the final registration data contains just two fields for the XLNG branch and bot ID as shown below:
XLNG |
Bot ID |
The PKT2 tag is then prepended with the RC4 and Base64 encoded data as follows:
PKT2 |
RC4_BASE64(registration_data) |
As a result, the version_number, operating_system and user_name is never sent to the C2. This bug will likely be fixed in future versions of the malware.
Figure 16 also shows that the branch ID and version number are no longer hardcoded unlike previous versions, with the encrypted version number and branch ID decrypted with an XOR key (0x3c).
Tools
Zscaler ThreatLabz has developed an IDA script to decrypt the Xloader’s encrypted code. The code is available in our GitHub tools repository here.
Conclusion
Since its inception, the Formbook and Xloader malware families has been a prominent threat. The threat actors behind it continue to update and improve the malware code in an effort to hinder analysis. In the most recent version, the threat actors increased the level of complexity yet again with additional layers of encryption for critical parts of the code and important data. However, Zscaler researchers have been able to unravel these obfuscation layers and analyze the key components of the malware code.
Cloud of Sandbox Detection
Zscaler's multilayered cloud security platform detects Xloader and Formbook indicators at various levels, as shown below:
Indicators Of Compromise (IOCs)
Variant |
Version |
SHA256 |
Botnet |
---|---|---|---|
XLoader |
4.3 |
9e1b4f2d408e187ca641c0c16269069d0acabe5ae15514418726fbc720b33731 |
6qne |
XLoader |
4.3 |
f55ce0741ed4615bae5646c644b3a971323ac344b12693495d5749c688d5d489 |
6qne |
XLoader |
4.3 |
3bd86f3906f59f627bf65664d2bfacf37a29dbaafeae601baf5eeb544396f26c |
6qne |
XLoader |
3.9 |
8e12b85676aaf45a93c91e2db2065151e19f184907da6d85701ac3b13d0e6052 |
nvp4 |
XLoader |
3.9 |
6a726fb5c93adbae0f3061b40b19745587c0114deb86bd72c90acdd69242cbe0 |
nvp4 |
Network Indicators
Type |
Domain |
---|---|
Harcoded C2 domain |
jourmoe[.]com |
C2 list domain |
060jinbo[.]com |
C2 list domain |
10086253[.]vip |
C2 list domain |
117ygh9x[.]com |
C2 list domain |
365-8119[.]com |
C2 list domain |
365heji[.]com |
C2 list domain |
4tx[.]ru |
C2 list domain |
667fm[.]com |
C2 list domain |
991-touring[.]info |
C2 list domain |
abttt[.]win |
C2 list domain |
adacaranya[.]com |
C2 list domain |
allforfun[.]online |
C2 list domain |
allison2patrick[.]online |
C2 list domain |
applicationsdown[.]store |
C2 list domain |
apsocreto[.]online |
C2 list domain |
avdeeva[.]info |
C2 list domain |
betfury-platform[.]net |
C2 list domain |
bilpoinsaat[.]net |
C2 list domain |
bocc[.]live |
C2 list domain |
bookinbournemouth[.]co[.]uk |
C2 list domain |
botanica-online[.]ru |
C2 list domain |
byfuture[.]biz |
C2 list domain |
canlicerrahi[.]xyz |
C2 list domain |
ceu84g[.]com |
C2 list domain |
chiyiqian[.]net |
C2 list domain |
christmatoy[.]com |
C2 list domain |
cinemamaxz[.]com |
C2 list domain |
coffeelectro[.]online |
C2 list domain |
dedmorozvidos[.]store |
C2 list domain |
difozaa[.]life |
C2 list domain |
dugebitv4[.]xyz |
C2 list domain |
eatgre[.]wiki |
C2 list domain |
expertponto[.]com |
C2 list domain |
farmanow[.]xyz |
C2 list domain |
flippingfrenzy[.]com |
C2 list domain |
g2fm[.]co[.]uk |
C2 list domain |
ginaandhipa[.]com |
C2 list domain |
graciesvoice[.]info |
C2 list domain |
guzmanmodels[.]com |
C2 list domain |
habka[.]online |
C2 list domain |
hal-skincare[.]com |
C2 list domain |
hiufouwnwk[.]shop |
C2 list domain |
hjiqa[.]com |
C2 list domain |
huifeng-tech[.]com |
C2 list domain |
identowel[.]com |
C2 list domain |
inigrey[.]com |
C2 list domain |
ituyiut[.]wang |
C2 list domain |
jimtrosper[.]com |
C2 list domain |
kajainterior[.]com |
C2 list domain |
loaddown[.]vip |
C2 list domain |
mgconsultantlogistics[.]com |
C2 list domain |
myif471ok9ipidk2kkl[.]xyz |
C2 list domain |
najdlegend1[.]com |
C2 list domain |
nnhuigou[.]com |
C2 list domain |
ogei[.]app |
C2 list domain |
poweroffer[.]net |
C2 list domain |
realtxt[.]co[.]uk |
C2 list domain |
seeword[.]site |
C2 list domain |
solutionsquik[.]net |
C2 list domain |
themas5erofssuepnse[.]cyou |
C2 list domain |
uevj[.]win |
C2 list domain |
vowlashes[.]co[.]uk |
C2 list domain |
wanknumbers[.]co[.]uk |
C2 list domain |
wsavxrg[.]shop |
C2 list domain |
zzaen[.]com |
References
- https://www.zscaler.com/blogs/security-research/analysis-xloaders-c2-network-encryption
- https://any.run/cybersecurity-blog/xloader-formbook-encryption-analysis-and-malware-decryption/
- https://www.netscout.com/blog/asert/formidable-formbook-form-grabber
- https://www.fortinet.com/blog/threat-research/deep-analysis-new-formbook-variant-delivered-phishing-campaign-part-I?utm_source=blog&utm_campaign=deep-analysis-new-formbook-variant-delivered-phishing-campaign-part-I
- https://www.fortinet.com/blog/threat-research/deep-analysis-formbook-new-variant-delivered-phishing-campaign-part-ii?utm_source=blog&utm_campaign=deep-analysis-formbook-new-variant-delivered-phishing-campaign-part-ii
- https://www.fortinet.com/blog/threat-research/deep-analysis-formbook-new-variant-delivered-in-phishing-campaign-part-iii
- https://www.fireeye.com/blog/threat-research/2017/10/formbook-malware-distribution-campaigns.html
- https://research.checkpoint.com/2021/top-prevalent-malware-with-a-thousand-campaigns-migrates-to-macos/
- https://research.checkpoint.com/2021/time-proven-tricks-in-a-new-environment-the-macos-evolution-of-formbook/
- https://research.checkpoint.com/2021/stealth-is-never-enough-or-revealing-formbook-successors-cc-infrastructure/
- https://research.checkpoint.com/2022/xloader-botnet-find-me-if-you-can/
Was this post useful?
Get the latest Zscaler blog updates in your inbox
By submitting the form, you are agreeing to our privacy policy.