Even if you have trouble reading your own code, you might still want to make it hard for others to decompile the assemblies you ship out the door.
As in the Java world, a number of tools are available that will easily decompile your .NET code [Hack #63] . Both the Java Virtual Machine and the .NET Common Language Runtime provide means of using reflection to "look inside" compiled assemblies. If this is alarming, it should be. After all, you may have class libraries with highly confidential business logicif that logic were to fall into the wrong hands, you could lose your competitive advantage. Luckily, Visual Studio contains a tool named Dotfuscator that you can use to make sure that the output of a decompiler is as close to gibberish as possible.
To use the Dotfuscator, you'll first need to create a project in Visual Studio and compile it (in this case, I've created a project with a class named SimpleMath). Then create a Dotfuscator Project for your assembly by following these steps:
On the Visual Studio menu, click Tools
At the Select Project Type dialog box, choose Create New Project and click OK. You'll now see a tool with several tabs along the top (Figure 10-25).
Although several tabs and numerous options can be configured in the Dotfuscator, you need to configure two items at a minimum to create an obfuscated assembly. They are the trigger file(s) and the build destination directory. Once these two options are set, you can save the Dotfuscator Project for use later. Dotfuscator Projects are saved in XML format.
Click the Trigger tab and notice that nothing is there. Now click Browse, search for your assembly, and click Open. You'll see that your assembly has been added to the Dotfuscator Project.
Click the Build tab. For the Destination Directory, click Browse, search for the directory where you want to place the obfuscated assembly, and click OK. Be sure this directory is not the same directory where the Debug assembly is placed.
Click File
Now
that
you've created and saved a Dotfuscator Project, you
can build it. Click File
Now that you've got an obfuscated assembly, let's take a look at it using two well-known tools, ILDASM and Reflector.
As you know, ILDASM can be used to view an assembly's manifest and its IL code [Hack #63] . You can use this tool to verify the Dotfuscator did its job by comparing the obfuscated assembly to the regular assembly. My SimpleMath class will be used as the example.
So launch ILDASM and open the unobfuscated assembly. Now launch another instance of ILDASM and open the obfuscated code. In both instances, expand the class(es) listed and take a look. Figure 10-26 is the unobfuscated assembly; Figure 10-27 is the obfuscated assembly.
Notice that the class name (SimpleMath) and its methods (Add, Divide, Multiply, Subtract) are clearly visible in the unobfuscated assembly, while the obfuscated assembly does not contain any names of significant meaning. If someone were to use ILDASM on your obfuscated assembly to gain knowledge of your business code, they won't find it very useful.
Let's now take a look at the actual IL code produced. For simplicity, we'll look at just one of the methodsthe Add method. Figure 10-28 is the unobfuscated IL code for the Add method; Figure 10-29 is the obfuscated version.
Notice that the only difference in the IL code is the method signature. The actual code execution path is identical, thus both assemblies will execute exactly the same. There is no performance penalty for code obfuscation.
Reflector is a tool that can be used to "look inside" .NET assemblies and see its codepaths and logic [Hack #64] . It does not produce an exact copy of the actual code for an assembly, but that's not the point. It's used to provide insight to the logic used for the internals of an assembly. Therefore, continuing to use the SimpleMath class, we'll investigate the differences Reflector shows between unobfuscated and obfuscated assemblies.
Launch two instances of Reflector: one to open the unobfuscated assembly and the other to open the obfuscated assembly. The figures show the disassembler view of the SimpleMath class. Figure 10-30 is the unobfuscated assembly; Figure 10-31 is the obfuscated one.
Similarly to what was shown in ILDASM, Reflector does not show the actual class and method names in the obfuscated code (because the IL for the obfuscated assembly does not have them).
Reflector's real power is viewing the disassembled code for each method, so using the Add method again, let's take a look. This is the disassembled code for the Add method. Figure 10-32 is the unobfuscated version; Figure 10-33 is the obfuscated one.
As you can see with this extremely simple example, the disassembled views are very similar. However, to know that the "d" method was for adding two numbers, I had to view the disassembled code for each method in the obfuscated assembly and then had to realize that the "d" method did in fact simply add two numbers together. Any .NET assembly even slightly more complex than this example will benefit from code obfuscation.
Code obfuscation is only ever a deterrentgiven enough effort and time, even the most obfuscated code could be decompiled and understood. The only guaranteed way to ensure your code will not be decompiled is to never put it on the client machine in the first place. One technique is to encapsulate your sensitive business logic in a web service and call that web service from your application. Just because obfuscation is not a guarantee does not mean it is not valuable, since it will still prevent the majority of people from being able to decompile your application.
Dave Donaldson