NDepend Blog

Improve your .NET code quality with NDepend

In the Jungle of .NET Obfuscator Tools

April 26, 2024 7 minutes read

In the Jungle of .NET Obfuscator Tools

In this article, I will explain our genuine experience with various .NET Obfuscator Tools. We end up explaining that .NET Reactor is the one we choose to obfuscate our code for various reasons: reliability, support, seniority, cost, and obfuscation options.

There are actually dozens of .NET Obfuscator as listed here obviously we didn’t try them all. Many of these projects are abandoned anyway. Building an obfuscator for .NET is a popular and fun task, made easier by libraries like the Mono.Cecil project. However, creating a functional obfuscator that properly obfuscates the code without introducing bugs is challenging. .NET obfuscators that work are the exception rather than the norm.

I won’t go into the debate of the need for an obfuscator. To protect intellectual property, obfuscating symbols and obscuring IL code is a common approach. However, for more comprehensive protection, in-house work is recommended as explained in Don’t rely on someone else to protect your software. Even web developers should consider obfuscation since important intellectual property is often sent to the client side in browsers.

Before starting, let’s note that prior publication, the present post has been submitted to each product owner listed here to make sure everything written is correct.

Preemptive Dotfuscator

For over a decade, we used Preemptive Dotfuscator to obfuscate our code. Microsoft promoted Dotfuscator as a .NET obfuscator, but it’s likely they never intended to provide one. Initially, developers transitioning from C++ and VB6 to .NET didn’t realize their intellectual property was exposed. This was seen as a downside to the new platform compared to C++ and VB6.

Our code was compatible with an older version of Dotfuscator for .NET 4.0 and 4.5, but after migrating to newer versions like .NET 4.7.2 and .NET 6/7/8, we needed a more updated obfuscator. While Dotfuscator can handle these newer versions, they recently increased their subscription price policy by 80% each year without added value or an upper limit. This greatly multiplied our yearly fee after a decade of use.

While Preemptive Dotfuscator is a functional product, the increasing yearly fees for support and updates are unreasonable. Accepting these conditions now means potentially paying uncontrolled fees in the future, so we opted to look for alternatives. It’s important to remember that choosing this product could lead to a similar situation.

Eazfuscator.NET

Eazfuscator.NET has a good reputation, has an affordable pricing and has lots of fans online. We tried it but figured out that the tool does not provide mapping files. Mapping files of assemblies generated by Dotfuscator makes it possible to decode production stack traces, which is essential to track production problems and fix them.

Instead, Eazfuscator.NET encrypts obfuscated symbols with a private key. Thus production stack traces can be decoded with the private key. At first sight, this is pretty cool. However there are two significant problems with this approach.

  • Encrypted symbols are available publicly. We talked with the author of Eazfuscator.NET and he is pretty certain that encrypted symbols cannot be cracked (verbatim in his own words “Given a reliable crypto, a motivated hacker would not be able to come up with anything unless he has a few million years and all computational resources of the world at his disposal. This is just how math works – nobody can overcome that no matter how skillful they are.”). Nevertheless, this approach is necessarily less secure than the mapping file approach where symbols released in the wild have nothing to do with the original ones. Here is a quote on the page of de4dot – a tool to reverse-engineer obfuscated code “Most of the obfuscation can be completely restored (eg. string encryption), but symbol renaming is impossible to restore since the original names aren’t (usually) part of the obfuscated assembly”. Let’s underline that de4dot doesn’t crack Eazfuscator.NET encrypted symbols but the message is clear. However, this post DECRYPTING EAZFUSCATOR.NET ENCRYPTED SYMBOL NAMES shows well that a private password-based system to secure symbols is much less secure than a private mapping of obfuscated symbols.
  • Encrypted symbols size is correlated with the original symbols size. The author claimed that the size is roughly similar. We tend to use large symbols to make our code comprehensive. An additional bonus we had with a mapping file approach is that our assemblies size reduced significantly (10 to 15%) because symbols like “NDepend.Platform.DotNet.VisualStudio.VisualStudioEditionHelper” were shortened to something like “B6U”. NASA sent men on the moon and back in 1969 with 4KB RAM. I used to program my first micro games with a 4KB RAM computer too in the 80’s. Today mobile phone flashlight apps usually weigh 10 to 20MB. Call me old-fashioned but I am quite unhappy with this bits inflation. 10/15% less bits in our redistributable matter.

The Eazfuscator.NET author underlined that “On the positive side there is no state in contrast to the stateful nature of mapping files. If you create frequent releases on a variety of build machines this may be a good point for you as it makes things easier”.

