• Home
  • Products
  • The experience of using Spices.Net Obfuscator

The experience of using Spices.Net Obfuscator

Review of options,advises and recommendations

Ver: 1.2, updated 28 November 2006

Introduction

The product of 9Rays.Net company Spices.Obfuscator supplied both separately and as a part of the tool platform for .Net developer of Spices.Net has wide choice of options for protection .Net applications and class libraries.
This article is devoted to consideration of practice with recommendations on how to use these options for protection not only against reverse engineering and deobfuscation, but also for protection of algorithms and data contained in .Net assemblies.
Spices.Obfuscator is a tool for protecting different kinds of assemblies from managed C++ assemblies , ASP.Net, Windows.Forms and Compact.Framework assemblies.
The Spices.Obfuscator tools can be customized by means of ObfuscationOptions which can be seen in Spices.Project for each project assembly. Open the assembly in Spices.Net, go to section Properties, open the property AssemblyList, and then open sub-properties to get the setting options of Obfuscator of each assembly.

ObfuscationOptions.Members

Selection of member types allows to include or exclude from obfuscation the assembly members on the basis of their types. There are several standard configurations of obfuscation being under consideration in this section.

    Standalone executable file (.exe file)

    If your assembly is a standalone executable file (.exe file), it can be obfuscated with Members.Full option, in this case all the members of the assembly will be obfuscated. The only exception here is the methods, fields and properties which were inherited from external types or implement external interfaces. This is the maximum protection type that can be used for obfuscation of such types of assemblies.

    Class library

    Two sub-types of assemblies are available here:

      Assemblies-components without saving of inheritance.

      For such types of the assemblies the user can apply options Members.Default or DefaultImproved, which allow to save public members and their inheritance as well.

      Class library with saving of inheritance.

      The main problem of Reflection/Serialization is that the members of this assembly are used by name, that is why it is so important to save the members used in Reflection/Serialization. This type of assembly requires saving of the untouched class members used in serialization. For this type of the assembly the user can apply Members.KeepsSerialization option for saving public properties, public types as well as the data of enum type. As the assembly can be of mixed types and/or use one or other tool, .Net provides more flexible options for customization. The user can manually customize Members property or use other Spices.Project tools for including or excluding one or other type of the assembly member.

Assembly using Reflection or Serialization.

The main problem of Reflection/Serialization is that the members of this assembly are used by name, that is why it is so important to save the members used in Reflection/Serialization. This type of assembly requires saving of the untouched class members used in serialization.. For this type of the assembly the user can apply Members.KeepsSerialization option for saving public properties, public types as well as the data of enum type.
As the assembly can be of mixed types and/or use one or other tool, .Net provides more flexible options for customization. The user can manually customize Members property or use other Spices.Project tools for including or excluding one or other type of the assembly member.

Excluding from obfuscation

To exclude one or other type of the assembly member from obfuscation the user can apply the following tools:

  • Collection Spices.Project.Excludes Ц here you can call an embedded editor and select the required member of the assembly for exclusion.
  • Collection Spices.Project.ExclusionPatterns Ц this collection of regular expressions allows to exclude from obfuscation the members by name. Let us assume that the expression "MyCompany.MyNamespace.*" will allow to exclude all the members of the assembly, which full name will begin with MyCompany.MyNamespace.
  • Declarative exclusion - use the attributes whose original texts are supplied with Spices.Obfuscator. Just attach the attribute NineRays.Obfuscator.NotObfuscate in the original code for exclusion of the given member from Obfuscator.

    namespace MyCompany.Mynamespace
    {
      using NineRays.Obfuscator;
      [NotObfuscate]
      public class MyClass { }
    }

    For exclusion of the members of the assembly by name use the attribute NotObfuscateMembers:

    namespace MyCompany.Mynamespace
    {
      using NineRays.Obfuscator;
      [assembly:NotObfuscateMembers("MyCompany.Mynamespace.*")]
      public class MyClass { }
    }

Inclusion into obfuscation

  • Collection Spices.Project.InclusionPatterns Ц this collection of regular expressions allows to include members into obfuscation by name. Let us assume that the expression MyCompany.MyNamespace.*"will allow to include all the members of the assembly, whose full name will begin with MyCompany.MyNamespace.
  • Declarative inclusion Ц use the attributes, whose original texts are supplied with Spices.Obfuscator. Just attach the attribute NineRays.Obfuscator.SpecialName in the original code for inclusion of the given member in obfuscation.

    namespace MyCompany.Mynamespace
    {
      using NineRays.Obfuscator;
      [SpecialName("~~")]
      public class MyClass { }
    }

    To include a member of the assembly by name use the attribute ObfuscateMembers:

    namespace MyCompany.Mynamespace
    {
      using NineRays.Obfuscator;
      [assembly:ObfuscateMembers("MyCompany.Mynamespace.*")]
      public class MyClass { }
    }

