HomeMalware Analysis
XLoader/FormBook: Encryption Analysis and Malware Decryption 
HomeMalware Analysis
XLoader/FormBook: Encryption Analysis and Malware Decryption 

Today ANY.RUN’s malware analysts are happy to discuss the encryption algorithms of XLoader, also known as FormBook. And together we’ll decrypt the stealer’s strings and C2 servers. 

Xloader is a stealer, the successor of FormBook. However, apart from the basic functionality, the unusual approaches to encryption and obfuscation of internal structures, code, and strings used in XLoader are also of interest. Let’s take a detailed look at the encryption of strings, functions, and C2 decoys. 

Encryption in XLoader

First, we should research 3 main cryptographic algorithms used in XLoader. These are the modified algorithms: RC4, SHA1, and Xloader’s own algorithm based on a virtual machine. 

Analyze Xloader fast and easy. Try ANY.RUN sandbox.  

Get started with a free account 

The modified RC4 algorithm 

The modified RC4 algorithm is a usual RC4 with additional layers of sequential subtraction before and after the RC4 call. In the code one layer of subtractions looks like this:

  # transform 1
      for i in range(len(encbuf) - 1, 0, -1):
          encbuf[i-1] -= encbuf[i]

      # transform 2
      for i in range(0, len(encbuf) -1):
          encbuf[i] -= encbuf[i+1]

The ciphertext bytes are subtracted from each other in sequence from right to left. And then they go from left to right. In the XLoader code, it looks like this:

Function performing RC4 encryption
Function performing RC4 encryption

The modified SHA1 algorithm 

The SHA1 modification is a regular SHA1, but every 4 bytes are inverted:

def reversed_dword_sha1(self, dat2hash):
      sha1Inst = SHA1.new()
      sha1Inst.update(dat2hash)
      hashed_data = sha1Inst.digest()
      result = b""
      for i in range(5):
          result += hashed_data[4*i:4*i+4][::-1]
      return result

Xloader’s own virtual machine algorithm 

The last algorithm is a virtual machine that generates one to four bytes of plaintext, depending on the current byte of the ciphertext. Usually, this algorithm is used as an additional encryption layer, which will be discussed later. The entry of the VM decryption routine looks like this:

An example of transformations in a virtual machine’s decryption routine
An example of transformations in a virtual machine’s decryption routine

Decrypting XLoader Strings

Next, let’s investigate how string encryption works in XLoader. All byte arrays containing encrypted strings or key information are ​​located in special kinds of blobs.

An example of a blob with encrypted data
An example of a blob with encrypted data

As you can see in the screenshot above, this blob is a function that returns a pointer to itself, below this function are the bytes you are looking for.

In order to decrypt strings, first a key is generated. The key is generated from 3 parts, to which the above-described functions are applied.

Key generation function to decrypt strings
Key generation function to decrypt strings

Here K1_blob, K2_blob, and K3_blob are functions that return data from the blocks described above, and the string length is an argument for them. 

The functions VM_Decrypt, RC4_with_sub_Layer and sha1_* are modified algorithms that we discussed earlier.

Schematically, the key generation algorithm can be represented by the following diagram. 

Scheme of key generation to decrypt strings

Here E and K are the data and the key that is fed to the input of the RC4 function, respectively, and K1, K2, and K3 are the data obtained from the K1_blob, K2_blob, and K3_blob functions.

The strings themselves are also stored as a blob and are covered by two layers of encryption:  

  • VM_decrypt
  • RC4 that uses the key obtained above. 

At the same time, RC4 is not used for the whole blob at once.

After removing the first layer, the encrypted strings themselves are stored in the format:

encrypted string length – encrypted string

Consequently, to decrypt the strings, we need to loop through this structure and consistently decrypt all the strings.

Function for decrypting strings
Function for decrypting strings

Below is an example of the encrypted data after stripping the first layer. Length/string pairs for the first 3 encrypted strings are highlighted in red.

The first 3 encrypted strings
The first 3 encrypted strings

The same strings after decryption:

The first 3 lines after decoding
The first 3 lines after decoding

Along with the encrypted strings, C2 decoys are also stored there. They are always located at the end of all decrypted strings, beginning and ending with the f-start and f-end strings.

Decrypting XLoader’s C2 Servers