He also added that there is no immediate plan for mapping files. Unfortunately, this means that Eazfuscator.NET was not the right choice for us.

Babel

Babel has a good reputation and affordable price, and includes a mapping file feature. However, despite multiple attempts and discussions with the author, we were unable to get it to work on our assemblies. While it may work for other applications, it didn’t for us.

Obfuscar

It was interesting to try an open-source obfuscator. Obfuscar was the first choice since there are some recent enough commits and its nuget package was downloaded more than 760K times!

Unfortunately, despite trying hard we couldn’t generate bug-free code due to known flaws such as TypeLoadExceptions and inability to obfuscate all enums values. I had the chance to discuss with Lex Li, one of the main contributor on Obfuscar over the years and his stance is :

“Obfuscar does have a few design flaws which I was trying to fix but unable to fully address. However, I noticed a fork https://github.com/3shape/obfuscar which is built upon my unsuccessful attempt (dating back a few years ago) and seems to be promising. I don’t have time to evaluate their work though.”

Confuser

We didn’t bother trying the open-source obfuscator ConfuserEx since it hasn’t been touched for years and the project is officially discontinued and unmaintained. The project forked to neo-ConfuserEx that also hasn’t been touched for years either.

.NET Reactor

After all these attempts (and time lost) we tried .NET Reactor. It has mapping files, affordable pricing and is maintained since 2004 with new versions released regularly.

Strong UI and good documentation are essential for complex tools like obfuscators. What I appreciate about .NET Reactor is its UI that’s full of tooltips and links to extensive documentation. It’s beneficial to have feature descriptions embedded in the UI, so users won’t have to go back and forth to the documentation or seek support. For instance, selecting “Public Types Internalization” prompts the description, “If enabled, .NET Reactor will convert all public types of an application into internal ones. This way the accessibility of types and members is reduced” making it easy to understand.

We have the same approach with the NDepend online and embedded documentation. Personally, I don’t like to be stuck on a setting or a behavior not well documented. I consider that ISVs are not here to sell support but to build solutions that seamlessly solve problems and bring value. More on this digression can be read in You Should Favor Software Products That Include Support in the Price.

Initially, .NET Reactor did not work for us due to resource unavailability and some unobfuscated override method names. However, after several rounds of communication with the author, we were able to generate a bug-free obfuscated version of our code. The support we received was prompt and efficient. Now we have a reliable obfuscation process with excellent support, and all that for less than 5% of what we used to pay with Dotfuscator.

Conclusion

One important aspect of obfuscators not covered in this post is the various extra protection features like virtualization, string encryptions, anti-tampering… Again it is recommended to do some in-house/custom protection. Keep in mind that some project exists like the aforementioned de4dot tool to reverse-engineer code generated by popular obfuscators.

Everything written in this post is genuine. To find the best .NET Obfuscator tool for your needs, it’s important to start by trying a tool that is well-maintained with recent updates and commits. After researching and evaluating various options, we recommend trying out .NET Reactor based on our positive experience with the tool.

Comments:

  1. I can imagine it took quite a while to figure it out.

    I’m looking forward to play with the new .net 5/6 build of NDepend. I guess that also took quite some testing to make sure everything was right.

    I understand the reasons to pick .net reactor. The UI is indeed very understandable. There are a few things I don’t like about it but in general it’s a good choice.

    Thanks for sharing your experience.

  2. David Gerding says:

    Nice write-up and much appreciated.

  3. Very good article. I was questioning myself a lot about the use of obfuscators and have also tried out some of the mentioned, but at the company we don’t use one in the end…

    What I am asking myself is when I publish my .net file to singel file, ready to run with an fixed runtime identifer I’ll get sort of binary code.
    At first glance I cannot dissasemble and reconstruct any code from it.
    What do you think, do I still need an obfuscator for this szenario?

    1. > when I publish my .net file to singel file, ready to run with an fixed runtime identifer I’ll get sort of binary code.

      Do you mean that you are using .NET Ahead Of Time compilation (AOT)? as explained here:
      https://blog.ndepend.com/net-native-aot-explained/

      In that case the code is much less decompilable (since there is no more IL Intermediate Language code). But a motivated hacker can still decompile it and see how the code works. However Obfuscator presented here are not concerned with this scenario.

  4. OK. After some thinking and updating my ILSpy to the latest version I found out that ILpy can diassemble and show all sources of an “publish single file” application. (DnSpy can’t by the way…)
    So there IS definitifely still the need to obfuscate….

Comments are closed.