PreEmptive Protection - Dotfuscator
Community Edition User Guide

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.

Note: It is important to test your application after Renaming, because some applications and frameworks rely on certain code elements having their original names at runtime. In these cases, you will need to exclude those code elements from renaming.

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 Edition, 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>DotfuscatorCommunityEditionSample.exe</name>
            <type>
                <name>DotfuscatorCommunityEditionSample.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 DotfuscatorCommunityEditionSample.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.

Dotfuscator Professional Edition also offers the ability to 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:

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:

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(\..*)?

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, e.g., Sample.MyDictionary is a type named MyDictionary in the namespace Sample.

    • A nested type's full name includes its outer type, e.g., Sample.MyDictionary/KeyValuePair is a type named KeyValuePair in the type described by the previous bullet.

    • A generic type's full name includes its type specification, e.g., 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 property

  • The type's attributes contain no attribute listed with a - prefix in the rule's Attribute specifier property

  • The 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. If false, 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

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 (e.g., 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 (e.g., 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 property

  • The member's attributes contain no attribute listed with a - prefix in the rule's Attribute specifier property

  • The 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

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
      • Supertype Rule
        • Regular Expression: true
        • Name: Sample\.IProvider.*
      • Method Rule
        • Regular Expression: true
        • Name: .*
        • Signature: string\(\)
        • Attribute specifier: none

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

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 from SimpleContract will match.

  • If Allow Inheritance is false, then types derived from SimpleContract 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 project-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 to a.

    • Sample.Contracts.SimpleContract could be renamed to b.

  • Rename only: Namespaces will be renamed. The namespace hierarchy will remain intact, just with different names.

    • Sample.IProvider could be renamed to a.b.

    • Sample.Contracts.SimpleContract could be renamed to a.a.a.

  • Preserve: Namespaces will not be renamed; only the simple names of types will change.

    • Sample.IProvider could be renamed to Sample.a.

    • Sample.Contracts.SimpleContract could be renamed to Sample.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.



Dotfuscator Version 5.27.0.4713. Copyright © 2017 PreEmptive Solutions, LLC