Next, let’s see how the main C2 encryption works. The main C2 is located elsewhere in the code, so you can get it separately from the C2 decoys. 

Code snippet demonstrating C2 decryption.
Code snippet demonstrating C2 decryption.

To decrypt it, as well as to decrypt the strings, 3 keys are used. The C2 decryption scheme is shown below: 

  • EC2 is the encrypted C2
  • DC2 is the decrypted C2

The algorithm itself is a 3 times sequential application of the RC4 algorithm with 3 different keys.

C2 decoys’ decryption scheme
C2 decoys’ decryption scheme

Also, in newer versions of XLoader C2 decoys, which usually lie along with all the other strings, turn out to be covered by an additional layer of encryption, and, at first glance, it is completely unclear where exactly the decryption of these strings occurs. 

Since XLoader has several entry points, each responsible for different non-intersecting functionality, with many functions turning out to be encrypted.

The C2 decoys are decrypted inside the XLoader injected into Explorer.exe. And in this case, it is passed to netsh.exe, which also contains XLoader via APC injection. 

The C2 life cycle in different XLoader modules
The C2 life cycle in different XLoader modules

In order to understand how a C2 decoy is encrypted, first of all, you need to understand how the functions are encrypted. 

It’s actually quite simple. RC4 is used as the encryption algorithm. This time, the key is hardcoded and written right in the code and then xored with the 4-byte gamma.

After that, you should find pointers to the start and end of the function. This is how you do it:  a unique 4-byte value is placed at the beginning and end of each encrypted function. The XLoader looks for these values and gets the desired pointers.

Code snippet demonstrating the decryption of the function
Code snippet demonstrating the decryption of the function

Then the function is decrypted, control is given to it, and it similarly searches for and decrypts the next function. This happens until the function with the main functionality is decrypted and executed. So, functions should be decrypted recursively.

The key to decrypting C2 decoys consists of 2 parts and is collected separately at two different exit points. One exit point gets the 20-byte protected key, and the second gets the 4-byte gamma to decrypt the key.

Example of extracted XLoader malware configuration

Applying the above algorithms we can extract the configuration from Xloader, including C2, C2 decoys,  and strings. For your convenience, we have integrated automatic extraction of the Xloader configuration into ANY.RUN interactive sandbox — just run the sample and get all the IOCs in seconds. 

Extracted malware configuration in ANY.RUN
Extracted malware configuration in ANY.RUN

Extracted malware configuration in ANY.RUN
Extracted malware configuration in ANY.RUN

Examples of successfully executed samples:

https://app.any.run/tasks/f6d29aa7-4054-44b6-b4cc-61684742da88/

https://app.any.run/tasks/aa804b50-2c11-447e-a5a9-709b83634aa0/

https://app.any.run/tasks/8bcca55f-99ae-4b8d-b60e-226562068d9a/

Sum it up

In this article, we discussed the encryption in xLoader stealer. It is based on both add-ons to existing algorithms and self-written algorithms.

The main tricky part of the decryption process is the key generation and the fact that the XLoader functionality is split into modules that can be run in different processes. Because of this, in order to extract strings, we have to decrypt the executable code, among other things.

Fortunately, ANY.RUN is already set up to detect this malware automatically, making the relevant configuration details just a click away.

If you want to read more content like this, check out our analysis of the Raccoon Stealer, CryptBot, or Orcus RAT.

Appendix

Analyzed files

Sample with new C2 decoys encryption

TitleDescription
NameMT10320221808-004. pdf.exe
MD5b7127b3281dbd5f1ae76ea500db1ce6a
SHA16e7b8bdc554fe91eac7eef5b299158e6b2287c40
SHA256726fd095c55cdab5860f8252050ebd2f3c3d8eace480f8422e52b3d4773b0d1c

Sample without C2 decoys encryption

TitleDescription
NameTransfer slip.exe
MD51b5393505847dcd181ebbc23def363ca
SHA1830edb007222442aa5c0883b5a2368f8da32acd1
SHA25627b2b539c061e496c1baa6ff071e6ce1042ae4d77d398fd954ae1a62f9ad3885

What do you think about this post?

14 answers

  • Awful
  • Average
  • Great

No votes so far! Be the first to rate this post.

1 comments