Skip to main content
Version: 2023.4

4.12. Debugging

4.12.1. Introduction to Debugging After Obfuscation

Assembly can be easily debugged in Debug project configuration when no obfuscation takes place.

But you may want to debug your assembly in Release configuration when obfuscation does take place. There are not many reasons to do so; however, sometimes it may be a life-saver. That's why Eazfuscator.NET supports debugging after obfuscation.

The debugging feature of Eazfuscator.NET is turned off by default to allow faster builds and better optimizations. If you want to enable debugging, then please follow the instructions below:

Instructions on enabling debug support for an output assembly

  1. Open obfuscatable project inside the IDE

  2. Add new source file to the project and call it ObfuscationSettings.cs (for C#) or ObfuscationSettings.vb (for Visual Basic .NET). You may prefer to use another name instead of ObfuscationSettings.cs or ObfuscationSettings.vb

  3. Fill ObfuscationSettings.cs with the following content (C#):

    using System;
    using System.Reflection;

    [assembly: Obfuscation(Feature = "debug", Exclude = false)]

    For Visual Basic .NET, fill ObfuscationSettings.vb with the following content:

    Imports System
    Imports System.Reflection

    <Assembly: Obfuscation(Feature:="debug", Exclude:=False)>
Note

Debugging experience may slightly suffer if used together with code control flow obfuscation feature.

4.12.2. How It Works

Eazfuscator.NET changes assembly contents during obfuscation, so the debugging information gets out of sync when no special provisions are made. If the input assembly contains an applied "debug" attribute discussed above, then Eazfuscator.NET takes care of debugging information and transforms it according to the applied assembly changes. That's why the debug information is always in sync when debug support is on for a given assembly.

The debug information is stored in a .pdb file, which is located near the assembly. For example, MyAssembly.dll may have a corresponding MyAssembly.pdb file. When you start a debug session, the debugger tries to find the .pdb files for all loaded assemblies. If the right .pdb file is found, you can set breakpoints and watch variables in the debugger.

4.12.3. Possible Security Risks

.pdb files store the following information:

  • The names of source files (including their full paths)
  • Line numbers
  • Associations between IL instruction offsets, line numbers, and source files

The names of source files can be used to find the original class names when the corresponding .pdb file is available to a reverse-engineer. So please use .pdb files with care — they can weaken the protection strength.

The security of .pdb files can be improved by using secure debugging.

4.12.4. Tuning

The debugging directive provides a basic experience by default. This is enough to quickly step through your code and spot exceptions. You may also opt-in to the improved security and readability of debugging information. To do that, please read the notes below.

The full notation of a custom attribute for debugging has the following form:

[assembly: Obfuscation(Feature = "debug [flags]", Exclude = false)]

where [flags] is an optional enumeration of flags separated by spaces.

The list of available flags is presented in the table below.

Table 4.12. The list of flags for debugging directive

Flag

Description

secure

Activates secure debugging

relative-file-paths

Instructs to produce relative file paths in resulting .pdb file

nonintrusive

Allows to perform nonintrusive debugging sessions to catch hard-to-reproduce bugs sensitive to time, size or other nonlinear factors

Secure Debugging

Debug information can be a weak point in security of an obfuscated application. But what if you want to get the line numbers and file names without compromising the security? Well, this goal is easily achievable. All you have to do is to supply [secure] flag to an obfuscation attribute like so in C#:

[assembly: Obfuscation(Feature = "debug [secure]", Exclude = false)]

or in VB.NET:

<Assembly: Obfuscation(Feature:="debug [secure]", Exclude:=False)>

What happens then? Eazfuscator.NET starts to encrypt source file names in .pdb file in the very same way as it does for other items such as class and method names. So, whenever you have symbol encryption set up for your assembly it will be also applied to the content of .pdb file.

Tip

If you do not want to apply symbol encryption to the whole assembly then just provide a password as shown below:

[assembly: Obfuscation(Feature = "debug [secure] with password XXXXXX", Exclude = false)]

Change XXXXXX with your password. Keep the password in secret. The password can contain script variables.

Obviously, the secure debugging makes stepping through the code impossible as a debugger no longer knows how to find the source files: their names are now encrypted and debugger has no means to decrypt them. This is a little sacrifice for the big benefit: all logged exceptions will contain the full information you need in an encrypted and safe form. Class names, method names, argument names, file names and line numbers are all there to help you to precisely locate the problematic code. And now you can safely distribute .pdb files to your customers without the risk of security breach.

Tip

Secure debugging is essential feature when you want to distribute .pdb files to your customers as a sole part of your product. Smaller applications surely can live without it. Applications of a larger scale, notably business-oriented ones, may have the hard times unless secure debugging is employed for the obfuscated code.

Relative File Paths

.pdb file stores the full paths of source files by default. That's an excellent idea for an interactive debugger because it can find the source files easily. However this can be an overhead when you only need stack traces or secure debugging. That's why you may prefer to save some storage bits by using relative file paths. They are shorter, as well as a resulting .pdb file. Stack traces get shorter too, their readability improves. If you use automated error reporting then you will benefit from smaller workloads. To use relative file paths, please supply [relative-file-paths] flag to an obfuscation attribute like so in C#:

[assembly: Obfuscation(Feature = "debug [relative-file-paths]", Exclude = false)]

or in VB.NET:

<Assembly: Obfuscation(Feature:="debug [relative-file-paths]", Exclude:=False)>

4.12.5. Debug Renaming

Debug renaming is a special renaming technique for debugging of obfuscated applications. The result of this technique is the presence of human readable symbol names in output assemblies. Such symbol names allow to instantly watch variables and stack traces by an unaided eye.

Debug renaming works by applying _x_ prefix to every renamed class and class member. The part of name after the prefix equals to the original name of an item.

Instructions on enabling debug renaming for an output assembly

  1. Open obfuscatable project inside the IDE

  2. Add new source file to the project and call it ObfuscationSettings.cs (for C#) or ObfuscationSettings.vb (for Visual Basic .NET). You may prefer to use another name instead of ObfuscationSettings.cs or ObfuscationSettings.vb

  3. Fill ObfuscationSettings.cs with the following content (C#):

    using System;
    using System.Reflection;

    [assembly: Obfuscation(Feature = "debug renaming", Exclude = false)]

    For Visual Basic .NET, fill ObfuscationSettings.vb with the following content:

    Imports System
    Imports System.Reflection

    <Assembly: Obfuscation(Feature:="debug renaming", Exclude:=False)>
Caution

Debug renaming is exclusively a debugging feature. Never leave this feature enabled for production assemblies; otherwise, original symbol names can leak to the outside world.