NDepend

Improve your .NET code quality with NDepend

In the Jungle of .NET Obfuscator Tools

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. On a side note it is surprising to see so many attempts. I guess building an obfuscator is a task considered both fun and not too complicated given reader/writer IL libraries like the Mono.Cecil project. Experience shows that building an obfuscator that works – I mean that obfuscates the code properly without introducing bugs in the obfuscated code – is difficult: .NET Obfuscators that work are more the exception than the rule.

I won’t go into the debate of the need for an obfuscator. As many other ISV we want to protect our Intellectual Property (IP) and obfuscating symbols and blurring the IL code obviously helps. Moreover for more serious protection you should consider doing some in-house work anyway as explained in Don’t rely on someone else to protect your software. Even web developers are concerned by obfuscation since some significant IP are sent on the client side in the browser. There are many Javascript obfuscators available and some obfuscators for Blazor (IL or WASM compiled) already exist.

A rule of thumb for web content is to remain positive and don’t harm anyone. Online bashing and hassle is a waste of time, shows a negative image and never outcome to anything productive. However in this post I will explain that some obfuscators were genuinely not the right choice for us for various reasons. Keep in mind that each mentioned product has some real-world users that are happy with it. Also prior publication, the present post has been submitted to each product-owner listed here to make sure everything written is correct.

Preemptive Dotfuscator

For more than a decade we relied on Preemptive Dotfuscator to obfuscate our code. Since the early days of .NET in 2002/2003 Microsoft promoted Dotfuscator for .NET users that wanted an obfuscator. My guess is that Microsoft never had wanted to provide a .NET obfuscator. In the early days of .NET, the developers coming from C++ and VB6 didn’t realize straight away that with the new .NET platform their IP was now exposed crystal clear to everyone. This is an aspect of .NET that was seen as a regression compared to C++ and VB6.

Until now our code was .NET 4.0 and .NET 4.5 and Dotfuscator just worked. As a consequence an older version of Dotfuscator was sufficient. However we migrated to .NET 4.7.2, .NET 5/6/7 and .NET Standard and we needed an up-to-date obfuscator that can handle the latest .NET flavors. Dotfuscator can certainly do that (not verified). However in 2021 they changed their subscription price policy with a 25% increase every year with no real added value and there seems to be no upper limit. In the end that literally multiplies the yearly fee we used to pay for a decade.

Preemptive Dotfuscator is a product that works. It is normal to pay a yearly subscription for support and an up-to-date product. However the increasingly high yearly fees is a greedy policy we refused. If we accept these conditions now, we will end up paying an unbounded and uncontrolled fee later. This is not sane and we decided to explore alternatives.

As a lesson learned, keep in mind that if you go with this product you might be well end up in a similar situation.

Eazfuscator.NET

Eazfuscator.NET has a good reputation, has a very 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 make 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 (which doesn’t sound serious in a mouth of a security expert). Nevertheless this approach is objectively 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 weight 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 file. Unfortunately this means that Eazfuscator.NET was not the right choice for us.

Babel

Same as Eazfuscator.NET, Babel has a good reputation and a very affordable price. It also has the mapping file feature. It looked pretty promising. Unfortunately despite many hours and a lot of discussion with the author to try to make it work on our assemblies, we didn’t obtain a working obfuscated version.

The tool works fine for many other applications so it might work for you. Unfortunately it didn’t for us.

Obfuscar

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

Unfortunately despite trying hard we never succeeded in generating a bug-free version of our code. It has some well known flaws like throwing some TypeLoadException on some overriden methods that we were experiencing. This other issue also was a blocker unless we accepted to not obfuscate all our enums.

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, very affordable pricing and is maintained since 2004 with latest version released a few days ago.

What struck me positively first is that its UI is full of tooltips and also contains many links to a massive documentation. The best UI is the one that can be understood intuitively. But for complex enough tools – like an obfuscator – some embedded feature descriptions are welcome: for example I appreciate that when I select the setting “Public Types Internalization” this description is immediately shown to me “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”. This way this is all clear and there is no need to go to the online documentation or ask support.

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 ISV are not here to sale 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.

.NET Reactor didn’t work straight for us. Generated assemblies had some problems with some resources unavailable once obfuscated. A few override method names were not obfuscated also. Nevertheless we did a few roundtrip with the author until the obfuscated version generated totally bug-free code for our application. The support we received was reactive (no pun intended) and smooth. And we now have a solid obfuscation process with seamless support, for not even 5% of what we used to pay with Dotfuscator.

Conclusion

One key aspect of obfuscators neglected 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 exposed in this post is genuine and there is no hidden goal to promote .NET Reactor and criticize other mentioned products.

Again quoted obfuscator that didn’t work for us might work for you. Moreover there are certainly other .NET obfuscators out there that do the job well and that we didn’t touch.

My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend in 2004.

Nowadays NDepend is a full-fledged Independent Software Vendor (ISV). With more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.

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.

Comments are closed.