3.1. Obfuscation Techniques
Eazfuscator.NET works on the CIL level so any 100% managed .NET assembly can be obfuscated. Automatic obfuscation of satellite assemblies is fully supported. Assemblies with embedded native code are not supported by Eazfuscator.NET. Obfuscated assemblies produced by Eazfuscator.NET can work on alternative .NET runtime implementations such as Mono.
Eazfuscator.NET uses several techniques to obfuscate the code.
Eazfuscator.NET automatically selects appropriate obfuscation methods for every item in .NET assembly. Not all the items can be obfuscated without breaking assembly functionality and so Eazfuscator.NET thoroughly analyzes an item before applying obfuscation transformations to it. Eazfuscator.NET has as its object to protect intellectual property to the maximum possible extent but without breaking assembly functionality. If intellectual property safety is endangered then Eazfuscator.NET produces a warning message but almost never overobfuscates at cost of breaking assembly functionality.
Let's overview main obfuscation techniques used by Eazfuscator.NET.
3.1.1. Symbol Renaming
Symbol renaming is the most powerful obfuscation method. Classes, methods, properties, fields and method's parameters get renamed with a randomly generated or encrypted title whenever it is applicable. New name usually consists of unprintable or chaotic Unicode characters.
Example 3.1. Source code retrieved with decompiler before symbol renaming
class MainForm
{
…
private bool _UseStartupShutdownEffects;
private bool _FadeDirection;
private bool _LargeFadeStep;
private System.Windows.Forms.Timer _OpacityTimer;
…
private void MainForm_Load(object sender, EventArgs e)
{
if (this.DesignMode)
return;
this.Icon = Icon.ExtractAssociatedIcon(Assembly.GetEntryAssembly().Location);
if (this._UseStartupShutdownEffects)
{
this.Opacity = 0;
this._FadeDirection = true;
this._LargeFadeStep = true;
this._OpacityTimer.Start();
}
else
{
Application.DoEvents();
Point point1 = this.Location;
this.Location = new Point(Int32.MinValue, Int32.MinValue);
this.Show();
Application.DoEvents();
this.Location = point1;
}
}
…
}
Example 3.2. Source code retrieved with decompiler after symbol renaming
class
{
…
private bool ;
private bool ;
private bool ;
private System.Windows.Forms.Timer ;
…
private void (object , EventArgs )
{
if (this.DesignMode)
return;
this.Icon = Icon.ExtractAssociatedIcon(Assembly.GetEntryAssembly().Location);
if (this. )
{
this.Opacity = 0;
this. = true;
this. = true;
this. .Start();
}
else
{
Application.DoEvents();
Point point1 = this.Location;
this.Location = new Point(Int32.MinValue, Int32.MinValue);
this.Show();
Application.DoEvents();
this.Location = point1;
}
}
…
}
There are advanced options available for symbol renaming feature.
3.1.2. String Encryption
String is one of the most widely used data type in applications. At the same time, unencrypted string values allow to easily infer the program operation with an extreme brutality. To avoid that, every string value gets encrypted during obfuscation.
Example 3.3. Source code retrieved with decompiler before string encryption
class LicenseManager
{
…
internal bool CanRun()
{
if (LicenseContainer.Get("License").IsValidFor(_CurrentCustomer))
return true;
else
return false;
}
…
}
Example 3.4. Source code retrieved with decompiler after string encryption
class LicenseManager
{
…
internal bool CanRun()
{
if (LicenseContainer.Get( . (-2942637)).IsValidFor(_CurrentCustomer))
return true;
else
return false;
}
…
}
There are advanced options available for string encryption feature.
3.1.3. Constant Literals Pruning
Constant literals pruning removes redundant meta information from the obfuscated .NET assembly whenever it is possible. This information is often not necessary at the runtime, and it is useful at compile time only. However its presence in the compiled assembly can lead to additional weakness for decompilation.
Example 3.5. Source code retrieved with decompiler before constant literals pruning
class LicenseManager
{
…
public enum Decision
{
Allow,
Deny,
UnrestrictedDeveloperMode,
Lock
}
internal Decision MakeDecision()
{
if (CanRun())
return Decision.Allow;
if (IsDeveloperSite())
return Decision.UnrestrictedDeveloperMode;
int int1 = UnlicensedRunCount;
if (int1 > MaxUnlicensedRunCount)
return Decision.Lock;
int1++;
UnlicensedRunCount = int1;
return Decision.Deny;
}
…
}
Example 3.6. Source code retrieved with decompiler after constant literals pruning
class LicenseManager
{
…
public enum Decision
{
// constant literals are gone
}
internal Decision MakeDecision()
{
if (CanRun())
return 0;
if (IsDeveloperSite())
return 2;
int int1 = UnlicensedRunCount;
if (int1 > MaxUnlicensedRunCount)
return 3;
int1++;
UnlicensedRunCount = int1;
return 1;
}
…
}
3.1.4. Overload Induction
Overload induction is a complementary obfuscation method to symbol renaming technique. Formally, overload induction algorithm minimizes the number of unique symbol names in the obfuscated assembly. As a result, obfuscated classes, fields, properties and methods may have the same name as long as it doesn't violate symbol resolution rules used by .NET runtime. Such symbol names sameness makes prying intruder absolutely entangled.
Example 3.7. Source code retrieved with decompiler before symbol renaming using overload induction
class MainForm
{
…
private bool _UseStartupShutdownEffects;
private bool _FadeDirection;
private bool _LargeFadeStep;
private System.Windows.Forms.Timer _OpacityTimer;
…
private void MainForm_Load(object sender, EventArgs e)
{
if (this.DesignMode)
return;
this.Icon = Icon.ExtractAssociatedIcon(Assembly.GetEntryAssembly().Location);
if (this._UseStartupShutdownEffects)
{
this.Opacity = 0;
this._FadeDirection = true;
this._LargeFadeStep = true;
this._OpacityTimer.Start();
}
else
{
Application.DoEvents();
Point point1 = this.Location;
this.Location = new Point(Int32.MinValue, Int32.MinValue);
this.Show();
Application.DoEvents();
this.Location = point1;
}
}
private int CalculateSize()
{
return this.Width * 2 / 3;
}
…
}
Example 3.8. Source code retrieved with decompiler after symbol renaming using overload induction
In this listing unprintable characters in symbol names were replaced with visible ones (A, B, C, …) to show up names' uniqueness distribution.
class A
{
…
private bool A;
private bool B;
private bool C;
private System.Windows.Forms.Timer D;
…
private void A(object A, EventArgs B)
{
if (this.DesignMode)
return;
this.Icon = Icon.ExtractAssociatedIcon(Assembly.GetEntryAssembly().Location);
if (this.A)
{
this.Opacity = 0;
this.B = true;
this.C = true;
this.D.Start();
}
else
{
Application.DoEvents();
Point point1 = this.Location;
this.Location = new Point(Int32.MinValue, Int32.MinValue);
this.Show();
Application.DoEvents();
this.Location = point1;
}
}
private int A()
{
return this.Width * 2 / 3;
}
…
}
3.1.5. Class Hierarchy Linerization
Class hierarchy linearization is a complementary obfuscation method to symbol renaming technique. This method is applied to the class names only. During obfuscation all the information about class namespaces is irreversibly destroyed when it's possible. After the obfuscation, all obfuscated classes are linearly located at the large root namespace, so all the information about class affiliation with application's subsystems is pruned.
Example 3.9. Source code retrieved with decompiler before symbol renaming using class hierarchy linearization
namespace MyPreciousIdea
{
namespace Licensing
{
class License
{
…
}
class Manager
{
…
}
}
namespace UI
{
class MainForm
{
…
}
class SettingsForm
{
…
}
class LicensingForm
{
…
}
}
…
}
Example 3.10. Source code retrieved with decompiler after symbol renaming using class hierarchy linearization
class
{
…
}
class
{
…
}
class
{
…
}
class
{
…
}
class
{
…
}
…
3.1.6. XML Documentation Filter
Some .NET languages provide an easy way to automatically create XML documentation for projects. You can automatically generate an XML skeleton for your types and members, and then provide summaries, descriptive documentation for each parameter, and other remarks. With the appropriate setup, the XML documentation is automatically emitted into an XML file with the same name as your project and the .xml extension. This file is located in the same directory as the output .exe or .dll file of your project.
Everything seems good until it is discovered that XML documentation file contains descriptions not only for publicly visible classes and members, but for private items too.
Eazfuscator.NET stops that threat by instantly applying XML documentation filter on every obfuscation run. XML documentation for all non-public classes, methods, fields, properties and events is automatically pruned so that essential knowledge about component internals does not leak to the rest of the world anymore. This feature is essential for component developers and publishers.
3.1.7. XAML Renaming
XAML markup language is used by WPF, Silverlight, Windows Store applications to define elements, events, data bindings, and other aspects of the user interface. XAML renaming is the process of simultaneous renaming of related symbols in code and XAML during obfuscation.
Eazfuscator.NET finds all the connections between XAML and code:
Then, the related symbols get renamed. Synchronously and consistently in code and XAML:
As a result, XAML renaming delivers higher obfuscation coverage and ensures that all related items are correctly and accordingly processed in XAML and code.