Software copy protection is a never-ending topic among developers. While it is true that perfect software copy protection is almost a dream given today's operating system and hardware infrastructure, if you are careful and use the right tools and techniques you can achieve a good degree of protection for your applications.
This article does not teach you to reinvent the wheel and implement your own copy protection techniques from scratch. Instead, it teaches you the basic principles of copy protection, and then it shows how to efficiently use free (or very cheap) tools such that you can achieve a decent degree of copy protection for your .Net applications with zero or few investments. Complete working samples written in both C# and VB.NET are attached to this article.
Step 1: Implement correct license management
License management is the most important aspect of making money out of a software application. Only you or your company should be able to generate license keys, and you must be able to enforce using each license key on one computer (or a number of computers that you choose).
Many developers resort to hiding an obscure key generation and validation algorithm into the application, or encrypting a license key with a symmetrical encryption algorithm, and then hiding the encryption/decryption key into the application for license key decryption and validation. These methods are incorrect and weak, and if a malicious party is really interested in your application the decryption keys or decoding/encoding algorithm will be extracted from your application in a matter of days since release.
License Key Generation Using Digital Signature Algorithms
The correct way to generate license keys is to use digital signatures and public/private key encryption. The problem is that the RSA algorithm is not suitable for this.
The library that I have successfully used for my licensing needs is SoftActivate Licensing SDK (from http://www.softactivate.com/ ). Unfortunately it is not completely free, but it is quite cheap compared to others which charge you an arm and a leg for the same functionality. This library generates digitally signed license keys using Eliptic Curve Cryptography (why ECC and not RSA ? Because with RSA, the generated license keys would be waay to long - like hunderds of characters long). What does this mean ? It means that there is one encryption key for license key generation and signing (which is NOT embedded in the application - it is only used at your company for generation), and a separate decryption key for digital signature verification of the license key (which is embedded in the application, but cannot be used to generate license keys, just to validate them). So even if a malicious party reverse engineers the application, they cannot generate license keys on your behalf.
Ok, we have the license key generation covered, but how to make sure that each license key is used on only one computer ? This is where product activation comes into play. Product activation essentially means "locking" each license key to only one or a maximum number of computers (most of the time via a Hardware Id).
How is product activation accomplished ? Usually, this involves your application sending the license key and hardware id of the computer on which it runs, to a licensing server. The licensing server checks if the license key is valid and how many hardware id's have been sent for this key until now (this is referred to as the number of previous activations). If the number of previous activations is lower than a certain limit, an activation key is generated by the licensing server (using the same ECC algorithm and private key used for license key generation) which takes into account the received hardware id, and then this activation key is sent to the customer's application. From this moment on, at every startup (and optionally at random times during the application execution for added security) the application checks if the activation key is valid in conjuncation with the current hardware id, and the check is made with the same public key used for license key validation. If all is ok (activation key digital signature is valid, and the hardware id matches), the application continues. If not, it exits or asks the user to activate the application.
It is important to note that when connecting to any activation or licensing server in general, the connection should be made via an authenticated method, like HTTPS. In the HTTPS case, the server should have a valid certificate which should be validated by the client application everytime it connects to the server. Another good practice is for the client to have embedded a list of IP addresses on which the licensing server can be reached, rather than a hostname, because a host name can be forged in the hosts file of the operating system (however, this not is generally possible when using HTTPS with server certificate validation).
However, by using public key cryptography to perform software activation, even forging the licensing service address is not very easy, because the private key used to generate activation keys is not available to an attacker.
The library I mentioned above also provides product activation support (and also hardware id generation resistant to hardware component replacements) and includes a licensing server which can be installed on (Windows-based) shared hosting environments, so we also have this base covered.
Step 2: Merging licensing-related assemblies within your main application executable
This is a very important step, which is used to merge sensitive assemblies into your main executable, in preparation for code obfuscation. Why must we merge the assemblies and not obfuscate each of them ? Because when you obfuscate an assembly, the public APIs of that assembly must remain unobfuscated so they can be used by other assemblies. Thus, the obfuscation will be much less effective if we keep the sensitive assemblies separate from the main executable.
For assembly merging we will be using Microsoft ILMerge tool, which is a free tool used to perform .Net assembly merging. Basically, if your executable uses some external assemblies, you can embed them into your main executable very similar to the static library linking used when you are working with native code.
Microsoft ILMerge can be downloaded from here: http://www.microsoft.com/en-us/download/details.aspx?id=17630
Here is a crucial piece of advice to make assemby merging effective: use the /internalize flag with ILMerge (see it at work in the sample's post build step). This will change the public APIs in the merged assembly such that they will become "internal", and this way the obfuscation step will not keep them unobfuscated.
Step 3: Obfuscating your .Net code
Assembly obfuscation is likely a familiar topic among .Net software developers. Obfuscation makes the assemblies unreadable with popular de-compiling tools such as Reflector. There are several obfuscation tools available, but I like to make the most out of the free ones. You must be aware that obfuscation can break the functionality of some assemblies, so you must carefully test your resulting assemblies after obfuscation.
Update: Although this was probably the most powerful free obfuscator, it seems that beginning sometimes in June 2012, it became paid software, and the price is also very high.
However, all is not lost: the latest free version (v3.3) is still available on some download sites such as here: http://www.flexdownload.com/download/eazfuscator-net.aspx
This is quite a powerful obfuscator, it supports most of the basic and advanced obfuscation techniques (renaming, string encryption, control flow obfuscation, unreadable characters) but unfortunately it has some quirks and it is quite rigid to use. If you need to obfuscate assemblies that you will later want to be "merge-friendly", you may encounter problems (ILMerge complaining). Also, you can't obfuscate already compiled assemblies with the options you want.
You can download Eazfuscator.Net (latest trial version, you can get the last free version from above) from here:
This is a basic but sufficiently powerful obfuscator, with the big advantage that it is open-source. Version 2.0 is the one to use, since the 1.5.x version does not support .Net 4.0. It is very customizable and you can set many options like skipping classes, methods, properties, namespaces, etc. even on already compiled assemblies.
You can download obfuscar from here:
DotFuscator Community Edition
This tool is included with Visual Studio. However, I would advise to just don't bother with it, it is too crippled and restrictive it its free form. It is however a very good tool if you buy it.
However, given the fact that Eazfuscator is not free anymore, I think that DotFuscator Community Edition needs further consideration as a possible free obfuscation alternative, possibly more powerful than Obfuscar. Moreover, if you register your copy of Visual Studio, you can get for free the DotFuscator Enhanced Community Edition, which adds some additional security over the non-enhanced version.
Which Obfuscation Tool to Choose ?
Often times I find myself using the code control flow obfuscation capabilities of Eazfuscator (I disable renaming and string encryption) and then I use Obfuscar to handle renaming and string encryption. This way I am ensuring maximum compatibiliy of the obfuscated assemblies.
Step 4: Strong-Naming Your Assemblies
This is a general .Net topic, so I won't go into details. However, strong naming is a mandatory step in ensuring the tamper-proofness of your assemblies. By strong-naming your assembly you ensure the fact that the assembly was not altered since it was built. Visual Studio can be used to automatically strong name the built assemblies (see the attached sample project).
More about strong naming can be found here: http://msdn.microsoft.com/en-us/library/wd40t7ad.aspx
Using the code
As a first step, make sure that Microsoft ILMerge, Eazfuscator.Net and SoftActivate Licensing SDK are installed on the development machine.
Before compiling the sample
Before compiling, copy the LicensingService subfolder under the Bin folder from the SoftActivate Licensing SDK installation folder, inside the Tools folder created by unzipping the sample.
Compiling the sample
In order to compile the sample, load the solution in Visual Studio 2010 and select the "Protected Release" build configuration. Please note that for the project to build, both Microsoft ILMerge and Eazfuscator.Net must be installed. Check the "Post Build Step" in the project properties to see if the paths to the tools are the correct ones.
The post build step does the following (only on the "Protected Release" build configuration):
- Renames the sample application into a temporary file
- Merges the sample application with the licensing assembly into one executable having the name of the application
- Obfuscates the resulting merged application
- Deletes the temporary file
Running the sample
First and foremost, you must start the licensing server by running the RunLicensingService.bat file from the Tools folder. Make sure that the paths in the .bat (to Visual Studio and to the sample folder) are set correctly ! Go to the SampleApp\bin\Protected Release folder and run the SampleApp.exe file. The sample protected file is already included in pre-compiled form in the SampleBinary folder
Studying the sample
You can use Reflector (from http://www.reflector.net/) to open the executable assembly and study the effects of assembly merging and obfuscation.
Points of Interest
One important thing to note is that in the provided sample I did not use the built-in Settings mechanism included in .Net Framework 2.0 and instead I preferred to build my own simple class. Why ? Because the built-in mechanism uses reflection. And reflection doesn't work well with obfuscation. Basically, your settings class must be excluded from obfuscation in order for it to work. This means that your settings properties become visible with a decompiling tool like Reflector, which is not desirable.
There is one important thing that I did not touch in this article, and that is how to handle trial versions of a product, how to prevent clock manipulation, etc. I intend to update this article and present some techniques for achieving this as safely as possible. However, the problem is that there isn't a perfectly safe way of doing this (without going online), almost everyone uses some obscuring techniques...but we will see what we can come up with.
June 12, 2012: Initial Release
July 11, 2012: Added VB.NET sample (in addition to the C# sample), updated information on free obfuscators
November 23, 2012: Added additional security considerations about the connection between the client application and licensing service