Selecting type of names generation
(ObfuscationOptions.Naming)

    Spices.Obfuscator provides wide choice of tools for naming the obfuscated members. Remember, the shorter the name of the obfuscated member, the less is the size of the final assembly. For generation of shorter names the longer dictionaries are required, you may selected them in ObfuscationOptions.Naming.
    The base Numbers, Alphabetical, Alphanumeric represent sets of number symbols, ANSI-letters, as well as their combinations accordingly.
    The dictionary NonDisplayable symbols is intended to prevent viewing of your assembly in browses and receive IL-listing that could be used by the linker (ILASM). Other dictionaries are the combinations of base dictionaries used for expansion of the set and optimization of the size of the generated assembly.
    It is worth saying about CustomDictionary. The matter is that the user can apply his/her own symbol dictionary for obfuscation, this dictionary is defined as a line in the property ObfuscationOptions.CustomDictionary. For example, you can define symbols from your own national alphabet, this will allow to expand your dictionary and decrease the size of the assembly.

Creating unique assemblies
(ObfuscationOptions.MixDictionary)

    For creating unique assemblies, after each obfuscation use the option ObfuscationOptions.MixDictionary. In this case Spices.Obfuscator will "reshuffle" the dictionary for creating each time the unique combinations of symbols, which, in turn, will provide generation of the unique assembly.

Restructuring classes in namespaces
(ObfuscationOptions.NamespaceRestructuring)

Restructuring classes in namespaces is intended for breaking visual conceptual links between classes, which are usually located in the original assembly by types, that is the namespace .Data will contain classes and services working with data, and .Utils will contain classes-utilities.

  • In selecting the option ObfuscationOptions.NamespaceRestructuring.AsIs the namespace remain untouched, and the classes will be obfuscated and grouped under renamed namespaces, but they will be grouped as well.
  • ObfuscationOptions.NamespaceRestructuring.EachTypeOneNameSpace Ц each obfuscated class will be transferred to a separate namespace. This could extremely confuse an investigator, but this option increases the assembly size.
  • ObfuscationOptions.NamespaceRestructuring.AllTypesOneNamespace Ц each obfuscated class will be transferred to a single namespace. The structure of the classes will be more simple but this option will decrease the assembly size.
  • ObfuscationOptions.NamespaceRestructuring.NoNamespaces Ц All the obfuscated classes will be presented without the namespace. The class structure will be more simple, but this option will also decrease the assembly size.

Software watermarking
(ObfuscationOptions.SoftwareWatermark)

    This option allows to put УwatermarksФ into the assembly. With the help of УwatermarksФ the user can control the presence of the mark in the assembly that will confirm its originality. This option came from java-obfuscation, in which signing of assemblies to confirm its originality and integrity has not been used yet, but you can use this option to mark generated blocks with service notes, for example, "Not For Resale", "Not For Commercial Use" or, for example, for storing serial numbers or public keys.

Incremental obfuscation
(ObfuscationOptions.IncrementalObfuscation)

    Incremental obfuscation is required for developing the software products, in which substitution of system components (patching) is provided. For this purpose it is necessary to keep internal namespace invariable. Incremental obfuscation of Spices.Obfuscator uses strict algorithms for generation of invariable names, and even, if the name of a member changes, it will have the same name in obfuscation as in the previous obfuscation.

AntiILDASM
(ObfuscationOptions.antiILDASM)

    antiILDASM options are intended to prevent the use of assembly during loading to ILDASM or decompilation in the decompilers using ILDASM tools. When using minimum option antiILDASM.True, the assembly will be loaded to ILDASM, but this option will prevent creation of full IL listing in the course of disassembling. antiILDASM.Complete will prevent loading the assembly to ILDASM and decompilers, as well as obtaining the full listing.
    NB:Since v5.1.1.0 antiILDASM feature protects .Net 1.1 and 2.0 assemblies from both - 1.1 and 2.0 ILDASM's. Usage of this features is recommended.

