Dcrat Deobfuscation - How to Manually Decode a 3-Stage .NET Malware

Manual analysis and deobfuscation of a .NET based Dcrat. Touching on Custom Python Scripts, Cyberchef and .NET analysis with Dnspy.

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.

If you've ever wondered how to analyse .net malware - this might be the blog post for you.


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


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 it using the password infected

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

Pe-studio is also a great option but I 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, I 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 is a loader and not the final dcrat payload.

In order to analyze the suspected loader, I moved on to Dnspy

Dnspy Analysis

Utilizing Dnspy, I 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

In order to peek at the code being executed - I 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, I 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 - I suspected the encryption was not complex, but still, I decided not to analyze it this time.

Instead, I 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 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, I decided to take the second approach.

Extracting Stage 2 using Module Breakpoints

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

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

Debug -> Windows -> Module Breakpoints

How to set a module breakpoint using Dnspy

I 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

I then executed the malware using the start button

Dnspy button to Start or Continue execution

I accepted 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 I ignored it by selecting Continue

Dnspy alert when a module breakpoint has been triggered
Once executing - the Continue button can be used to resume 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 I could see the koi module had been loaded.

Example of a suspicious module being loaded into memory

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

Dnspy Option for Saving a Loaded Module

I then exited the debugger and moved on to the koi.exe file.

Analysis of koi.exe

The koi.exe file is another 32-bit .net file. Containing references to ConfuserEx

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

I moved on and opened koi.exe using dnspy.

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

File Overview with Dnspy

There was no Entry point available, so I started analysis with the rewrwr namespace in the side panel. This namespace contained one Class named Form1

The Form1 class immediately called Form1_Load, which itself immediately referenced a large string that appears 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 had been filled, it was 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 were decoded, I took the first character from the first 5 strings and base64 decoded the result.

Brief Overview of the Additional obfuscation used
Example of this decodes using base64

This confirmed my theory on how the malware was decoding the next stage.

In order to extract the next module, I copied out the strings and put them into a Python script.

Python Script to Decode the Dcrat Encoded Strings

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

The file was 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

Now I had obtained a stage 3 file - which again was a 32-bit .net executable.

This time - no references to ConfuserEx

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

The entropy was reasonably normal - and did not contain any large flat sections that may indicate a hidden payload.  

The lack of ConfuserEx and relatively normal entropy - was 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 terrible.

Dnspy view of Obfuscated Functions in Final Payload

I then went to the Entry-point to see what was going on

The first few functions were mostly junk - but there were 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 I used detect-it-easy to look for more interesting strings contained within the file.

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

Overview of some plaintext strings contained in the malwar.e 

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

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

So I 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. I was 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 - I 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 was 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 I obtained that dictionary and prettied it up using Cyberchef to remove all of the \ escapes.

Cleaning up escape characters with Cyberchef

I then created a partial Python script based on the information I 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 - I was able to obtain a cleaner-looking string than before.

Here's a before and after

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

It was probably safe to assume this string was reversed + base64 encoded, but I 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 I then added these steps to my Python script.

Updated Python Script for decoding Dcrat

And executed to reveal the results - successful C2!

Successfully obtaining the decoded C2 using python. 

(The URL's contained some base64 reversed/encoded strings and were not very interesting)

This C2 domain had only 2/85 hits on VirusTotal

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

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

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

Copies of the decoding scripts - https://github.com/embee-research/Decoders/tree/main/2023-April-dcrat

Link to the original malware - https://bazaar.abuse.ch/sample/fd687a05b13c4f87f139d043c4d9d936b73762d616204bfb090124fd163c316e/