There are a lot of decompilers available in the .NET ecosystem and this has always been the case. I mean always. However, I sometimes forget that not everyone knows or appreciates this and that my perspective is born from the fact that I was a professional developer during the formative years of .NET. So it was a bit of a shock to see some of the responses to Decompilation being available in Visual Studio.
I wrote about this orthogonally but it is important to repeat some fundamental Intermediate Language and Just in Time compilation are important concepts. Lets define them again here:
IL (Intermediate Language) - All .NET compilers generate Intermediate Language (IL) no matter what the underlying language used to develop the application. The CLR actually has no idea about the language used to develop a given application. All .NET compilers will generate a standard, common language we refer to as IL (aka, MSIL and CIL).
So you have executable or assembly replete with IL, now what? We have to execute it right? That is where JIT comes in:
JIT (Just in Time) - Before Intermediate Language (IL) can be executed, it must converted by the .NET Framework's JIT compiler to native code, which is CPU specific code that run on some computer architecture as the JIT compiler. Rather than using time and memory to convert all the MSIL in portable executable (PE) file to native code, it converts the MSIL as it is needed during execution and stored in resulting native code so it is accessible for subsequent calls.
There are some real advantages to this IL/JIT strategy:
- You can potentially run your code on any platform because you are not stuck with native code (or specific version of native you built). You will, however, need to an JIT compiler for those platforms.
- Further you can add run-time optimizations that are not possible had you created native code. So if a new CPU feature is created your IL can potentially take advantage of it (assuming an updated JIT compiler).
Given this pattern it is relatively straight for to create tools that exceed ILDASM, I have written about Lutz Roeder’s Reflector or ILSpy and a couple of others in the past. Decompilers exist and have always existed, so what can you do to protect your code?
Since .NETs inception folks that have sought out additional protection against decompilation have normally turned to obfuscation. There at least a dozen to select from that are free (such as ConfuserEx) to professional grade (such as PreEmptive). I do not have any endorsements to make here only that a quick Bing search can give you much to choose from.
Roslyn Compiler ILSpy integration
One other point of interest is that decompilation with ILSpy has existed in Visual Studio for a few years now but it is still under a preview flag. If you navigate to Options->Text Editor->C#->Advanced the Analysis section allows you to enable navigation to decompiled sources.
Once enabled this permits you to F12 (go to definition) into 3rd party software and see what’s going, I think it is a really helpful feature for understanding how code may be helping or hurting you.
But lets say your a software creator who is not keen on Visual Studio users being able to casually browse through your code, you can actually use the SuppressIldasmAttribute class to stop decompilation from occurring on your module. Of course this will not protect you from the plethora of other decompilers on the market.
Visual Studio Debugger ILSpy integration
My team has also done a lot of work with integrating the ILSpy decompilation with the Visual Studio Debugger and you now have the option of decompiling during debugging or when you are analyzing a memory dump. Now if you are confronted with a No Symbols Loaded page? Or maybe experienced an exception occurring in a 3rd party .NET assembly but had no source code to figure out why? You can use Visual Studio to decompile managed code even if you don’t have the symbols, allowing you to look at code, inspect variables and set breakpoints. I love this new feature!