Analysis of a 3-stage malware sample resulting in a dcrat infection. The initial sample contains 2 payloads which are hidden by obfuscation. This analysis will demonstrate methods for manually uncovering both payloads and extracting the final obfuscated C2.

Tooling

  • Detect-it-easy - Quick initial analysis of pe-files
  • Dnspy - Analysis, decompilation and debugging of .NET files
  • Cyberchef - Interactive tool for prototyping decoders

Samples

The malware file can be found here
And a copy of the decoding scripts here

Initial Analysis

The initial file can be downloaded via Malware Bazaar and unzipped using the password infected

detect-it-easy is a great tool for the initial analysis of the file.

Pe-studio is also a great option but we personally prefer the speed and simplicity of detect-it-easy

Detect-it-easy revealed that the sample is a 32-bit .NET-based file.
- The protector Confuser(1.X) has also been recognized.

Initial analysis using Detect-it-easy

Before proceeding, we checked the entropy graph for signs of embedded files.

I used this to determine if the file was really dcrat, or a loader for an additional payload containing dcrat.

In my experience, large and high entropy sections often indicate an embedded payload. Indicating that the file being analyzed is a loader.

Entropy Analysis of the Initial .exe file - Showing a large section of high entropy

The entropy graph revealed that a significant portion of the file has an entropy of 7.98897 (This is very high, the maximum value is 8).

This was a strong indicator that the file was a loader and not the final dcrat payload.

To analyze the suspected loader, we moved on to Dnspy

Dnspy Analysis

Utilizing Dnspy, we saw that the file had been recognized as rewrwr.exe and contained references to confuserEx. Likely this means the file is obfuscated using ConfuserEx and might be a pain to analyze.

Dnspy overview of the initial file

To peek at the code being executed - we right-clicked on the rewrwr.exe name and selected go to entry point

This would give me a rough idea of what the actual executed code might look like.

The file immediately creates an extremely large array of unsigned integers. This could be an encrypted array of integers containing bytecodes for the next stage (further suggested by a post-array reference to a Decrypt function)

Viewing Encrypted Arrays using Dnspy
Using Dnspy to locate and view the Decryption function

The initial array of uints was so huge that it was too large to display in Dnspy.

Given the size, we suspected this array was the reason for the extremely high entropy previously observed with detect-it-easy

After the array, there is again code that suggests the array's contents are decrypted, then loaded into memory with the name koi

Given the relative simplicity of the code so far - we suspected the encryption was not complex, but still, we decided not to analyze it this time.

Instead, we considered two other approaches

  • Set a breakpoint after the Decrypt call and dump the result from memory.
  • Set a module breakpoint to break when the new module is decrypted and loaded. Then dump the result into a file.

I took the second approach, as it is reliable and useful for occasions where the location of decryption and loading isn't as easy to find. (Typically it's more complicated to find the Decryption function, but luckily in this case it was rather simple)

Either way, we decided to take the second approach.

Extracting Stage 2 using Module Breakpoints

To extract stage 2 - We first created a module breakpoint which would break on all module loads.

To do this, we first opened the module breakpoints window.

Debug -> Windows -> Module Breakpoints

How to set a module breakpoint using Dnspy

We then created a module breakpoint with two wildcards. This will break on all new modules loaded by the malware.

Module breakpoint to break on all loaded modules

We then executed the malware using the start button

Dnspy button to Start or Continue execution

We can accept the default options.

Default options for Dnspy Debugging are ok

Immediately, a breakpoint was hit as mscorelib.dll was being loaded into memory. This is a default library and we ignored it by selecting Continue

Dnspy alert when a module breakpoint has been triggered
Once executed - the Continue button can be used to resume the execution

The next module loaded was the original file being analyzed, which in this case can be safely ignored.