String Encryption
(ObfuscationOptions.StringEncryptionMode)

    This option Spices.Obfuscator allows to encode string information used in your assembly. If your assembly uses encoding, saves access keys or password information, the use of StringEncryption is strongly recommended. In this case use full encoding of all strings in the assembly; this will complicate the efforts in attempt to break your assembly. There are two modes of StringEncryption:
    • StringEncryptionMode.Hide Ц this mode allows to hide the string information from methods without using encryption.
    • StringEncryptionMode.Encrypt - this mode allows to hide the string information from methods and to use string encryption.
    • StringEncryptionMode.3DES - this mode allows to hide the string information from methods and to use TripleDES cryptoalgorithm.
    Note that 9Rays.Net Company has made great efforts to reduce the effect of productivity in using StringEncryption, and, indeed, even during critical work with strings the reduction of productivity is practically unnoticeable.

Cross-obfuscation of assemblies

    Cross-obfuscation of assemblies allows to obfuscate, with simultaneous obfuscation of assembly sets, the references to assembly members that have been already obfuscated in the assembly, to which the members refer, shortly speaking to cross-obfuscate. This greatly increases the quality and level of obfuscation and allows to obfuscate public members of all assemblies (unless they are used in serialization or reflection).
    Cross-obfuscation is applied automatically to the assemblies of one project.
    So, do not ignore such a possibility, and include to Spices.Project all the assemblies of your project (excluding system and 3rd party), in this case you will receive more qualitative obfuscation.
    Cross-obfuscation is also effective in working with incremental obfuscation as in this case a single namespace will be created.

Using Spices.Solution

    Spices.Solution is a new object introduced by the company with version Spices.Obfuscator 5.0, being actually a holder of Spices.Project collection. Application of Spices.Solution is useful in simultaneous obfuscation of some projects or configuration of the same project.
    Let us assume that you have prepared the project for release. The project has several configurations with different sets of assemblies and functionality, which were compiled using conditional compilation. You have versions Evaluation, Light, Pro, Enterprise of your product. You are able to form Spices.Project for each of the versions and include them in one Spices.Solution for obfuscation at a time.

Using ObfuscationEvents

    This is another wonderful option of Spices.Project and Spices.Solution that allows to add flexibility into the process of obfuscation. Spices.Project has 10 events, Spices.Solution has 2 events of obfuscation, which allow to do operations customized by the user in obfuscation process. With the help of these events you can automate creation of the complete packet of distribution and turn obfuscation process into a conveyor to prepare your application for publication.

