Unlike .NET applications, unmanaged code compiles to machine code which is far more secure than what we have out of the box in C#/VB.NET. Before for reversed engineering we used debuggers that traced registers, showed API calls, strings and recognized procedures but we had to deal with it in pure assembler. How secure are our applications written in .NET Framework, what can we do to make them more secure and is it worth it?
Basics
In theory C# code could be compiled to machine code but in reality all compilers target CIL ( Common Intermediate Language ), previously called MSIL. IL managed code which is run by the virtual machine is surprisingly similar to C# although confusing at first.
The first and very basic technique allowing us to view compiled .NET code is disassembling the target assembly by Intermediate Language Disassembler (ILDasm) included in Microsoft SDK (Program Files\Microsoft SDKs\Windows\v6.0A\bin)
Using ILDasm together with ILasm (CIL assembler) you can decompile application to text file :
ILDasm /OUTPUT=Rev.il ReverseMe.exe
apply changes and the compile it again :
ILAsm Rev /output=ReverseMe.exe
But why bother making changes in IL if you’re a C# programmer, there is a useful freeware tool for viewing .NET assemblies called .NET Reflector. Add-ins exist that allow user to dump reflected code into class files, we should bare in minds that it is a very nice way of translating code into other language .
I assume that most of you have already heard about this tool and now are wondering how to prevent it from reflecting your code. There used to be an anti reflector trick - it used a specific IL instruction unknown to the Reflector. This solution was very effective because it made the Reflector stop at that instruction and the rest of the code was unreadable. Unfortunately anti reflector tricks have one grate disadvantage, they are using bugs and after the patch is released they become obsolete and your code can be viewed without obstacles.
If you are releasing a demo version of your application it is better not to include all of the functionality inside the code instead of e.g. disable buttons that run those methods which should be obvious in context of using reflector however there is also .NET runtime object editor called Hawkeye that allows non-programmers to change properties of objects by pointing to them. Having that in mind disabled button can be enabled by anyone who knows how to run application and how to use a mouse.
Methods of securing
I will start here from the end. Every known method of securing applications can be reversed but as long as the effort required to achieve that goal is greater than application value there is no point in doing so. In other words it is faster for someone to write his own code or cheaper to buy your application with source code than trying to reverse properly secured application and that is why you should become acquainted with all the methods below.
- Name mangling
There are lots of different variations of this one. The idea is to change every method/variable name to letter (for example : a,b,c,d,.. and so on) to make it less readable to human. It is easier to figure out what “rename” method does than “a” method. It is something that everyone can do by themselves, using tool they wrote or commercial ones. Issue with some basic tools is that there are counter tools to rename methods back to more readable form.
- String encryption
It is always a bad idea to put confidential text inside the code, encrypting it will make reversed engineering harder , not impossible. It can be achieved both by using obfuscating tools or by writing your own algorithm.
That is why you should not think encryption will guarantee that no one can read stings inside the code.
- Control flow
We put a lot of effort in making out code easy to understand , control flow obfuscation is the opposite. Lots of references, jumps form one method to another , cutting methods into dozens of pieces just to make it almost impossible to decompile code automatically. The best expression that fits to this method is “spaghetti code”. Control flow does not change the way your application is run but it will slightly slow it down.
- Strong names
Signing application with a strong name has a few purposes , one of them is assuring integrity of the code so any change that has been made will result in error while trying to launch the application, the bad news is that it can be removed for example with SNRemove. Dependencies based on strong names will make application more secure.
- Obfuscators
There is a wide variety of obfuscating tools on the market that offer comprehensive methods of securing applications including all above and adding some new ones like generic packing which compress applications into non CIL Portable executable (PE) file that when lunched unpacks assembly and runs it from memory, at first it does not look like managed code but can easily be reversed for example with “.NET Generic Unpacker”. There are some really powerful tools like {smartassembly} that will definitely increase the security of code but on the other hand the more popular the obfuscator is the more chance that there is a program like {smartkill} which targets specific versions of {smartassembly} and undo the changes.
There is no way you can guarantee the complete safety of your code but you can and should secure it so reversing it will not be beneficial to anyone. If you think that reversed engineering is not being used in big companies your wrong. It is a commonly used technique to save time and money.
If you would like to know more about the topic in general not only in .NET , I recommend to start with reading about Portable Executable (PE), assembler language basics and debuggers like OllyDbg.