Copyright © 2002 Remotesoft Inc. All rights reserved.
Updated on Nov 06, 2002
Microsoft .NET format (MSIL code) contains almost all of the information, apart from comments, that is in original source (C#, Visual Basic.NET, Visual C++.NET, etc) files.
One must be aware that by using a decompiler, such as our Salamander .NET decompiler, a hostile competitor can easily reverse engineer your .NET binaries and steal your intellectual properties. This is obviously a major problem that need to be addressed.
To counter this threat, it is better to obfuscate your .NET executable files (so called assemblies) before distributing your product. The obfuscation process strips all unnecessary information from .NET assemblies. This includes local variable names, method parameter names, debug information and some metadata. Additionally, class, interface, field and method identifiers are renamed to render them meaningless.
The .NET runtime that runs your MSIL code, does not care at all about these changes. However, the decompiled version of these classes is extremely difficult to understand and therefore, frustrates and complicates any attempts to reverse engineer your code.
The changes that an obfuscator makes to your assemblies are not reversible - there is no automated way for a reverse engineer to recover the lost information about your code.
An additional benefit to obfuscation is a substantial reduction in the size of your code, due to the removal of unnecessary information and the replacement of large, human-readable identifiers with small machine generated names. This size reduction is beneficial as it leads to a faster startup for your programs.
Salamander .NET obfuscator is a tool to protect your intellectual properties. It transforms your .NET assemblies (.EXE or .DLL) in such a way that decompilation of the new format would result in source codes that are extremely difficult to understand, and virtually impossible to be recompiled.
Salamander .NET obfuscator is extremely easy to use through a command-line utility that simply takes .exe, .dll or XML config files as input and transform them into new format. Extensive testing of hundreds of assemblies have proven that our .NET obfuscator always produces equivalent and obfuscated code.
The following images show the difference between the original (left panel) and the obfuscated assembly (right panel). Notice most of the identifiers are renamed to a single letter 'A'.
![]() |
![]() |
You can open one or more .NET assemblies, browse it, configure it, and then perform the obfuscation. This section shows you a tutorial for some of the common tasks.
To launch the Explorer, goto Start -> Programs -> Remotesoft -> Remotesoft .NET Explorer
From the File menu, choose Open, this starts a file dialog where you can select your file. You can also click the File Open icon in the toolbar to bring up the file dialog, or you can select a file from the most recent files in the File menu.
To open an obfuscator XML config file, from the File menu, choose Open XML Config, which will bring up a file dialog for you to choose an XML file.
Let's open our sample files, installed in c:\program Files\Remotesoft\Obfusactor\samples\MyApp. Please open the following 4 files one by one,
If the file is a valid .NET assembly, the left panel, will display a tree view that shows the class hierarchy of the assembly. If you do not see the explorer bar, go to the View menu, and select Explorer Bar. The explorer bar has three tabs: class view, metadata view, and PE Format, click the class view to browse the namespaces, classes and methods. Click the metadata tab to view the low level meta data of the assembly. The PE Format tab lists those data entries in an executable file, such as imported functions. If you open a regular Windows .exe or .dll file, which is not a .NET image, then only the PE Format tab works.
The following shows the explorer after the 4 files are opened. We are now going to do a simple config for the obfuscator, since MyModule.dll and MyPrivateLib.dll are only used internally, and thus we can mark them as private. Select those two nodes, and right click "Mark As Private".
Expand the class tree, and select a class, or any of its members, then do one of the following to disassemble the class,
Simply press the "Obfuscate" button to perform the obfuscation, you can read from the message on the rigt panel to find where the obfuscated files are stored, see below.
Name look up is vey simple. You simply click a node of your interest, and the little arrow will tell you the obfuscated name of a symbol, or the original name of an obfuscated symol. For example, type UseSimpleLib in MyApp.exe becomes a.A after obfuscation, a.A::A() corresponds to original method, UseSimpleLib::accessTest().
The package contains two components that need to install, Remotesoft .NET Obfuscator and Remotesoft .NET Explorer.
Remotesoft .NET obfuscator is a console application that currently runs only on Windows platform, including Windows NT, Windows 2K and Windows XP. It requires Microsoft .NET Framework SDK. We recommend that you obtain the latest copy of the SDK from Microsoft.
The obfuscator is extremely easy to install. Double click the downloaded .msi file, input your serial number and the installation will proceed automatically.
Remotesoft .NET Explorer is a Windows Forms application, and it is also extremely easy to install. Double click the downloaded .msi file, and the installation will proceed automatically.
Remotesoft .NET obfuscator is designed to be integrated into your build process, so that obfuscation can become a consistently applied and automatic part of your regular build and QA cycle. For this reason, it is a command line utility with simple options. For complicated situations, you can write a XML config file to control the obfuscation process.
A simple way to view obfuscation is as a phase in your build process where the interface to your .NET assemblies is specified and only that interface is left accessible to the outside world. This interface is the list of classes, interfaces, methods, fields, properties and events that you provide through custom attribute programming, or in an XML config file. If you don't customize it, the obfuscator uses default settings.
obfuscator [-verbose] [-exe] [-dll] [-d outdir] [-out
outfile] [-log] [-keepmd]
[-sign keyfile] [-delsig]
[-delaysign] [-ildasm] [-enum] [-samesize] [-nosal]
[-keepparam] [-keepdebug] [-dis] [-private file]* inputfile (inputfile)*
where:
inputfileis the filename for your original, unobfuscated .NET assembly (.exe or .dll), or the file name of your XML config file (.xml).
Options:
[-verbose] Verbose output.
[-exe] Obfuscate the input assemblies as self-contained applications, and use the strongest obfuscation level. This is the default behavior for *.exe files.
[-dll] Obfuscate the input assemblies as libraries, and do not obfuscate public members. This is the default behavior for *.dll files.
[-d outdir] Specify which directory to put the generated codes.
[-out outfile] Specify an output file, this is ignored if multiple input files are being obfuscated.
[-log] Generate a log file,
.log, into the same output directory. This is used for the text log of this obfuscation run, the file is named as <inputExeOrDll>.log.
[-keepmd] By default, some metadata, mainly properties and events, are removed. Use this option to keep those metadata in case the obfuscated code behaves differently.
[-sign keyfile] Sign input assemblies with the specified key file.
When your assembly has been already strong name signed, the obfuscated assembly will be re-signed automatically with the original keyfile. Use this option to specify a different key file. For more info, click here.
[-delsig] When your assembly has been already strong name signed, it won't work after obfuscation, choose this option to remove the signature, so you can test out the obfuscated assembly. Our standalone desktop version re-signs the obfuscated code automatically.
CAUTION: When this option is choosed, the resulting assembly will not be able to re-signed afterwards, therefore, this option should be mainly used for testing purpose in the case you are not the author of the assembly and you do not have access to the key file. For more info, click here.
[-delaysign] When your assembly has been already strong name signed, it won't work after obfuscation, choose this option so you can re-sign the obfuscated code afterwards. After you download the obfuscated assembly, you can do one of the following,
- invoke sn -Vr <assembly> to continue to work with the obfuscated assembly.
- invoke sn -R <assembly> <keyfile> to re-sign the obfuscated assembly when the key file is finally available.
[-ildasm] Prevent ILDASM-like tools from disassembling your assemblies after obfuscation. This option is only good for .exe files.
[-enum] Obfuscate enum members. In default, enum members are left unchanged.
[-samesize] Obfuscation usually results in smaller file size, which may not work sometimes, especially for mixed images. Use this option to tell the obfuscator not to shrink the file size.
[-nosal] By default, the obfuscator emit code to prevent our salamander decompiler, use this option if you do not want to prevent the decompiler from decompiling the obfuscated code.
[-keepparam] By default, method parameter names are removed, use this option if you want to keep parameter names.
[-keepdebug] By default, debug info is stripped, use this option to keep debug info.
[-dis] Disassemble the file, generate ilasm output.
[-private file] Obfuscate the depedent assembly aggressively as an internal component. This option can be used multiple times to specify more than one dependency.
If you don't like the command line, you can choose the
graphical user interfaces. Double click the dotexplorer.exe program, or start it through the
start menu start\programs\Remotesoft Obfuscator\Remotesoft .NET
Explorer. Please read the following section: Working with the Graphical
User Interfaces.
Most of the time, the obfuscation will be accomplished by a simple invocation of the obfuscator with the default settings. The following are some examples,
obfuscator SimpleTest.exe SimpleTest.exe will be obfuscated using the strongest level (.exe) with almost all symbols renamed. The obfuscated image is saved to obfuscated\SimpleTest.exe, probably with a smaller file size.
obfuscator -dll SimpleTest.exe SimpleTest.exe will be obfuscated as libraries (.dll) with public symbols unchanged. The obfuscated image is saved to obfuscated\SimpleTest.exe, probably with a smaller file size.
obfuscator -ildasm SimpleTest.exe SimpleTest.exe will be obfuscated using the strongest level (.exe) with almost all symbols renamed. The obfuscated image is saved to obfuscated\SimpleTest.exe, probably with a smaller file size. The resulting file will crash the ildasm utility, and thus won't be disassembled by ildasm.
obfuscator -private MyModule.dll -private
MyPrivateLib.dll MyApp.exe MyPublicLib.dll will perform a whole obfuscation, two files are specified as private and thus their public symbols will be fully obfuscated. These 4 files might depend on each other in a very complex fashion, but you do not care, the obfuscator will analyze the dependencies, and obfuscate cross references accordingly.
obfuscator SimpleTest.xml Take the XML config file as input, and perform obfuscation accordingly.
Due to inheritance constraints, some identifiers, mostly virtual methods, cannot be modified. For example, the public String ToString() method, an override of the System.Object class, cannot be renamed.
The log file records all of the symbols in an assembly, including the original names and the obfuscated names. You can look up the log file to find the original name from an obfuscated symbol name. We will provide a utility to help you.
In theory, obfuscation can not guarantee code equivalency. The reflection APIs, namely, certain methods of the System.Type and the System.Reflection namespace, refer to classes, methods, fields, properties and events using a string name. If your assemblies use these reflection methods to refer to identifiers, your code may behave incorrectly after obfuscation because the string name may have been changed. Obfuscator adds a warning to the log file if the above reflection methods are used in the obfuscated code. If the reflection methods act only on classes, methods, fields, properties and events that are defined in external assemblies, there will be no problem. If, however, the reflection methods act on identifiers within the assembly, these identifiers must be specified in the XML config file so that obfuscation does not change them.
When a type is declared as Serializable, its fields can not have duplicate names after obfuscation, otherwise, serialization will not work. Our obfuscator will automatically rename its fields so each of them will have a different obfuscated name. If it still does not work, you can use the keepfields attribute in the class element to specify that all of its fields should be excluded from obfuscation.
Although most of the time, a simple invocation of the obfuscator with the default settings will accomplish your obfuscation needs. However, there are situations that you may need to control the obfuscation process, for instance:
The obfuscator is designed to be highly configurable so you have full control of the obfuscation process. You can configure the obfuscator in two ways,
With custom attribute insertion, you insert certain attributes into your source code, when the obfuscator later recognizes these attributes, the obfuscation will proceed according to your specification, and all inserted code will be completely removed after obfuscation.
With XML config file, you specify your settings in an XML file, and use it as input of the obfuscator.
The attribute class, Remotesoft.ObfuscatorAttribute, is used to control the obfuscation behavior. You can apply this special attribute to an assembly, a type, a field, a method, a property, or an event, to define how the obfuscation should proceed.
namespace Remotesoft
{
/// This attribute is used to decorate a member in an assembly that is going to
/// be obfuscated. It controls how the obfuscation should be performed.
[AttributeUsage(AttributeTargets.All)]
public class ObfuscatorAttribute : Attribute
{
public string MapTo;
public bool Obfuscate;
private bool rename;
public ObfuscatorAttribute()
{
this.rename = true;
}
public ObfuscatorAttribute(bool rename)
{
this.rename = rename;
}
}
}
Programming with this attribute is simple, you insert it into your source code where you want to configure the obfuscation. The following shows a simple example, the insertion of the attribute is shown in red. In the example, method bar(int data) will not be renamed, and field pData will be renamed to "ddd" after obfuscation.
class Foo
{
[Remotesoft.ObfuscatorAttribute(false)]
void bar(int data)
{
...
}
int test(int data)
{
...
}
[Remotesoft.ObfuscatorAttribute(MapTo="ddd")]
int pData;
}
To compile the source files, you need to use a reference
to our library: Remotesoft.Obfuscator.dll, e.g.,
csc
/r:Remotesoft.Obfuscator.dll ReflectionTest.cs
The following example uses reflection methods to retrieve a field, int which. Since the default obfuscation will rename all possible identifier names including the which field, the obfuscated code will behave differently from the original assembly. In order to prevent such error, you can tell the obfuscator not to rename the specific field using the attribute, as shown below in red. When this attrbiute is present, the obfuscated assembly behaves exactly as the original file.
// csc /r:Remotesoft.Obfuscator.dll ReflectionTest.cs
using System;
using System.Reflection;
class ReflectionTest
{
[Remotesoft.ObfuscatorAttribute(false)]
int which;
[Remotesoft.ObfuscatorAttribute(MapTo="trash")]
string name;
ReflectionTest(int which)
{
this.which = which;
name = "Christina Zhang";
}
public static void Main()
{
int data = 1234;
ReflectionTest rt = new ReflectionTest(data);
try {
// use reflection to get the field value
FieldInfo fi = typeof(ReflectionTest).GetField("which", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
Console.WriteLine("You should see {0}, here: {1}", data, fi.GetValue(rt));
} catch (Exception e) {
Console.WriteLine(e.Message);
}
// display field directly
Console.WriteLine("name = {0}", rt.name);
}
}
The following image shows the obfuscated assembly, notice the which field is unchanged, and the name field is renamed to trash as specified by the ObfuscatorAttribute.
Attribute programming provides you a very simple way to configure the obfuscation during your programming circle. All of the inserted code will be completely removed from your final assembly after obfuscation.
Custom attribute insertion is simple, but it requires modification of your source code. If you do not want obfuscation to get involved into your source code, you may want to choose an XML config file to control the obfuscation process.
With XML config file, you have the most flexible way to define an obfuscation mechanism that meets your requirement.
The XML file resembles very much to the hierarchy of a .NET assembly, it contains similar elements, such as module, class, method, field, etc. In each level, you can specify how obfuscation should be done.
<?xml version='1.0'?>
<!DOCTYPE obfuscator SYSTEM "obfuscator.dtd">
<obfuscator>
<target>exe</target>
<option name="ildasm" value="false" />
<module>
<file>SimpleTest.exe</file>
<name>SimpleTest</name>
<target>dll</target>
<output>SimpleTestOB.exe</output>
<namespace obfuscate="true">
<name>Test</name>
<mapto>TestOB</mapto>
<class rename="false">
<name>SimpleTest</name>
<method rename="false">
<name>foreachTest</name>
<signature>void ()</signature>
</method>
<method rename="false">
<name regex="true">.*</name>
<attribute>public virtual</attribute>
</method>
<field rename="false">
<name regex="true">.*</name>
<attribute>private static</attribute>
</field>
</class>
<class>
<name>SimpleException</name>
<attribute>private</attribute>
<field rename="false">
<name regex="true">.*</name>
</field>
</class>
</namespace>
</module>
</obfuscator>
The following list is the DTD of the XML config file. In this section, we will explain all elements in details.
<!--
Remotesoft obfuscator XML configure file DTD. All rights reserved. March 2002 --> <!ELEMENT
obfuscator (var*, target?, option*, outdir?, nameconvention?, plugin?, module, module*)> <!ELEMENT
var EMPTY> <!ATTLIST
var name CDATA #REQUIRED> <!ATTLIST
var value CDATA #REQUIRED> <!--
target should be exe or dll --> <!ELEMENT
target (#PCDATA)> <!--
output directory --> <!ELEMENT
outdir (#PCDATA)> <!ELEMENT
option EMPTY> <!ATTLIST
option name CDATA #REQUIRED> <!ATTLIST
option value CDATA #REQUIRED> <!--
name convention to define how obfuscation name is given, the default is: A,
a, B, b, C, c, ..., A1, a1, ..., A2, a2, ... Here
you can define as many names as you want, the obfuscator will fecth them one by one, after
all names are used, a number will be appended. -->
<!ELEMENT
nameconvention (item*)> <!ELEMENT
item (#PCDATA)> <!--
ATTLIST item index CDATA #REQUIRED --> <!ELEMENT
plugin (classname, assemblyfile)> <!ELEMENT
classname (#PCDATA)> <!ELEMENT
assemblyfile (#PCDATA)> <!ELEMENT
module (file, (name | mapto)?, target?, output?, use?, (namespace | class | field | method)*)>
<!ATTLIST module obfuscate (false | true) "true">
<!ATTLIST module rename (false | true) "false">
<!ATTLIST module export (false | true) "true">
<!ELEMENT file (#PCDATA)>
<!-- output file path, relative to outdir, if absolute, then superseds outdir -->
<!ELEMENT output (#PCDATA)>
<!-- The following element is used to specify an obfuscated file for the module,
so the module will not be obfuscated, and other modules should perform
incremental obfuscation based on this obfuscated file.
-->
<!ELEMENT use (#PCDATA)>
<!ELEMENT namespace (name, mapto?, class*)>
<!ATTLIST namespace obfuscate (false | true) "true">
<!ATTLIST namespace rename (false | true) "false">
<!ATTLIST namespace keeppublic (false | true) "false">
<!ELEMENT class (name, mapto?, attribute?, (field | method | property | event | class)*)>
<!ATTLIST class obfuscate (false | true) "true">
<!ATTLIST class rename (false | true) "true">
<!ATTLIST class keeppublic (false | true) "false">
<!ATTLIST class keepfields (false | true) "false">
<!ELEMENT field (name, mapto?, attribute?)>
<!ATTLIST field obfuscate (false | true) "true">
<!ATTLIST field rename (false | true) "true">
<!ELEMENT method (name, mapto?, attribute?, signature?)>
<!ATTLIST method obfuscate (false | true) "true">
<!ATTLIST method rename (false | true) "true">
<!ELEMENT property (name, mapto?, attribute?)>
<!ATTLIST property obfuscate (false | true) "true">
<!ATTLIST property rename (false | true) "true">
<!ELEMENT event (name, mapto?, attribute?)>
<!ATTLIST event obfuscate (false | true) "true">
<!ATTLIST event rename (false | true) "true">
<!ELEMENT attribute (#PCDATA)>
<!ELEMENT signature (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ATTLIST name regex (false | true) "false">
<!ELEMENT mapto (#PCDATA)>
<!ELEMENT obfuscator (var*, target?, option*, outdir?, nameconvention?, plugin?, module, module*)>
The XML config file starts with this root element, it may contain variable definitions (<var>), global options (<option>), obfuscation target (<target>), output directory (<outdir>), name convention (<nameconvention>), plugin definition (<plugin>), and one or more module definitions (<module>).
<!ELEMENT var EMPTY> <!ATTLIST var name CDATA #REQUIRED> <!ATTLIST var value CDATA #REQUIRED>
This element defines variables to use in the XML config file. Each variable is defined using the required name-value attributes, e.g.,
<var name="workdir" value="d:\salamander\output" />
Other elements can refer to this variable using the following notation,
$(var)e.g.,
<module> ... <output>$(workdir)\SimpleTestOB.exe</output> ... </module>
The value of the variable will replace the var reference when XML file is parsed, so the above output element will have a value of d:\salamander\output\SimpleTestOB.exe
<!ELEMENT target (#PCDATA)>
The target element defines the obfuscation visibility, the value should be either exe or dll. When the target is exe, the obfuscator considers the assemblies to be self-contained, and obfuscates all possible names very aggressively, including public members, and removes all properties and events definitions. When the target is dll, the obfuscator considers the assemblies to be libraries, therefore public members are not obfuscated, and only non-public properties and events are removed. If you specify a value rather than exe or dll, an error will be thrown.
<!ELEMENT outdir (#PCDATA)>
This element specifies the ouput directory to store the obfuscated assemblies. It works together with the <output> element. If no outdir is specified, the obfuscated files will be put into a sub directory, called obfuscated , in the same directory where the original assemblies reside.
<!ELEMENT option EMPTY> <!ATTLIST option name CDATA #REQUIRED> <!ATTLIST option value CDATA #REQUIRED>
This element is used to specify the global options for the obfuscator, zero or more such elements may exist in the <obfuscator> element, a name-value pair is required to specify an option, e.g.,
<option name="ildasm" value="true" />
indicates that the obfuscator should emit code to prevent ILDASM from dissembling the obfuscated files. The global options specified in XML config file has low priority than those specified in the command line.
<!ELEMENT nameconvention (item*)> <!ELEMENT item (#PCDATA)>
This element defines how obfuscation names are given. By default, the obfuscator uses 52 letters, as shown in the following naming convention:
A, a, B, b, C, c, ..., Z, z A1, a1, B1, b1, C1, c1, ..., Z1, z1 A2, a2, B2, b2, C2, c2, ..., Z2, z2 ...
the obfuscator fetches them one by one, after all names are used, a number will be appended by the end. If you do not like the default, you can define a new naming convention here. Define as many names as you want, the obfuscator will fetch them one by one, after all are used, a number is appended.
For each name, make an <item> element, pay attention to the order as it will be the order for the name to be retrieved by the obfuscator, for example, the following name convention uses C# keywords for the obfuscated names,
<nameconvention> <item>abstract</item> <item>as</item> <item>base</item> <item>bool</item> <item>break</item> <item>byte</item> <item>case</item> <item>catch</item> <item>char</item> <item>checked</item> <item>class</item> <item>const</item> <item>continue</item> <item>decimal</item> <item>default</item> <item>delegate</item> <item>do</item> <item>double</item> <item>else</item> <item>enum</item> <item>event</item> <item>explicit</item> <item>extern</item> <item>false</item> <item>finally</item> <item>fixed</item> <item>float</item> <item>for</item> <item>foreach</item> <item>goto</item> <item>if</item> <item>implicit</item> <item>in</item> <item>int</item> <item>interface</item> <item>internal</item> <item>is</item> <item>lock</item> <item>long</item> <item>namespace</item> <item>new</item> <item>null</item> <item>object</item> <item>operator</item> <item>out</item> <item>override</item> <item>params</item> <item>private</item> <item>protected</item> <item>public</item> <item>readonly</item> <item>ref</item> <item>return</item> <item>sbyte</item> <item>sealed</item> <item>short</item> <item>sizeof</item> <item>stackalloc</item> <item>static</item> <item>string</item> <item>struct</item> <item>switch</item> <item>this</item> <item>throw</item> <item>true</item> <item>try</item> <item>typeof</item> <item>uint</item> <item>ulong</item> <item>unchecked</item> <item>unsafe</item> <item>ushort</item> <item>using</item> <item>virtual</item> <item>void</item> <item>while</item> </nameconvention>
The following image shows an example using the the above name convention.
Unicode can be used to specify the name convention, if you want to use non-displayable characters as obfuscated names, you can do something as follows, ILDASM will have trouble displaying these names, however such non-displayable characters can be easily converted by a decompiler.
<nameconvention> <item></item> <item></item> <item></item> <item></item> <item></item> <item></item> <item></item> <item></item> <item>	</item> <item> </item> <item></item> <item></item> <item> </item> <item></item> <item></item> <item></item> <item></item> <item></item> <item></item> <item></item> </nameconvention>
The following image shows an example using the above naming covention.
<!ELEMENT plugin (classname, assemblyfile)> <!ELEMENT classname (#PCDATA)> <!ELEMENT assemblyfile (#PCDATA)>
This element is used to extend the obfuscator. A
classname and an assembly file need to be specified. The class must implement
Remotesoft.IObfuscator interface. The
obfuscator will invoke the methods defined in the interface during the
obfuscation process. This way provides you with programmatic control of the
obfuscation process. In your classes, you can access many internal data
structures of the assembly.
This feature is not supported in the first version.
<!ELEMENT module (file, (name | mapto)?, target?, output?, use?, (namespace | class | field | method)*)> <!ATTLIST module obfuscate (false | true) "true"> <!ATTLIST module rename (false | true) "false"> <!ATTLIST module export (false | true) "true">
The module element specifies how the given module should be obfuscated. The term module here also refers to an assembly, since the difference of an assembly and a module is minimal, an assembly has a manifest while a module does have a manifest. An assembly at least contains one module.
The hierarchy of the module element is the same as the logical structure of a module. It may contain global fields, methods, and classes. Classes are organized in different namespaces. The term class also refers to interfaces, enums and structs.
You can define the obfuscation rules at each granularity. The rules in smaller granularity always supersede the ones in upper level. When regular expressions are used, searches are performed in the same level of hierarchy.
when this attribue is true, the module should be exported, and its public symbols should not be obfuscated; when this attribute is false, the module will be considered as an internal module, and even its public symbols will be obfuscated.
These two attributes are common to the module element and its child nodes. The obfuscate attribute defines whether the associated element and its members need to be obfuscated, the default is true. When it is false, its associated element and that element's child elements will not be obfuscated, all obfuscation rules will be ignored. The rename attribute is different from the obfuscate attribute, it tells the obfuscator whether to rename the target element when that element is obfuscatable. A target element might have a true obfuscate value, but rename is false. For example, the following specifies that the class is to be obfuscated, but keeps the class name unchanged.
<class obfuscate=true rename=false>
When rename is false, you should not specify a <mapto> element.
<!ELEMENT file (#PCDATA)>
This element specifies the input file name of the module for obfuscation. Obfuscator will load the module from this file.
<!ELEMENT output (#PCDATA)>
This element specifies the output file name to save for the module after obfuscation, if the path is relative, then it will be created under the directory specified by the <outdir> element, if the path is absolute, then it superseds the <outdir> element. When this element does not exist, the same file name is used as that of the original module.
<!ELEMENT use (#PCDATA)>
This element is used for incremental obfuscation. It specifies a previously generated obfuscated file for the module, so this module will not be obfuscated again, and other modules should perform incremental obfuscation based on this obfuscated file.
<!ELEMENT namespace (name, mapto?, class*)> <!ATTLIST namespace obfuscate (false | true) "true"> <!ATTLIST namespace rename (false | true) "false"> <!ATTLIST namespace keeppublic (false | true) "false">
A module may contain zero or more namespaces, a namespace contains at least one class. You can specify whether a namespace should be obfuscated, whether it should be renamed, and how it should be renamed.
When the keeppublic attribute is true, all public members within this namespace will be excluded from obfuscation, including all public types and their public members, recursively. This attribute is useful when you want to obfuscate everything except to keep a few namespaces.
<!ELEMENT class (name, mapto?, attribute?, (field | method | property | event | class)*)> <!ATTLIST class obfuscate (false | true) "true"> <!ATTLIST class rename (false | true) "true"> <!ATTLIST class keeppublic (false | true) "false"> <!ATTLIST class keepfields (false | true) "false">
A class belongs to a namespace, or directly to the module (the global namespace). The term class is used here in a general sense to refer to classes, interfaces, enums and structs. You can use this element to specify whether a class should be obfuscated, whether it should be renamed, and how it should be renamed.
Each class may contain zero or more fields, methods, properties, events and nested classes. By default, if the obfuscation target is exe, all classes and their members are renamed except those can not be changed, such as special method names (.ctor and .cctor), and virtual methods that are first declared in external assemblies. If the obfuscation target is dll, then all members that need to be exported to the outside will be kept unchanged, in addition to those can not be obfuscated.
When the keeppublic attribute is true, all public members within the current type will be excluded from obfuscation.
When the keepfields attribute is true, all fields within the current type will be excluded from obfuscation, including private fields. This attribute is useful, for example, hen you have trouble in dealing with object.
<!ELEMENT field (name, mapto?, attribute?)> <!ATTLIST field obfuscate (false | true) "true"> <!ATTLIST field rename (false | true) "true">
A field belongs to a class, or directly to the module (global fields). You can use this element to specify whether a field should be obfuscated, whether it should be renamed, and how it should be renamed. The signature subelement is optional.
<!ELEMENT method (name, mapto?, attribute?, signature)> <!ATTLIST method obfuscate (false | true) "true"> <!ATTLIST method rename (false | true) "true">
A method belongs to a class, or directly to the module (global methods). You can use this element to specify whether a method should be obfuscated, whether it should be renamed, and how it should be renamed. The signature subelement is required since methods are usually overloaded.
By default, methods are renamed except those can not be changed, such as special method names (.ctor and .cctor), and virtual methods that are first declared in external assemblies. For libraries, public methods are kept unchanged. If you want to overwrite the default settings, you need to use this element to define your own obfuscation rules.
<!ELEMENT property (name, mapto?, attributes)> <!ATTLIST property obfuscate (false | true) "true"> <!ATTLIST property rename (false | true) "true"> <!ELEMENT event (name, mapto?, attribute?)> <!ATTLIST event obfuscate (false | true) "true"> <!ATTLIST event rename (false | true) "true">
Properties and events belong to classes, they are usually used by tools such as compilers, the runtime does not need them. By default, if the obfuscation target is exe, all properties and events are completely removed from the assembly. If the obfuscation target is dll, then only public properties and events are kept unchanged, others are completely removed from the assembly.
<!ELEMENT attribute (#PCDATA)>
This element allows the specification of modifiers, usually the accessibility of its target, to restrict the matching process. This element can be used with a class, a field, a method, a property or an event. Only those matching the specified attributes will be processed, e.g.,
<class>
<name>SimpleTest</name>
<method rename="false">
<name regex="true">.*</name>
<attribute>
public static
</attribute>
...
</method>
</class>
The above sample code tells the obfuscator not to
obfuscate all public and static methods in class SimpleTest.
The legal values of this element is shown below depending on its target. A list of values separated by a space, ' ', might be used for this element as well, in which case all of attributes should be matched.
| attribute | class | field | method | property | event |
| public | yes | yes | yes | yes | yes |
| private | yes | yes | yes | yes | yes |
| family | yes | yes | yes | yes | yes |
| assembly | yes | yes | yes | yes | yes |
| famandassem | yes | yes | yes | yes | yes |
| famorassem | yes | yes | yes | yes | yes |
| nested | yes | ||||
| interface | yes | ||||
| sealed | yes | ||||
| static | yes | yes | yes | yes | |
| abstract | yes | yes | yes | yes | yes |
| virtual | yes | yes | yes | ||
| final | yes | yes | yes |
<!ELEMENT signature (#PCDATA)>
This element is used to specify a signature for field, method, property or event. You must specify a signature when you define <method> element, but signature for fields, properties and events definitions are optional.
Signature is defined using C# convention, e.g.,
<signature> String(int, String[]) </signature>
Parameter names can be ignored, types will be automatically resolved from the class and module where this method is defined, therefore you can use simple type names.
<!ELEMENT name (#PCDATA)> <!ATTLIST name regex (false | true) "false">
This element defines a name for identifiers. When the regex attribute is true, matches will be searched in its enclosing element level, for example, if you define a <method> element in a <class> element with a regular expression method name, all methods in that class will be searched to match the regular expression, and the obfuscation rules will be performed to those methods.
<!ELEMENT mapto (#PCDATA)>
This element specifies a name to be used for an identifier after obfuscation.
This feature provides you with the most powerful way to control the obfuscation process. You write your own code to define the renaming process.
This feature is not supported in the first release.
Associated with your assembly or module files, there are other types of sattelite files need to be handled. Fortunately, our obfuscator deals with them automatically. What you need to do is make sure that these files can be accessed from the current directory.
There is no special handling for resource files, our obfuscator handles them automatically in most situations. Sometimes, when a literal resource name is used, you will need to preserve certain namespaces or classes.
In this section, we'll show you how to trouble shoot resource problems through an example, WinCV.exe, distributed with Microsoft .NET Framework SDK.
First, let's simply use the default settig to obfuscate it, as shown below. Notice the resource name is automatically renamed to A.B.resources to reflect the namespace obfuscation (see the red circle).

Second, test run the program. Simply click the "!" button to launch the program, we will see a JIT debug dialog box, select a debuuger, and the following error message appears. Obviously, the resource "Microsoft.Tools.SR" is mising, and thus the program can not run successfully. This indicates that the obfuscation has not performed correctly.
Using our decompiler, and we locate that the resource is refered through the following statement,
resources = new ResourceManager("Microsoft.Tools.SR", base.GetType().Module.Assembly);
Since the resource name, Microsoft.Tools.SR, is refered as a literal string, however, the obfuscation we just performed automatically change the resource name to A.B, no wonder the program won't run after obfuscation. In this case, we have to preserve the resource name. Right click the "Microsoft.Tools.SR" class node, and select "Preserve" menu item, as shown below,


Our obfuscator deals with strong named assemblies automatically, no extra work is required.
Usually,
attaching a strong name signature to your code involves two steps:
(1) create the strong name key using the SN
utility: sn -k sample.snk
(2) compile your assembly with the key by adding a
declaration to the assembly to indicate the location of the key file, as shown
below,
C#:
[assembly: AssemblyKeyFile("sample.snk")]
class StrongNameTest
{
...
}
VB.NET:
<assembly: AssemblyKeyFile("sample.snk")>
Public Class StrongNameTest
...
End Class
Just make sure that your key file is in the correct
path when the obfuscator is invoked, and our obfuscator will
automatically re-sign the modified assembly with the same key file. If you do
not have access to the key file, you can choose to delay sign the protected
assembly, or choose to remove the signature, so you can continue to work with
the obfuscated code.
Remotesoft .NET Explorer is a generic object browser and disassembler with professional look and feel. It offers the same functionality as Microsoft ILDASM utility, plus low level viewing of metadata and PE format. Remotesoft .NET Explorer works together with our decompiler, obfuscator and protector, and acts as a console for easy navigation and powerful code editing and printing. This tool can be used as a source code editor, and it has a powerful syntax coloring system that recognizes many popular source files, including IL, C#, C/C++, VB, ASP, JAVA, HTML, FORTRAN, PHP, etc.
Remotesoft .NET Explorer works together with our protector, and act as a console.
Remotesoft .NET Explorer can be used alone as an assembly browsing and disassembling utility. In this regard, you can consider it to be something like Microsoft ILDASM, but with more functionality. It supports viewing of low level metadata, and most of all, it allows modification of the loaded assemblies.

Remotesoft .NET Explorer has built-in support for viewing low level .NET metadata. The following is a screen shot that shows the string heap of the selected assembly. A hex dump of the file is display in the lower right pane.

Remotesoft .NET Explorer has built-in support for viewing low level PE (Portable Executable) format. It recognizes both .NET images and native images that are compile from C/C++. The following is a screen shot shows the CLI header of the selected assembly. A hex dump of the file is displayed in the lower right pane..
You can use the explorer to configure and perform the obfuscation interactively, then view the result immediately. If you are not satisfied with the result, you may change your config and redo the obfuscation. After you are done with config, simple click the "obfuscate" button to perform the obfuscation.
Integrated with the obfuscator, Remotesoft .NET Explorer
provides a console to facilitate the obfuscation process. You can use it to
configure the obfuscation, then either performs the obfuscation immediately, or
save the XML config file, and use the command line to perform the obfuscation.
Name preservation
As we discussed earlier, certain symbols have to be excluded from obfuscation in some situations. Remotesoft .NET Explorer allows you to preserve any symbols very easily. Select any namespace, class, method or field node, right click and then select Preserve menu, the selected symbol will be preserved from obfuscation. A symbol with name preservation will be marked with red color. Use the same menu to remove a name preservation.
As shown below, the left panel shows how to preserve a class name, so that class will not be renamed after obfuscation. The right panel shows the results of the obfuscation, notice the selected class name is indeed kept unchanged.
![]() |
![]() |
Use the MapTo menu, to create a name mapping for a symbol, so that symbol will be named to your specification after obfuscation.
As shown below, the left panel shows how to map a class name, so that class will be renamed as you specified after obfuscation. The right panel shows the results of the obfuscation, notice the selected class indeed have the obfuscated name as specified.
![]() |
|
|
![]() |
||
Select a top level module node, and use the Mark As Private to mark/unmark a private module. When a module is marked as private, it indicates that the selected module is an internal component, and thus its public symbols will be fully obfuscated. Cross references from other modules will be obfuscated accordingly.
Private modules are marked with a closed diamond icon.

When you are satisfied with the config, you can use the Save XML Config menu to save the XML config file. This file has the format as described above.
A saved XML config file can be opened using the Explorer, and it can be also used as an input file for obfusactor command line.
Incremental obfuscation allows you to obfuscate a new assembly in consistent with the previous obfuscation results, and therefore you can perform hot fixs by distributing a small patch to your customers. This is extremely useful when your products consist of a few assemblies, and later you need to modify one of them or add a new assembly.
The incremental obfuscation will help, when your products consist of multiple assemblies, and later, you want to ship a new component to customers, but without redistributing those components your customers already have. Therefore, you want to obfuscate the new component based on the name maps generated from the last run.
Most obfuscators requires you to save a complete log file with all name mappings in order to perform an incremental obfuscation. These kind of log files are hard to maitain. Fortunately, our obfuscator does not rely on any logs, and it is extremely easy to perform incremental obfusaction. Instead of any log files, our obfuscator uses the original and obfuscated assemblies that you already have to perform incremental obfuscation. You simply need to specify an obfuscated file that has been previously generated for a module.
In this section, we give an example of doing incremental obfuscation. Use .NET Explorer to open UseSimpleLib.xml from the samples folder in Remotesoft Obfuscator installation directory.
UseSimpleLib.exe (compiled from UseSimpleLib.cs) refers to assembly SimpleLib.dll (compiled from SimpleTest.cs). The XML config file, UseSimpleLib.xml, performs the obfuscation with SimpleLib.dll as private component, and thus both UseSimpleLib.exe and SimpleLib.dll are obfuscated completely. Click the "Obfuscate" button, the obfusacted code will be saved to samples\obfusacted folder

Now, you are ready to ship the obfuscated images, UseSimpleLib.exe and SimpleLib.dll, to your customers.
After some period, you find that you need to add one more method into UseSimpleLib.exe, see the new source code in UseSimpleLib1.cs. One way is to perform the same obfusaction as before, and re-ship both images again. However, the best way would be to tell your customers to ony update the modified component, UseSimpleLib.exe. Now, you will have to perform an incremental obfusaction using the previous run.
The following are steps to perform an incremental obfuscation.
1. Right click a module node that you want to use an exisiting obfuscated file. In our example as shown below, right click "Set Incremental File..." on SimpleLib.dll

2. A file dialog will appear, and you can select the obfuscated file from previous obfusaction run, in our case, choose "samples\obfuscated\SimpleLib.dll". After the file is set, the tree node will be colored as pink.

3. Simply click the "Obfuscate" button to perform the obfuscation,

4. You can now use "Save XML Config..." from the "File" menu to save the configuration, which can be later on opened through "Open XML Config...", or used in a batch process.
With this utility, you can easily look up the original/obfuscated symbol names.
1. Go to "Tools", "Name Utility" to open the utility
2. Input the original/obfuscated file names, you can also browse to selecy a file
3. Click the "OK" button, and the two modules will be loaded, click a node to see the orginal/obfuscated symbol names.