After that, a suspicious-looking koi module was loaded into memory. (If you don't have a modules window, go to debug -> windows -> modules)

How to View Currently Loaded Modules in Dnspy

Here we could see the koi module had been loaded.

Example of a suspicious module being loaded into memory

At this point, we saved the koi module to a new file using Right-Click -> Save Module.

Dnspy Option for Saving a Loaded Module

We can then exit the debugger and move on to the koi.exe file.

Analysis of koi.exe

We can observe that koi.exe is another 32-bit .net file containing references to the ConfuserEx Obfuscator

Initial Analysis of a .NET file using Detect-it-easy

This time it does not seem to contain any large encrypted payloads.

Although the overall entropy is low, large portions of the graph are still suspiciously flat. This can sometimes be an indication of text-based obfuscation.
Entropy Analysis when a text-based obfuscation is used

We can now go ahead and open koi.exe in Dnspy.

This time there was another rewrwr.exe name and references again to ConfuserEx

File Overview with Dnspy

Koi.exe does not have a defined Entry Point. Instead we can begin analysis with the rewrwr namespace (located in the side panel). This namespace contains one Class named Form1

The Form1 class immediately called Form1_Load, which itself immediately referenced a large string that appeared to be base64 encoded.

Example of Entry Point Containing Obfuscated Data

Despite appearing to be base64 - the text does not successfully code using base64. This was an indicator that some additional tricks or obfuscation had been used.

Attempting to Decode Base64 Using Cyberchef - Initially fails due to additional obfuscation

I decided to jump to the end of the base64-looking data - Noting that there were about 50 large strings in total. Each titled Str1 str2 ... all the way to Str49

It was very likely these strings were the cause of the flat entropy graph we viewed earlier. Text based obfuscation tends to produce lower entropy than "proper" encryption
Example of another "base64" obfuscated string in Dnspy

At the end of the data was the decoding logic. Which appeared to be taking the first character from each string and adding it to a buffer.

Decoding Logic Utilised by the Dcrat Loader - Viewed with Dnspy

After the buffer is filled, it is base64 decoded and loaded into memory as an additional module.

Example of Decoded Contents being loaded into Memory 

In order to confirm the theory on how the strings are decoded, we can take the first character from the first 5 strings and base64 decode the result.

Brief Overview of the Additional obfuscation used
An example of this decodes using base64


This confirmed the theory of how the malware was decoding the next stage.

In order to extract the next module, we can copy out the strings and place them into a Python script.

Python Script to Decode the Dcrat Encoded Strings

Running this script creates a third file. Which for simplicity's sake is named output.bin

The file is recognized as a 32-bit .NET file. So the decoding was successful.

Initial Analysis of Third .NET File using Detect-it-easy

Stage 3 - Analysis

We have now obtained a stage 3 file - which again is a 32-bit .NET executable.

Luckily this time, there are no references to ConfuserEx or other obfuscators.

Initial Analysis of Third .NET File using Detect-it-easy

The entropy is reasonably normal - and does not contain any large flat sections that can indicate a hidden payload.

The lack of ConfuserEx and relatively normal entropy - is an indication that this may be the final payload.

Moving on to Dnspy, the file is recognized as IvTdur2zx


Despite the lack of ConfuserEx, the namespaces and class names look obfuscated in some way.

Dnspy view of Obfuscated Functions in the Final Payload

We can jump to the Entry Point for further analysis.

The first few functions are mostly junk - but there are some interesting strings referenced throughout the code.

For example - references to a .bat script being written to disk

Dnspy Overview of Strings in The .NET File

Since the strings were largely plaintext and not obfuscated - At this point we can use detect-it-easy to look for more interesting strings contained within the file.

This reveals a reference to DCrat - as well as some potential targeted applications (discord, steam, etc)

Overview of some plaintext strings contained in the malware

At that point, you could probably assume the file was DCrat and an info stealer - but we wanted to continue my analysis until I'd found the C2.

In the above screenshot, we noticed some interesting strings that looked like base64 encoding + gzip (the H4sIAA* is a base64-encoded gzip header).

So we attempted to analyze these using CyberChef.

The first resulted in what appeared to be a base64 encoded + reversed string.

This was strongly hinted by the presence of == at the start.

Cyberchef - Base64 + Gzip + Additional Obfuscation

After applying a character reverse + base64 decode. We were able to obtain a strange dictionary as well as a mutex of Wzjn9oCrsWNteRRGsQXn + some basic config.

This was cool but still no C2.

Cyberchef - Decoding the "base64" strings

I then tried to decode the second base64 blob shown by detect-it-easy.
But the result was largely junk.

Cyberchef - Failed Decoding of Additional "base64" strings

Attempting to reverse + base64 decode returned no results.

Cyberchef - Additional failures when decoding strings

At this point - we decided to search for the base64 encoded string to see where it was referenced in the .net code.

Using Dnspy to search for string cross-references (x-refs)

This revealed an interesting function showing multiple additional functions acting on the base64 encoded data.

In total, there are 4 functions ( M2r.957 , M2r.i6B, M2r.1vX, M2r.i59 ) which are acting on the encoded data.

Viewing Additional layers of string obfuscation using Dnspy

The first function M2r.957 is a wrapper around another function M2r.276 which performed the base64 and Gzip decoding.

Delving Deeper into an "obfuscation" function. 

The next function M2r.i6B took the previously obtained string and then performed a Replace operation based on a Dictionary

Cyberchef View of Obfuscated String
Interesting to note - is that the Value is replaced with the Key and not the other way around as you might expect.
Dnspy - Overview of Dictionary-based String Replace

Based on the previous code, the input dictionary had something to do with a value of SCRT

Analysing additional string obfuscation using Dnspy

Suspiciously - there was an SCRT that looked like a dictionary in the first base64 string that was decoded.

Cyberchef - locating the dictionary used for decoding

So we obtained that dictionary and prettied it up using Cyberchef to remove all of the \ escapes.

Cleaning up escape characters with Cyberchef

We then created a partial Python script based on the information we had so far. (I'll post a link at the end of this post)

Python Script used to decode the string

Executing this result and printing the result - we were able to obtain a cleaner-looking string than before.

Here's a before and after

Before applying additional text-replacement
After applying additional text-replacement

It was probably safe to assume this string was reversed + base64 encoded, but we decided to check the remaining two decoding functions just to make sure.

M2r.1vX was indeed responsible for reversing the string.

Dnspy - Analysis of additional obfuscation (string reverse)

M2r.i59 was indeed responsible for base64 decoding the result.

Dnspy - Analysis of additional obfuscation (base64 encoding)

So we then added these steps to my Python script.

Updated Python Script for decoding Dcrat

And executed to reveal the results - successful C2!
http://battletw[.]beget[.]tech/

Successfully obtaining the decoded C2 using Python. 

(The URLs contained some base64 reversed/encoded strings and were not very interesting)

This C2 domain had only 2/85 hits on VirusTotal

At this point, we had obtained the C2 and decided to stop my analysis.

In a real environment, it would be best to block this domain immediately in your security solutions. Additionally, you could review the previous string dumps for process-based indicators that could be used to hunt signs of successful execution.

Additionally, you could try to derive some Sigma rules from the string dumps or potentially use the C2 URL structure to hunt through proxy logs.