Programs written for .NET are easy to reverse engineer. .NET applications compile to a high-level, expressive file syntax called MSIL (Microsoft Intermediate Language) that contains method and variable names and can be easily decompiled back into source form.
Attackers can use freely available decompilers to easily see the source of any .NET application, exposing software licensing code, copy protection mechanisms, and proprietary business logic - whether it's legal or not. Anyone can peruse the details of a software application for security flaws to exploit, unique ideas to steal, features to crack, or worse.
This is not the only option, though. Obfuscation is a technique that provides seamless renaming of symbols in assemblies as well as other tricks to foil decompilers. Properly applied obfuscation increases protection against decompilation by orders of magnitude, while leaving the application intact.
When an obfuscator tool goes to work on readable program instructions, a side effect is the output will confuse a human interpreter and break the decompiler the human interpreter was using. While the executable logic is preserved, the reverse semantics are rendered non-deterministic. As a result, attempts to reverse-engineer the instructions fail because the translation is ambiguous. Deep obfuscation creates a myriad of decompilation possibilities, some of which produce incorrect logic if recompiled. The decompiler, as a computing machine, has no way of knowing which of the possibilities could be recompiled with valid semantics. Humans write and employ decompilers to automate decompilation algorithms that are too challenging for the mind to follow. It is safe to say that any obfuscator that confuses a decompiler poses even more deterrence to a human attempting the same undertaking.
It is important to understand that Dotfuscator is a "post-compile" tool - it works by modifying already-compiled application assemblies. The development environment and tools do not change to accommodate obfuscation, and source code is never altered, or even read, in any way. Obfuscated binaries are functionally equivalent to traditional binaries (except where intentionally changed) and will execute on the Common Language Runtime (CLR) with identical results. (The reverse, however, is not true. Even if it were possible to decompile strongly obfuscated binaries, it would have significant semantic disparities when compared to the original source code.)
The following illustration shows the flow of a typical build process with and without Dotfuscator:
That means you follow all your normal processes to develop and compile your application, and then you configure Dotfuscator to process those binaries. Dotfuscator will take the binaries as input, perform the obfuscation per your configuration settings, and generate the same set of binaries as output - but those binaries will be obfuscated.
Most often, the process of developing and obfuscating an application looks like this:
- Follow normal development and QA procedures for most of the project lifecycle.
- Somewhere past the half-way point but well before release, use the Dotfuscator UI (in Visual Studio or on its own) to configure Dotfuscator to work with your application, using basic smoke testing to ensure that the obfuscation hasn't caused obvious issues with the application.
- Integrate Dotfuscator into your build process, using our Visual Studio integration, MSBuild task, or straight command-line calls.
- Use the obfuscated build in QA for the remainder of the project.