Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

7 Ways to Protect your .NET Code from Reverse-Engineering

16 Mar 2011 0  
If you’re about to release your software internationally and it’s written in .NET, then you ought to consider protecting your code and IP. This article outlines 7 ways to protect your .NET code from reverse-engineering and other malicious forms of attack.

Introduction

If you are making your software available internationally, and your software is written in .NET (which is particularly easy to decompile), then you ought to consider protecting your code. You can protect your code in various ways, including obfuscation, pruning, resource encryption, and string encoding. In this article, we will show you 7 different ways to protect your Intellectual Property against reverse-engineering, theft, and modification, by using just one tool: SmartAssembly.

Obfuscation

Obfuscation is a classic code protection technique used to make your code hard to read. Obfuscation changes the name of your classes and methods to unreadable or meaningless characters, making it more difficult for others to understand your code.

SmartAssembly offers a choice between type/method name mangling and field name mangling.

 

Obfuscating type and method names

SmartAssembly offers three levels of obfuscation for type names and method names:

ASCII characters Renames types and methods using ASCII characters. For example, the type FullScreenSplash might be obfuscated to #dc.

Note: you must choose this option if you want to be able to decode stack tracks after obfuscation.

Unicode unprintable characters Renames types and methods using Unicode unprintable characters. For example, the type FullScreenSplash might be obfuscated to U+1D11E (which is unprintable).
Unicode unprintable characters and advanced renaming algorithm Renames types and methods using Unicode unprintable characters, and renames multiple items with the same name. For example, the types FullScreenSplash and FontStyle are both obfuscated to U+017D.

The following example shows code before and after type/method name mangling:

Before obfuscation:

C#
public ClientLicence GetLicence(ItemType type);

public bool IsFileInProject(string fileName);

public void ResolveAssemblyReferences();

public void Save();

private void SetMemento(Properties memento);

public void Start(bool withDebugging);

private void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink);

After obfuscation:

It is not possible to display unprintable characters. For the purpose of this example, unprintable characters are represented by an asterisk (*).

C#
public ‑.‑ *(‑.‑);

public bool *(string);

public void *();

public void *();

private void *(‑.‑);

public void *(bool);

private void *(‑.‑,‑.‑);

To check that your code has been obfuscated properly, you can use Red Gate’s .NET Reflector (a tool for disassembling .NET executables).

Obfuscating Field Names

Again, in order to give you more control over the level of obfuscation strength, SmartAssembly offers three different schemes for renaming field names:

One-to-one renaming schemeChanges all fields in all classes so that they have different names. A field's name is unique within an assembly.

Note: you must choose this option if you want to be able to retrieve the original field names from stack traces.

Standard renamingAlters the field name so that it is unique within a class; however the same name is often used within other classes in the assembly. For example, #a: string, #b: boolean, #c: string, #d: boolean.
Advanced renamingAlters the field name, however it not unique within a class and is reused. Fields of a different type will have the same name. For example, #a: string, #a: boolean, #b: string, #b: boolean.

Control Flow Obfuscation

In additional to renaming crucial parts of your code, you can also use Control Flow Obfuscation. This technique changes the code inside your methods, converting it into a complex and tangled control structure (spaghetti code). After Control Flow Obfuscation, you can execute your application in exactly the same way as before, but it is now very difficult for anyone else to analyze your code, and almost impossible for a decompiler to recreate the original source code.

Control Flow Obfuscation prevents most programs from being able to disassemble the code. For example, attempting to disassemble control flow obfuscated code using .NET Reflector will give:

C#
private static void Main() 
{ 
// This item is obfuscated and cannot be translated. 
}

String Encoding

Managed software stores all strings in one place and in a clear structure. By following the references to these strings, it is then possible to understand the purpose of your code, even after obfuscation. These strings can reveal important information, such as passwords, SQL requests, serial numbers, or login information. String Encoding protects the strings by encoding them.

The examples below show the effect of encoding three strings within an assembly:

Before String Encoding:

C#
"Fred.gate@hotmail.com"
"p@ssw0rd1"

"licensingUrl=http://licensing.red-gate.com/licensingactivation.asmx"

After String Encoding:

"FNRFk1TTJZM016VTPQ==.bmV1dSBzcGVjaWZpZWQ9sbGVjdGlvbi4=L"

References Dynamic Proxy

If you make calls outside of your assembly, these calls will still be visible in your code after String Encoding and Control Flow Obfuscation. For example, if you make a call to a message box, it would still be possible to find that call in the disassembled application, even with String Encoding and Control Flow Obfuscation enabled. By following external calls like this, it may still be possible for other people to understand parts of your code.

Reference Dynamic Proxy is a unique protection feature offered by SmartAssembly that allows you to hide most of the calls to external methods, properties, or fields in your code, by replacing them with calls to the proxy. By using this type of protection, you can make it very difficult for someone to find calls such as a trial expiry dialog, which could unintentionally offer clues about where to break in.

Pruning

Pruning automatically scans your software and removes any code that will never be executed at runtime. This includes removing non-useful metadata, such as the names of events, properties, and method parameters that would give someone else clues about what particular types and methods are for.

Resource Compression and Encryption

This feature compresses and encrypts your managed resources. This reduces the size of the assembly and makes the code harder to understand.

Dependency Merging

Dependency Merging allows you to choose particular DLLs, then merges them into one executable, giving you performance benefits because you don't have to load lots of DLL files. After merging, the dependency is inseparable from the main assembly.

Dependency Merging is not a protection feature per se, but it is it a lot easier to obfuscate and prune your code if you have one assembly, rather than several smaller DLLs. (If you want to obfuscate several assemblies without merging them, you will need to create several SmartAssembly projects.)

Conclusion

In this article, we have shown how you can use SmartAssembly to protect your intellectual property by obfuscating your code, hiding most calls to external methods, encoding strings, removing unessential code, and compressing and encrypting resources.

To try SmartAssembly on your own software, simply download a 14-day free trial from Red Gate’s website.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here