Protect .NET code from reverse engineering?
You can't.
There are steps you can take to make it a little more difficult, but ultimately any executable on the local machine is crackable. Eventually, that code has to be converted into native machine code and every application that is runnable is vulnerable.
What you want to do is just make it difficult enough to crack to make it not worth peoples' trouble.
Some suggestions I have for you to help protect your application:
- Obfuscate your code. Dotfuscator has a free edition and comes with Visual Studio.
- Use public/private key or asymmetric encryption to generate your product licenses. This ensures that only you can generate your license codes. Even if your application is cracked, you can be sure that they won't be releasing a key generator for your application, because it is impossible to reverse the key generating algorithm.
- Use a third-party packer to pack your .NET executable into an encrypted Win32 wrapper application. Themida is one of the better ones. This stops people from reflecting your application in .NET Reflector and makes it a pain to unpack for reversing.
- Write your own custom packer. If the third-party packers are too expensive, consider writing your own. Sometimes custom packers can be very effective, because there aren't well published methods on how to unpack them. The tutorial How to write your own packer gives a ton of good information on writing your own Win32 packer.
Ultimately though, if people want your application cracked they will. Look at all the commercial software out there that has a vast amount of resources to protect their applications and yet they are cracked before the applications are even released to the public.
A skilled reverse engineer can fire up IDA-Pro and slice through your application like butter no matter what you do. A packed application can be unpacked and obfuscation only prevents it from making it a walk in the park. All your hard work with your complex license code can be undone with a single byte patch.
You just need to accept that there is a very real chance people are going to pirate your software. There are some people who are never going to pay for your application no matter what and these are the people you don't need to worry about.
There are however, many businesses out there who would never risk a lawsuit and happily buy software licenses and many computer users who either don't want to risk it, find it wrong or are not tech savvy enough to pirate. These are your true customers, and you should focus your efforts on providing them with a good user experience and ignore the people cracking your software.
I've had my application pirated before, and I took it as a personal affront. Here I was, a small-time developer, pouring my heart and soul into an application and these people had the gall to pirate from me?! They were taking money directly from my pocket!
I immediately added in a bunch of draconian DRM code and attempted to sabotage any person using an illegitimate or cracked copy. I should of course have been working on making my application better instead of trying to stop the inevitable. Not only that, but I was hurting my true customers will all these extra protections I was putting in.
After a long battle I realized I was fighting the tides and all this time wasted was for naught. I took out all the phone-home code except for the barebones license functions and never looked back.
You can't fully secure any application (managed or not). If systems like the Playstation and iPad can get cracked — where the vendor even controls the hardware — what hope does your app have? Thankfully, you don't really want to. In my opinion, you need to secure your application just enough that someone can't accidentally pirate your product, and no more.
For example, if you use a per-machine license, it shouldn't just work when you install it on a new second machine. You'll want a good error message to prevent extra support calls, but don't spend extra time making it too hard to work around and don't hit users over the head with it.
Another example is a time-limited trial. Don't even worry about simple things like if users can just roll back the system clock. Someone who does that knows they are breaking your license, and as long as a user knows when they are in violation you've done enough.
You need to do this much because users don't care about your license. Licenses are made-up things that nobody cares about until they need to. No one reads them, and they really shouldn't have to. Therefore the best way to tell the user where the boundaries are is if the out-of-the-box behavior for your application complies with the license. In this first case that means either failing to install or installing in trial-version mode the second time. For the latter, it might just mean checking a plain-text date in a configuration file. Either way, make sure you handle it in an elegant, helpful, and respectful manner.
So that explains what it means do just that much. But why not go any further? Why not plug every little hole you can find? The answer is in two parts. First, if someone will cross the ethical threshold of consciously breaking your license terms — even in a simple way — they'll also be willing to do something more difficult or dangerous like pull your application from a torrent site — and there is a certain amount of danger involved in running applications downloaded from untrusted sources. Making it any harder is only a minor annoyance for these users and risks causing problems with your paying customers. Keeping it simple may prevent someone from digging into your application and releasing a more comprehensive crack. Second, you have few eyes available to look for flaws; the hackers have many, and they have more practice finding them. You only need to miss one little flaw, and your app will have the same distribution on pirate sites as if you did nothing. You have to be right every time; they only have to be lucky once. So the effort required is very high, and the likelihood of any measure of success is very low.
Ultimately, if someone wants to pirate your application (as opposed to just using it), and that is their main goal, they will. There's nothing you can do to stop them. This is the nature of software; once the files that make up your product are on a user's computer they will be able to do with them as they wish. This is especially relevant in managed environments like Java or .NET, but it definitely applies to native code as well. Time is on their side, and given enough time any digital security can be broken.
Since you can't stop users from pirating your product, your best course of action is to engage this class of user in a way the uses them to your benefit. It is often possible to get them working for you rather than against you. With that in mind, no matter what your application is, it's probably worth it to keep a free version that is almost completely functional and doesn't expire. The difference between even a US$1 price tag and free is huge, if for no other reason than that the customer doesn't have to trust you with their credit card. A free edition of your product will not only effectively kill pirated distribution (why risk a pirated version when you can be legitimate for the same price?), it has the potential to dramatically expand your audience.
The result is that you may need to increase the price of the for-pay edition, so that in the end instead of 2,000 users at $20 each you have 100,000 free users, of which 500 are willing to pay $99 for the "professional" edition. This earns you more money than if you spent a bunch of time locking up your product. More than that, you can engage these free users and leverage the relationship in several important ways.
One is support. A pessimist would take this opportunity to complain about the increased cost of supporting 100,000 free users, but something amazing happens instead: your product becomes largely self supporting. You see this all the time with large open source projects that have no money for support costs. Users will step up and make it happen.
Free users generally have reduced support expectations to begin with, and for good reason. All you need to do is mark the free edition as only qualifying for community support and put up a user-moderated online forum for that purpose. Your support knowledge base is self-generating, and advanced users will shepherd those who need extra hand-holding on your behalf. Even more importantly, this will allow you to identify and correct bugs faster, ultimately improving the quality of your product and lowering total support costs. This wasn't possible before because your user base wasn't large enough, but when you treat the free users as customers it can work very well.
Another is feedback. By watching your forum, you learn important improvement ideas that you may never have considered otherwise. This can allow you to ultimately turn more of your free users into paid users and create a more compelling product that will attract an even larger audience.
Finally, you need to consider marketing. All these free users are now fans rather than adversaries, and they will act accordingly. Not only that, but when it comes time to release your next version these users will have all gone through your approved distribution channel, rather than some other unknown mechanism. That means for your next version you start out connected with a larger, highly interested and supportive audience.
The best features to reserve for the professional edition are tools aimed at making it easy to do corporate deployment and management. A cracker won't see these as a compelling enough reason to hack it for his own use, but for a business looking to buy 300 licenses and push it out company-wide this is a must-have. Of course, the professional edition will be pirated anyway, but again: don't sweat it because you probably wouldn't be able to sell the product to those pirates no matter what you did, so it's not costing you any revenue.
While psychologically it can be hard to give away your product this much, hopefully you can understand how it really is the best way to go. Not only that, it's the only way to go in the long term. I know someone is out there thinking that they don't want to do it this way. After all, they've got by just fine selling their locked-down $20 product for years. But that's just too bad, because if you don't do it this way, eventually someone else will. And their product will be just as good as yours, or close enough they can get away with claiming that. Then all of a sudden your pricing looks outrageous, sales drop dramatically, and there's nothing else you can do. You can opt for an additional middle tier if you must, but it's unlikely to help you.
In my experience, making your application or library more difficult to crack hurts your honest customers whilst only slightly delaying the dishonest ones. Concentrate on making a great, low friction product instead of putting a lot of effort into delaying the inevitable.