Decompiling .NET Executables

Hacking 101 Reverse Engineering

Visual Studio Code is a free IDE that is great for debugging, compiling, and building .NET Framework applications.

Visual Studio Code

Let’s use a simple C# program to demonstrate a very basic workflow for decompiling .NET executables. First, let’s use Notepad++ to create a text file on the Windows virtual machine Desktop with the following code:

using System;

namespace dotnetapp
    class Program
        static void Main(string[] args)
            Console.WriteLine("What is your favourite Web Application Language?");
            String answer = Console.ReadLine();
            Console.WriteLine("Your answer was: " + answer + "\r\n");

We will save this file as test.cs. In order to compile it, we’ll use the csc.exe compiler from the .NET framework ( or feel free to compile using Visual Studio Code and run ‘dotnet build’ ).

c:\Users\Administrator\Desktop>C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe test.cs
Using CSC.exe to compile

Once our test.exe is created, let’s execute it to make sure it works properly.

What's your favorite web application language?
Your answer was: C-Sharp,have%20any%20source%20code%20available.

We can now open dnSpy and attempt to decompile this executable’s code. We’ll drag the test.exe file to the dnSpy window, which automatically triggers the decompilation process in dnSpy.

Test.exe in dnSpy

To view the source code of this executable, we’ll have to expand the test assembly navigation tree and select test.exe, dotnetapp, and then Program, as shown in Figure 33. According to the output, the decompilation process was successful.

Navigating to the decompiled source code

Excellent! We successfully decompiled the executable.


When analyzing and debugging more complex applications, one of the most useful features of a decompiler is the ability to find cross-references to a particular variable or function. We can use cross-references to better understand the code logic. For example, we can monitor the execution flow statically or set strategic breakpoints to debug and inspect the target application. We can demonstrate the effectiveness of cross-references in this process with a simple example.

Let’s suppose that while studying a target application, we noticed a few Base64-encoded values in the HTTP requests captured by Burp Suite. Since we would like to better understand where these values are decoded and processed within our target application, we could make the assumption that any functions that handle Base64-encoded values contain the word “base64”.

We’ll follow this assumption and start searching for these functions in dnSpy. For a thorough analysis we should open all the .NET modules loaded by the web application in our decompiler. However, for the purpose of education, here is an example search for the term “base64” within method names of an application.

Example showing a search in dnSpy

The search result provides us with a list of method names containing the term “base64” as shown below.

Searching for a base64 string

Let’s pick one of the functions and try to find its cross-references. We’ll select the Base64UrlDecode function by right-clicking on it and selecting Analyze from the context menu.

Analyzing a function

The results will appear in the Analyzer window. Specifically, expanding the function name reveals two options: Used By and Uses.

Finding cross-references for a given function

Modifying Assemblies

Finally, let’s demonstrate how to arbitrarily modify assemblies. We can use this technique to add debugging statements to a log file or alter an assembly’s attributes in order to better debug our target application.

In order to demonstrate this technique, we will briefly return to our previous custom executable file and edit it using dnSpy. Let’s right-click Program and choose Edit Class.

Editing a class in dnSpy

Then we’ll change “Your answer was: ” to “You said: “.

Modifying code the source code with dnSpy

And finally, we’ll click Compile, then File > Save All to overwrite the original version of the executable file.

Saving our modified assembly
Replacing our original test.exe file

If we return to our command prompt and re-run test.exe, the second print statement is now “You said: “.

Running an edited executable

Using a very basic example application, we have demonstrated how to recover the source code of .NET-based applications and how to find cross-references with the help of our favorite decompiler. We also demonstrated how to modify and save a .NET assembly file. Even if this modification doesn’t seem particularly useful, it will come in handy later on in the course when we will have to alter assemblies’ attributes in order to better debug our target application.

1 thought on “Decompiling .NET Executables

Leave a Reply

Your email address will not be published. Required fields are marked *