Decode Obfuscated Stack Trace

Feb 1, 2020

Obfuscation of an application is a great thing because it protects the intellectual property code, it gives you a competitive advantage and against anyone who is interested in the reverse engineering of your code. Hiding the code involves some additional issue when it comes to error reporting. In fact, a very important aspect to take into account is that the obfuscation can make application crash analisys harder to perform.

All programmers of .NET Framework knows that if the application crashes, they can analyze the stack trace to determine the cause of the error. But when the application is obfuscated most of the time the stack trace become a jumble of unreadable symbols and coming to the source of the error can be really annoying.

With Babel Obfuscator you can easily decode obfuscated stack trace generated using the usual display format. To deobfuscate the stack trace, first of all, you have to generate the mapping file of renamed symbols when the application is obfuscated. 

This can be done at command line by passing the switch mapout

babel.exe Acme.exe --mapout -tmpfeu --nooveloaded

Note that overloaded renaming is disabled (–nooveloaded). Infact oveloaded renaming protection assigns the same name to different methods and this could add some uncertainty when Babel will try to rebuild the original stack trace. If you have enabled overloaded renaming, Babel will show for each line of the decoded stack trace, all the possible methods that correspond to the most likely original method.

The map file generation can be enabled in the Babel User Interface by checking Map File in the Output tab.

Configure XML Map Files

The mapping file is an XML file that contains the association between the renamed symbol names and original ones.

This is an XML fragment of a mapping file generated during obfuscation:

<?xml version="1.0" encoding="utf-8"?>
<!--
  Babel map file.
  Generated by Babel Obfuscator version: 9.3.3.1
  Copyright © 2010-2020 babelfor.NET. All rights reserved.
-->
<BabelMap version="2.5" newNameEncoding="none">
  <TargetAssembly fullName="Acme, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f66185f16ea61c16" randomSeed="062dc683ec85f6b3" mvid="c87b28ba-a5ee-4187-8791-40021373f249" newMvid="9e8065e5-9d2b-2658-696b-952a24383324">
    <Namespace name="">
      <Class id="c1" name="&lt;Module&gt;" access="assembly" isSealed="true" />
      <Class id="c43" name="&lt;PrivateImplementationDetails&gt;" access="assembly" isSealed="true" newName="ap" newFullName="a.ap">
        <Field id="f142" name="AD6393503D9B3FAC9BE57C7B29F9105AA6BCCBF395357EFD971A39B902DE404B" type="System.Int64" access="assembly" isStatic="true" newName="fu" />
      </Class>
      <Class id="c51" name="" access="assembly" isBabelGenerated="true" newName="aw" newFullName="a.aw">
        <Field id="f147" name="" type="System.String" access="private" isBabelGenerated="true" newName="ge" />
        <Method id="m504" name=".ctor" access="public" isBabelGenerated="true">
          <ReturnType type="System.Void" />
          <Parameters>
            <Parameter name="" type="System.String" newName="gp" />
          </Parameters>
        </Method>

Note that the mapping file contains sensitive data and should be kept private, please do not distribute the map file with your application. 

As renaming generates symbol names randomly, the mapping file could be different from one obfuscation to another of the same assembly. So be sure to use the correct mapping file generated for the obfuscated application. The obfuscated stack trace could contain Unicode characters, this depends whether you configured Babel to use Unicode or ASCII symbols. Consider logging the obfuscated stack trace using Unicode or UTF8 encoding otherwise it will be impossible to reconstruct the original stack trace.

Now suppose that your obfuscated application has crashed, and you have collected an obfuscated stack trace. The stack trace has some unreadable lines due to obfuscation. To decode the stack trace and reveal the original method names to get the all the information about the exception occurred, the most straightforward way is to use the Babel User Interface.

First open the Babel UI and select Tools in the navigation panel. Browse for the XML file mapping in the XML Map Files grid. You can drag & drop the map file dirrectly in the grid. Copy the obfuscated stack trace in the text field “Obfuscated Stack Trace”. Alternatively, you can open the log file by pressing the folder Icon. The obfuscated stack trace should be formatted according the usual representation given by the Exception ToString() method:

System.Exception: (0x80131904): A network-related or instance-specific error occurred while establishing a connection to the server.
   at System.Data.SqlClient.SqlConnection.Open()
   at a.aq.fv(String gn)
   at a.ar.fx() 
   at a.ar.fw(String go)
   at a.e.get_k() 

Then press the “Deobfuscate Stack Trace” button to reveal the decoded stack trace.

Another method to decode the stack trace is to use the babel.exe command line tool. You need the stack trace log file and the XML mapping file. Then use the following command syntax:

babel.exe --stacktrace StackTrace.txt --mapin Acme.exe.map.xml

If the stack trace contains information coming from several assemblies, you can add more mapping files by entering each file using the –mapin option.

Finally, babel.exe exposes an interface that will allow you to decode the stack trace in your applications. This comes handy if you want to automate the de obfuscation of the stack trace. If you want to decode the stack trace programmatically, just add a reference to babel.exe and check out the following example code:

static int Main(string[] args)
{
    if (args.Length < 2)
    {
        Console.WriteLine("Usage: stackdecode.exe <filename> <xmlmapfile1> [xmlmapfile2 ...]");
        return 1;
    }
 
    StackTraceDeobfuscator stk = new StackTraceDeobfuscator();
 
    foreach (var xmlMapFile in args.Skip(1))
    {
        try
        {
            stk.AddMapFile(xmlMapFile);
        }
        catch (Exception ex)
        {
            Console.WriteLine(String.Format("Error reading XML map file '{0}':n{1}", xmlMapFile, ex.Message));
            return 1;
        }
    }
 
    try
    {
        StreamReader sr = new StreamReader(args[0]);
 
        Console.WriteLine("Deobfuscated Stack Trace:");
        Console.WriteLine(stk.DeobfuscateStack(sr));
    }
    catch (Exception ex)
    {
        Console.WriteLine(String.Format("Could not decode stack trace file '{0}':n{1}", args[0], ex.Message));
        return 1;
    }
 
    return 0;
}

Using PDB Files with Obfuscated Stack Trace

You can optionally use PDB files to get the source file line numbers in the decoded stack trace. To obtain the source file information you should enable the PDB file generation when obfuscating an assembly. Add a password to encrypt source file names so that you can deploy the encrypted PDB with your application. The obfuscated stack trace will display encrypted source file information not revealing the original file name to the user.

System.Exception: (0x80131904): A network-related or instance-specific error occurred while establishing a connection to the server.
   at System.Data.SqlClient.SqlConnection.Open()   
   at b.a(String g)
   at c.b() in <GFpQHv9iwQzX1Zmh+… >:line 21
   at c.a(String h)
   at Acme.ViewModel.MainViewModel.get_Message() in <GFpQHv9iwQzX1Zmh+… >:line 28 

The decoded stack trace will contain the decrypted file name.

System.Exception: (0x80131904): A network-related or instance-specific error occurred while establishing a connection to the server.
at System.Data.SqlClient.SqlConnection.Open()
at Acme.Entities.DatabaseContext.ConnectToDatabase(System.String connectionString)
at Acme.ViewModel.RS.CheckResourceLoaded() in C:AcmeAcme.ViewModelRS.cs:line 21
at Acme.ViewModel.RS.GetString(System.String name)
at Acme.ViewModel.MainViewModel.get_Message() in C:AcmeAcme.ViewModelViewModelMainViewModel.cs:line 28

You don’t need the PDB file when decoding the stack trace. All the information required to decrypt the file names is stored inside the XML map file.

Pin It on Pinterest

Share This