Spices.CodeAnonymizer technology
(Spices.Project.AnonymizeOptions)

    The technology included into a set of Spices.Obfuscator tools for protecting assemblies contains a set of methods for anonymization of data in assemblies Ц access to assembly members and external (referenced) members, creation of objects and call of methods.
    Let us see this matter in more detail to understand its efficiency:

      Anonymization of calls and access to fields

      The technology allows to anonymize access to fields and calls of methods both internal and referenced ones.
      Imagine that the referenced method System.Console.WriteLine(УHello world!Ф) will be anonymizated in x.y.p(z.s.0()).
      In processing the entire body of the method we can receive an unimaginable picture of calls, from which it will be very difficult to understand what is going on, and a assembly researcher will have to apply to each of the anonymized calls to restore the picture. This means that anonymization of the methods and field calls terrifically complicates the work of a researcher but at the same time it makes the assembly УtransparentФ for jitter and work of System.Reflection.
      You should have in mind that in using full obfuscation (obfuscation of all assembly members) it will be sufficient to anonymize only referenced members of the assembly. The technology optimizes internal calls and creates compact sets of anonymizers trying to scatter them over the whole assembly (i.e. in different classes ), which makes the work of a reseacher even more difficult.

      String encryption anonymization

      There is no secret that with the use of skilled approach the encrypted strings can be decoded to get the required result. Some deobfuscators are able to recognize a call of a simple function returning a string and receiving from it the needed result.
      The anonymizer allows to anonymize calls of decoded strings disguising more evident GetString() and object x() methods.
      In this case the methods are УscatteredФ over the whole assembly not allowing the deobfuscator to define class-container of decoding.

      Setting stubs for non-obfuscated methods (Stub methods)

      This method allows to set stubs on non-obfuscation methods and to hide an actual body of the method by replacing it with an anonymous stub. It makes efforts on decompiling and searching the method more difficult. This option is enhanced by anonymization of types and parameters that allows to hide information on transferred and returned data. Besides, this option can be enhanced by other options (ReferencedMethods, ReferencedFields, InternalMethods, InternalFields), and the body of the stub method will be also anonymized , that is its analysis will be more difficult.
      This method will be very useful for assemblies whose public members cannot be obfuscated. After processing all bodies of the non-obfuscation methods will be transferred to a secret place and replaced with stubs.

      Effect

      This is the result of processing the assembly by the program Spices.Obfuscator with the use of the methods described above:
      • The methods using calls of other methods and fields are actually divided, and a researcher expecting to get a single result receives УsandФ Ц a set of calls of stub micro methods, which it is more difficult Уto siftФ in order to get the desired result.
      • Calls of stub-methods, methods-anonymizers, calls of decoding strings are optimized and do not lead to reduction of productivity.
      • Access to external calls is hidden, which makes the bodies of the method УinsensibleФ.
      • Simultaneous use of different Spices.CodeAnonymizer methods greatly increases the degree of mess in the assemblies.

      Recommendation on using of Spices.CodeAnonymizer options

        Minimal obfuscation

        Minimal obfuscation is required for assemblies, which are used as components or libraries of classes or the assemblies using serialization of classes. In this case it is required to save untouched public members and/or the members which can be inherited or overridden. In minimal obfuscation (for example, while using ObfuscationOptions.Members = Default) additional code protection is required, in this case Spices.CodeAnonymizer will add missing gaps in protection. In this obfuscation mode it is recommended to use the following Spices.CodeAnonymizer options:
        • AnonymizerOptions.StubUntouchedMethods Ц for setting stubs on the non-obfuscated methods.
        • AnonymizerOptions.ReferencedMethods Ц for anonymization of calls of external methods.
        • AnonymizerOptions.ReferencedFields - for anonymization of calls of external fields.
        For enhancing protection it is required to switch off the following options:
        • AnonymizerOptions.KeepReturnTypes - for anonymization of the type of return data.
        • AnonymizerOptions.KeepParameterTypes - for anonymization of the type of the data transferred to the data method.
        • AnonymizerOptions.InternalMethods - for anonymization of calls of the internal methods.
        • AnonymizerOptions.InternalFields - for anonymization of calls of the internal fields.

        Full obfuscation

        In full obfuscation (with use of ObfuscationOptions.Members = Full) there is no need to use all the arsenal of Spices.CodeAnonymizer, the following options will be sufficient:
        • AnonymizerOptions.ReferencedMethods Ц for anonymization of calls of external methods.
        • AnonymizerOptions.ReferencedFields - for anonymization of calls of external fields.
        For enhancing protection the following options may be switched off:
        • AnonymizerOptions.KeepReturnTypes - for anonymization of return data.
        • AnonymizerOptions.KeepParameterTypes - for anonymization of types of the data transferring to the method.

        String encryption

        If the string encryption is used in obfuscation (StringEncryption = Hide or Encrypt) , then it is recommended to use the following option for anonymization of calls of string encryption.
        • AnonymizerOptions.StringEncryption.

Assembly optimizations

The Spices.Optimizer technology allows to dramatically optimize metadata size and increase assemblies performance. Functional tests have shown metadata optimization of up to 50%, even with conservative settings applied.

Recommendations for using the Spices.Optimizer technology:

  • Conservative(but effective) settings:

    If you are not familiar with the architecture of your assemblies, choose the Obfuscated mode for Properties, Events and Parameters.
  • Properties:

    use the Complete mode when your assembly does not contain classes used in Reflection or Serialization, or when the full obfuscation mode is used (ObfuscationOptions.Members = Full).
  • Events:

    use the Complete mode when your assemblies donТt contain classes used in the development environments and design-time, and when the full obfuscation mode is used (ObfuscationOptions.Members = Full).
  • Parameters:

    use the Complete mode when youТre sure that the parameters of the applied methods do not contain marshalling, default values, and that the parameters donТt have flags (for example Ц [in], [out]).

Conclusion

Unlike the products allowing to hide bodies of the methods such as Salamander Protector and Reactor and CodeVeil, which actually substitute the table of RVA- addresses of methods and restore it during assembly loading, as well as insert unsafe/unmanaged assembly initializer or require external initializer, Spices.Obfuscator executes such operations in the assembly. Doing so, Spices. Obfuscator optimizes internal calls, and assembly loading does not require extra optimization, that influences productivity. It should be noted that the assemblies processed by the methods described above have many disadvantages such as: they depend on the runtime version; cannot operate with ╤ompact Framework, Mono runtime; require distribution of external initializers, are not verifiable and cannot be CLSCompliant, are not scalable and transferable (the Net Framework platform itself gives these possibilities) in distinction from the assemblies generated by Spices.Obfuscator.
Some antivirus products and systems of assembly safety containing native code can be considered infected and can be prohibited for running, unlike the assemblies generated by Spices.Obfuscator.