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 initial file can be downloaded via Malware Bazaar and unzipped it using the password
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 revealed that the sample is a 32-bit .NET-based file.
- The protector
Confuser(1.X) has also been recognized.
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
In my experience, large and high entropy sections often indicate an embedded payload. Indicating that the file being analyzed is a loader.
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
In order to analyze the suspected loader, I moved on to
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.
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
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
After the array, there is again code that suggests the array's contents are decrypted, then loaded into memory with the name
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
Decryptcall and dump the result from memory.
- Set a
module breakpointto 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
I then created a module breakpoint with two wildcards. This will break on all new modules loaded by the malware.
I then executed the malware using the start button
I accepted the default options.
Immediately, a breakpoint was hit as mscorelib.dll was being loaded into memory. This is a default library and I ignored it by selecting
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)
Here I could see the
koi module had been loaded.
At this point, I saved the
koi module to a new file using
Right-Click -> Save Module.
We can then exit the debugger and move on to the
Analysis of koi.exe
We can observe that
koi.exe is another 32-bit .net file containing references to the
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.
We can now go ahead and open
koi.exe in Dnspy.
This time there was another
rewrwr.exe name and references again to
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 class immediately called
Form1_Load, which itself immediately referenced a large string that appeared to be base64 encoded.
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.
I decided to jump to the end of the base64-looking data - Noting that there were about 50 large strings in total. Each titled
str2 ... all the way to
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
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.
After the buffer is filled, it is base64 decoded and loaded into memory as an additional module.
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.
This confirmed the theory on 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.
Running this script creats a third file. Which for simplicity's sake is named
The file is recognized as a 32-bit .NET file. So the decoding was successful.
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.
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
Despite the lack of
ConfuserEx, the namespaces and class names look obfuscated in some way.
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
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)
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.
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.
I then tried to decode the second base64 blob shown by
But the result was largely junk.
reverse + base64 decode returned no results.
At this point - I decided to search for the base64 encoded string to see where it was referenced in the .net code.
This revealed an interesting function showing multiple additional functions acting on the base64 encoded data.
In total, there are 4 functions (
M2r.i59 ) which are acting on the encoded data.
The first function
M2r.957 is a wrapper around another function
M2r.276 which performed the
The next function
M2r.i6B took the previously obtained string and then performed a
Replace operation based on a
Interesting to note - is that the
Valueis replaced with the
Keyand not the other way around as you might expect.
Based on the previous code, the input dictionary was something to do with a value of
Suspiciously - there was an
SCRT that looked like a dictionary in the first base64 string that was decoded.
So I obtained that dictionary and prettied it up using Cyberchef to remove all of the
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)
Executing this result and printing the result - I was able to obtain a cleaner-looking string than before.
Here's a before and after
It was probably safe to assume this string was
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.
M2r.i59 was indeed responsible for base64 decoding the result.
So I then added these steps to my Python script.
And executed to reveal the results - successful C2!
(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/