Renaming
Dotfuscator's Renaming Obfuscation changes the names of types, fields, properties, methods, and parameters within the input assemblies.
By changing meaningful names (like ComputeGdp
) to valid but meaningless names (like a
), this transform makes reverse-engineering much more difficult.
Even if an attacker decompiles your assembly, they will be missing key information about what the code elements mean and how they relate to one another.
Overload Induction
Dotfuscator's patented Overload Induction™ technique further hinders reverse-engineering by giving as many code elements as possible the same new name, even if they have no relationship to one another. For instance, consider this C# code, before and after renaming:
Original source code
private void CalcPayroll(SpecialList employeeGroup) {
while (employeeGroup.HasMore()) {
employee = employeeGroup.GetNext(true);
employee.UpdateSalary();
DistributeCheck(employee);
}
}
Decompiled code after renaming with Overload Induction
private void a(a b) {
while (b.a()) {
a = b.a(true);
a.a();
a(a);
}
}
While both are functionally equivalent, the former's intent is much clearer to an attacker.
In the latter case, it can be difficult to even know what a
is referring to in a given usage.
Enhanced Overload Induction, which is exclusive to Dotfuscator Professional, goes a step further and considers a field's type, a property's type, or a method's return type as a distinguishing characteristic among members of a type. This not only allows even more code elements to be given to the same new name, but also makes automated decompilation harder, because most source languages (including C# and Visual Basic .NET) do not allow overloading on these characteristics.
Map File
Renaming is a lossy transform - after Renaming processes an assembly, semantic information about the declared code elements are lost. This makes it a useful obfuscation technique, but can cause problems if, for instance, a user of the application provides a stack trace when they encounter an error. The stack trace would still have the obfuscated names, making diagnosing the issue much more difficult.
To allow you to interpret such scenarios, Dotfuscator produces a map file when it performs renaming. This file maps the original code element names to the new names. By preserving, but not distributing publicly, this map file with your application releases, you can decipher issues reported in production.
The format of this XML file is straightforward.
Excerpt of a renaming map file
<dotfuscatorMap version="1.1">
<mapping>
<module>
<name>DotfuscatorCommunitySample.exe</name>
<type>
<name>DotfuscatorCommunitySample.Friendly</name>
<newname>b</newname>
<methodlist>
<method>
<signature>string()</signature>
<name>get_Name</name>
<newname>a</newname>
</method>
</methodlist>
</type>
</module>
</mapping>
</dotfuscatorMap>
This excerpt describes the result of renaming: the type DotfuscatorCommunitySample.Friendly
was renamed to b
, and its method, get_Name
, was renamed to a
.
You can configure where map files are written in the user interface via the Output map section of the Options tab in the Renaming screen.
Registered users can also automatically decode stack traces produced by the obfuscated application.
Exclusions
In some cases, proper application behavior requires that certain code elements not be renamed. These cases include when an assembly is to be used as a dependency of other assemblies (such as a library), and when reflection is used to find a code element.
Dotfuscator provides a number of ways for you to exclude code elements from the renaming process:
By explicitly excluding code elements from renaming, either in the user interface or by declarative obfuscation.
By defining custom exclusion rules.
By enabling built-in rules.
By indicating an assembly is a library assembly, therefore excluding all publicly-accessible types and members.
Certain code items are never renamed:
- Assemblies
- Modules
- Names reserved by IL (such as
.ctor
for constructors)
Exclusion Rules
Exclusion rules allow you to exclude multiple code elements with a set of logical criteria. This allows you to enforce a naming policy that adapts to code changes.
There are five kinds of rules:
- Namespace rules
- Type rules
- Member rules: Method rules, Field rules, Property rules, and Event rules
- Supertype rules
- Custom Attribute rules
Certain rules can be nested within other rules. See each rule kind's subsection for details.
Namespace Rules
A type matches a Namespace Rule if the type's namespace matches the rule's Name property.
If a Namespace Rule matches a type, then the name of the type, the names of the type's members, and the names of the parameters of the type's methods are all excluded from renaming.
Child of: None (top-level rule)
Properties
Regular Expression: Controls the interpretation of the Name property.
Name:
If Regular Expression is
true
: The regular expression that namespaces of types will be matched against.If Regular Expression is
false
: The exact name that namespaces of types will be matched against.
Description: Human-readable description or explanation of the rule.
For example, consider the following rule:
- Namespace Rule
- Regular Expression:
true
- Name:
Sample(\..*)?
- Regular Expression:
This rule will match each types whose namespace is Sample
or begins with Sample.
.
In other words, the rule matches the namespace Sample
and all sub-namespaces.
The names of the types matched, along with the names of their members and the names of the parameters of their methods, will be excluded from renaming.
Type Rules
A type matches a Type Rule if all of the following are true:
The type's full name matches the rule's Name property
A type's full name includes its namespace; for example,
Sample.MyDictionary
is a type namedMyDictionary
in the namespaceSample
.A nested type's full name includes its outer type; for example,
Sample.MyDictionary/KeyValuePair
is a type namedKeyValuePair
in the type described by the previous bullet.A generic type's full name includes its type specification; for example,
Sample.IPair`2<K,V>
is a generic interface that takes 2 type parameters.
The type's attributes contain every attribute listed with a
+
prefix in the rule's Attribute specifier propertyThe type's attributes contain no attribute listed with a
-
prefix in the rule's Attribute specifier propertyThe type is a subtype of at least one type matched by one of the rule's child Supertype Rules
A type is a subtype of the type it derives from.
A type is a subtype of all interfaces it implements.
If type A is a subtype of type B, and type B is a subtype of type C, then type A is a subtype of type C.
A type is not a subtype of itself.
The type matches one of the rule's child Custom Attribute Rules
A type also matches a Type Rule if it is a subtype of another matching type and the rule's Apply to Derived Types property is true
.
If a Type Rule matches a type and the rule's Exclude Type property is true
, then the name of the type is excluded from renaming.
To exclude members of a type, additional Member Rules will need to be configured as children of the Type Rule.
If you only want to exclude the names of members, but not the name of the type, then you will still need a Type Rule, but you should set the Exclude Type property to false
.
Child of: None (top-level rule)
Properties
Regular Expression: Controls the interpretation of the Name property.
Exclude Type: If
true
, the rule will exclude the type's name. Iffalse
, the rule will still match the type (for the purposes of sub-rules), but not exclude the type's name.Apply to Derived Types: If
true
, types that derive from types that match this rule will also be matched.Name:
If Regular Expression is
true
: The regular expression that full names of types will be matched against.If Regular Expression is
false
: The exact name that full names of types will be matched against.
Description: Human-readable description or explanation of the rule.
Attribute specifier: Allows you to further restrict what the rule matches based on IL keywords.
A prefix of
+
indicates that the type must have the indicated keyword to match.A prefix of
-
indicates that the type must NOT have the indicated keyword to match.
For example, consider the following rule:
- Type Rule
- Regular Expression:
true
- Exclude Type:
true
- Apply to Derived Types:
false
- Name:
.*Provider.*
- Attribute specifier:
+public
,-generic
- Regular Expression:
This rule will match each non-generic public type whose name contains Provider
.
The name of each of these types will be excluded from renaming.
Member Rules
The term "Member Rule" is used to refer to Field Rules, Method Rules, Property Rules, and Event Rules. They differ only in the kind of members they match (Field Rules match fields, Method Rules match methods, etc.).
A member matches a Member Rule if all of the following are true:
The member's defining type matches the rule's parent Type Rule
The member is of the same kind as the rule (for example, if the member is a field, the rule must be a Field Rule)
The member's simple name matches the rule's Name property
The member's signature matches the rule's Signature property
For Field Rules, this is the name of the field's type in IL (
bool
for a Boolean field,System.DateTime
for a DateTime field, etc.)For Method Rules, the signature contains the return type as well as the parameter types (for example,
bool(int32, int32)
for a method taking two signed 32-bit integers as parameters and returning a Boolean)Not applicable for Property Rules or Event Rules
The member's attributes contain every attribute listed with a
+
prefix in the rule's Attribute specifier propertyThe member's attributes contain no attribute listed with a
-
prefix in the rule's Attribute specifier propertyThe member matches one of the rule's child Custom Attribute Rules
If a member matches a Member Rule, then it is excluded from renaming. If the member is a method, its parameter names are also excluded from renaming.
Child of: A Type Rule
Properties
Regular Expression: Controls the interpretation of the Name and Signature properties.
Name:
If Regular Expression is
true
: The regular expression that simple names of members will be matched against.If Regular Expression is
false
: The exact name that simple names of members will be matched against.
Signature:
If Regular Expression is
true
: The regular expression that member signatures will be matched against.If Regular Expression is
false
: The exact signature that member signatures will be matched against.
Description: Human-readable description or explanation of the rule.
Attribute specifier: Allows you to further restrict what the rule matches based on IL keywords.
A prefix of
+
indicates that the type must have the indicated keyword to match.A prefix of
-
indicates that the type must NOT have the indicated keyword to match.
For example, consider the following Type Rule and its child Method Rule:
- Type Rule
- Regular Expression:
true
- Exclude Type:
false
- Apply to Derived Types:
true
- Name:
Sample\.Contracts\..*
- Attribute specifier:
+abstract
- Child rules:
- Method Rule
- Regular Expression:
true
- Name:
.*
- Signature:
.*
- Attribute specifier: none
- Regular Expression:
- Method Rule
- Regular Expression:
These rules will match all methods of abstract types in the Sample.Contracts
namespace, as well as all the methods of types that derive from those abstract types (because Apply to Derived Types is true
).
The names of the matched methods, as well as the names of their parameters, will be excluded for renaming.
The name of each of the matched types will not be excluded by the rules (because the Type Rule's Exclude Type is false
).
Supertype Rules
A type matches a Supertype Rule if the type's full name matches the rule's Name property.
Supertype Rules qualify their parent rules; they do not exclude anything by themselves.
Child of: A Type Rule
Properties
Regular Expression: Controls the interpretation of the Name property.
Name:
If Regular Expression is
true
: The regular expression that full names of types will be matched against.If Regular Expression is
false
: The exact name that full names of types will be matched against.
Description: Human-readable description or explanation of the rule.
For example, consider the following Type Rule and its child rules:
- Type Rule
- Regular Expression:
true
- Exclude Type:
true
- Apply to Derived Types:
false
- Name:
.*
- Attribute specifier: none
- Child rules
- Supertype Rule
- Regular Expression:
false
- Name:
Sample.Contracts.SimpleContract
- Regular Expression:
- Supertype Rule
- Regular Expression:
true
- Name:
Sample\.IProvider.*
- Regular Expression:
- Method Rule
- Regular Expression:
true
- Name:
.*
- Signature:
string\(\)
- Attribute specifier: none
- Regular Expression:
- Supertype Rule
- Regular Expression:
The Type Rule will match all types that derive from Sample.Contracts.SimpleContract
or implement an interface whose name starts with Sample.IProvider
.
As Exclude Type is true
, the names of these types will be excluded from renaming.
Additionally, due to the Method Rule, all methods of the matched types with signature string()
will also be excluded from renaming.
However, none of the specified supertypes themselves will be excluded from renaming (unless SimpleContract
implements IProvider
, in which case the former would be excluded).
Custom Attribute Rules
A type or member matches a Custom Attribute Rule if that type or member is annotated with a custom attribute whose full name matches the rule's Name property.
Custom Attribute Rules qualify their parent rules; they do not exclude anything by themselves.
Child of: A Type Rule or Member Rule
Properties
Regular Expression: Controls the interpretation of the Name property.
Allow Inheritance: If
true
, allows derived types or overridden members of the parent rule to be matched, even if they don't fulfill this rule.Name:
If Regular Expression is
true
: The regular expression that full names of custom attributes will be matched against.If Regular Expression is
false
: The exact name that full names of custom attributes will be matched against.
Description: Human-readable description or explanation of the rule.
For example, consider the following Type Rule and its child Custom Attribute Rule:
- Type Rule
- Regular Expression:
false
- Exclude Type:
true
- Apply to Derived Types:
true
- Name:
Sample.Contracts.SimpleContract
- Attribute specifier: none
- Child rules
- Custom Attribute Rule
- Regular Expression:
false
- Allow Inheritance: Varies, see below
- Name:
Sample.Attributes.ReferenceImplementationAttribute
- Regular Expression:
- Custom Attribute Rule
- Regular Expression:
The Type Rule will match Sample.Contracts.SimpleContract
if it is annotated with Sample.Attributes.ReferenceImplementationAttribute
.
If that match happens,
If Allow Inheritance is
true
, then all types derived fromSimpleContract
will match.If Allow Inheritance is
false
, then types derived fromSimpleContract
will also match if they are annotated with that attribute.
In either case, if SimpleContract
is not annotated with ReferenceImplementationAttribute
, then no derived types will match.
Namespace Options
Dotfuscator offers three config-level options for how to handle the namespaces of renamed types.
Flatten and rename: Namespaces will be removed; all types, including those originally in different namespaces, will now all be in the global namespace.
Sample.IProvider
could be renamed toa
.Sample.Contracts.SimpleContract
could be renamed tob
.
Rename only: Namespaces will be renamed. The namespace hierarchy will remain intact, just with different names.
Sample.IProvider
could be renamed toa.b
.Sample.Contracts.SimpleContract
could be renamed toa.a.a
.
Preserve: Namespaces will not be renamed; only the simple names of types will change.
Sample.IProvider
could be renamed toSample.a
.Sample.Contracts.SimpleContract
could be renamed toSample.Contracts.a
.
Any types that are excluded will retain their original namespaces.
Property and Event Removal
A type within an assembly may declare properties and events.
Each of these code elements is associated with backing fields and methods, which are typically generated by the compiler.
For instance, a property MyProperty
may be associated with a field <MyProperty>k__BackingField
and methods get_MyProperty
and set_MyProperty
.
Other code elements usually reference the property or event through these fields and methods, rather than through the property or event itself.
Therefore, if a property or event is not excluded from renaming, then it will be removed from the output assembly. This makes it even harder to reverse engineer the assembly, because the backing fields and methods, assuming they themselves are not excluded, will have no metadata-level connection to one another.