Introduction
We explored a range of commercial and open source obfuscators such as ConfuserEX, ConfuserEX2, DotFuscatorCE, Obfuscar with varying levels of success.
One glaring issue is that none of the obfuscators have great documentation for new comers or experienced developers when things don’t work as expected. Many hours are required to hunt down solutions from places other than the authors repositories.
Visual Studio – Microsoft have bundled the DotFuscator Community Edition with Visual Studio however we are not impressed with the free version as a serious entry point to protect your works. Also we don’t like being pestered to register.
Obfuscar – Probably works but we could not get any exe’s or DLL’s to work after obfuscation and it was just too difficult to find solutions and the authors site appears to have wiped the wiki.
ConfuserEX has a number of forks available and we settled on ConfuserEX-Reborn
And to compliment ConfuserEX we installed ConfuserEX for Visual Studio from Market Place however this crashed Visual Studio 2017 frequently and when you attempt to remove obfuscation from a project it leaves an entry “exec” in the project file that prevents a successful compile. So ConfuserEX for Visual Studio caused more issues than it was worth and we uninstalled it from Visual Studio.
Our final decision was to download the source for ConfuserEX Reborn and dnlib and compile ourselves. The ConfuserEX comes with a very functional GUI that we found was great for building the Ofuscated project and finally protecting your solutions.
ConfuserEX – Reborn
Features
- Supports .NET Framework 2.0/3.0/3.5/4.0/4.5
- Supports Mono (Some feature restrictions apply)
- Symbol renaming (Support WPF/XAML/BAML)
- Protection against debuggers/profilers
- Protection against memory dumping
- Protection against tampering (method encryption)
- Control flow obfuscation
- Constant/resources encryption
- Reference hiding proxies
- Disable decompilers
- Embedding dependency
- Compressing output
- Extensible plugin API
- Many more are coming!
Protections
Anti Debug Protection
ID: anti debug
Preset: Minimum
This protection prevents the assembly from being debugged or profiled.
Parameters
mode: This parameter define the used anti debug engine. Supported values are:
- safe: ConfuserEx would detect debugger/profiler using managed API
- win32: ConfuserEx would detect debugger/profiler using unmanaged WinAPI (Incompatible with OS other than Windows)
- antinet: ConfuserEx would detect debugger/profiler using antinet by 0xd4d (Produces unverifiable modules, incompatibile with Mono)
Default is safe.
Anti IL Dasm Protection
ID: anti ildasm
Preset: Minimum
This protection marks the module with a attribute that discourage ILDasm from disassembling it.
Note that this attribute, SuppressIldasmAttribute, can be circumvented quite easily and generally not respected by modern decompilers. This protection is just here for... completeness. 😛
Parameters
This protection has no parameters.
Anti Tamper Protection
ID: anti tamper
Preset: Maximum
This protection ensures the integrity of application.
This protection encrypts the methods with the checksum of the whole module, to ensure that the module will load only if no modification has been made to it.
This protection produces unverifiable modules.
This protection is incompatible with OS other than Windows due to usage of WinAPI.
Parameters
mode: This parameter define the way ConfuserEx decrypts the methods. Supported values are:
- normal: ConfuserEx would validate the checksum and decrypt the methods at the start of application.
- jit: ConfuserEx would validate the checksum at the start of application, and decrypt the methods right before each method is being compiled using JIT hooks. (Incompatibile with Mono, and potentially future version of .NET Framework. Use with care.)
Default is normal.
key: This parameter define the way ConfuserEx derives the decryption key. Supported values are:
- normal: ConfuserEx would use static algorithms with random parameters to derive the decryption key.
- dynamic: ConfuserEx would use dynamically generated algorithms to derive the decryption key.
Default is normal.
Constants Protection
ID: constants
Preset: Normal
This protection encodes and compresses constants (numbers, strings, and initializers) in the code.
Parameters
mode: This parameter define the way ConfuserEx encode the constants. Supported values are:
- normal: ConfuserEx would use static algorithms with random parameters to encode the constants.
- dynamic: ConfuserEx would use dynamically generated algorithms to encode the constants.
- x86: ConfuserEx would use dynamically generated native x86 expressions to encode the constants. (Produces unverifiable modules)
Default is normal.
decoderCount: This parameter is an integer value defining how many constant decoder ConfuserEx would generate. Default is 5.
Since each decoder has slight differences, more decoders would make manual decoding of constants by attackers more annoying, but the result file size would increase.
elements: This parameter defines what type of constants would be encoded. Possible values are a combination of:
- S: String constants (excluding primitive constants)
- N: Numeric constants (excluding primitive constants)
- P: Primitive constants (empty strings and commonly used numbers, e.g. 0, -1, 1, 2, etc.)
- I: Array initializer (Those using RuntimeHelpers.InitializeArray)
The value is case-insensitive. For example, a value of "SI" indicates non-empty strings and initializers should be encoded. Default is "SI".
cfg: This parameter is a boolean value whether decoding of constants are based on a control flow dependent state variable. Default is false
.
Enabling it would greatly enhance the strength of protection but the runtime performance may have a impact.
Control Flow Protection
ID: ctrl flow
Preset: Normal
This protection mangles the code in the methods so that decompilers cannot decompile the methods.
Parameters
type: This parameter define how ConfuserEx mangles the method code. Supported values are:
- switch: ConfuserEx would insert a switch-base state machine to reorder the codes.
- jump: ConfuserEx would inserts jumps in methods to produce traditional spaghetti code. (Produces unverifiable modules)
Default is switch.
predicate: This parameter define how ConfuserEx store the state variable if type is set to switch. Supported values are:
- normal: ConfuserEx would use the state variable directly.
- expression: ConfuserEx would encode the state variable using dynamically generated expressions.
- x86: ConfuserEx would encode the state variable using dynamically generated native x86 expressions. (Produces unverifiable modules)
Default is normal.
intensity: This parameter is a integer value from 0 to 100, indicates how large is each split code block. Default is 60.
depth: This parameter define how deep is the generated expression if predicate is set to expression or x86. Default is 4.
junk: This parameter is a boolean value indicates whether junk codes would be inserted. Default is false
. (Produces unverifiable modules)
Invalid Metadata Protection
Name Protection
ID: rename
Preset: Minimum
This protection obfuscate the symbols' name so the decompiled source code can neither be compiled nor read.
Parameters
mode: This parameter define the way ConfuserEx renames symbols. Supported values are:
- empty: ConfuserEx would rename all symbols to a empty string.
Expect many problems when using this mode. - unicode: ConfuserEx would rename symbols to Unicode unreadable characters.
Reflection may not work in this mode. - ascii: ConfuserEx would rename symbols to readable ASCII characters.
Reflection may not work in this mode. - letters: ConfuserEx would rename symbols to English letters.
- decodable: ConfuserEx would rename symbols to decodable string. The obfuscated name mapping would be saved to output folder in the file "symbols.map".
- sequential: ConfuserEx would rename symbols to sequential string. The obfuscated name mapping would be saved to output folder in the file "symbols.map".
- reversible: ConfuserEx would encrypt the symbols. The obfuscated names could be decoded by providing the password used in obfuscation.
- debug: ConfuserEx would add an underscore before the symbols. Not intended for production use.
Default is unicode.
password: This parameter is a string value, indicates the password ConfuserEx should use to encrypt the symbol names when reversible mode is used. Only effective on modules. Default is null.
renameArgs: This parameter is a boolean value, indicates whether ConfuserEx should remove the name of methods' parameters. Default is true
.
renEnum: This parameter is a boolean value, indicates whether ConfuserEx should change the name of enum values. Default is false
.
flatten: This parameter is a boolean value, indicates whether ConfuserEx should flatten the types by removing the namespaces. Default is true
.
forceRen: This parameter is a boolean value, indicates whether ConfuserEx should rename the symbols even if the analyzer shows that it should not be renamed. Default is false
.
renPublic: This parameter is a boolean value, indicates whether ConfuserEx should rename the symbols even if the item is visible outside the assembly. Default is false
.
renPdb: This parameter is a boolean value, indicates whether ConfuserEx should rename the variable names and the file names in PDB. Default is false
.
renXaml: This parameter is a boolean value, indicates whether ConfuserEx should rename the XAML file name. Default is true
.
Reference Proxy Protection
ID: ref proxy
Preset: Normal
This protection encodes and hides references to type/method/fields.
Parameters
mode: This parameter define the way ConfuserEx hide the references. Supported values are:
- mild: ConfuserEx would add an indirection method as proxy.
- strong: ConfuserEx would add a dynamic method delegate as proxy.
- ftn: ConfuserEx would use function pointer as proxy. Not implemented yet.
Default is mild.
encoding: This parameter define the way ConfuserEx encodes the method references. Supported values are:
- normal: ConfuserEx would use static algorithms with random parameters to encode the references.
- expression: ConfuserEx would use dynamically generated expressions to encode the references.
- x86: ConfuserEx would use dynamically generated native x86 expressions to encode the references. (Produces unverifiable modules)
Default is normal.
internal: This parameter is a boolean value, indicates whether ConfuserEx should also hide internal references. Default is false
.
typeErasure: This parameter is a boolean value, indicates whether ConfuserEx should hide the types of method parameters. Default is false
.
depth: This parameter define how deep is the generated expression if encoding is set to expression or x86. Default is 3.
initCount: This parameter define how many delegate initializer should be added if mode is set to strong. Default is 16.
Resources Protection
ID: resources
Preset: Normal
This protection encodes and compresses the embedded resources.
Parameters
mode: This parameter define the way ConfuserEx encodes the resources. Supported values are:
- normal: ConfuserEx would use static algorithms with random parameters to encode the resources.
- dynamic: ConfuserEx would use dynamically generated algorithms to encode the resources.
Default is normal.
Compressor
ID: compressor
This packer reduces the size of output using LZMA compression algorithm. Only one executable module may be in the project and it would be used as the main entry module.
Parameters
key: This parameter define the way ConfuserEx derives the decryption key. Supported values are:
- normal: ConfuserEx would use static algorithms with random parameters to derive the decryption key.
- dynamic: ConfuserEx would use dynamically generated algorithms to derive the decryption key.
Default is normal.
compat: This parameter is a boolean value, indicates whether ConfuserEx should use compatibility mode that works with Mono. Default is false
.
Example: <packer id="compressor">
<argument name="main" value="<module name>"/>
<argument name="key" value="normal"/>
</packer>
Item Signatures
namespace NS1 {
class MyClass {
class NClass {
}
public string StringValue = "Value";
public static int GetInt(ref int value);
public void DoThings<T>(T[] args);
public int IntVal { get; set; }
public string this[int index] { get; set; }
public event EventHandler ValueChanged;
}
}
MyClass : NS1.MyClass
NClass : NS1.MyClass/NClass
StringValue : NS1.MyClass::StringValue
GetInt : System.Int32 NS1.MyClass::GetInt(System.Int32&)
DoThings : System.Void NS1.MyClass::DoThings<!!0>(!!0[])
IntVal : System.Int32 NS1.MyClass::IntVal()
this : System.String NS1.MyClass::Item(System.Int32)
ValueChanged : System.EventHandler NS1.MyClass::ValueChanged
So let’s say you have the following output from your project with a couple of dependant libraries:
- TheWorldsGreatest.exe
- MyCommonLibrary.dll
- MyHTMLViewer.dll
We use ILMerge to merge the two dll’s into TheWorldsGreatest.exe.
As a result we just need to obfuscate and deploy a single exe.





