PreEmptive Protection - Dotfuscator 4.31
User Guide

Identify Renaming Exclusions

This page explains how to identify exclusions that need to be configured for a project. This example is focused on renaming, but the concepts can be applied to other protections as well. The example used here is for a Xamarin project, but the workflow can be applied to all applications you are protecting.

There are multiple reasons why a project would need to have renaming exclusions. One of the common reasons is some frameworks, for example Xamarin, rely heavily on reflection, which assumes that names of types and members at compile time remain the same at runtime. Dotfuscator's renaming protection applies various rules to ensure proper behavior with these scenarios. As rule improvements are introduced with releases of Dotfuscator, many cases may be handled automatically, especially if you have the latest version of Dotfuscator.

However, there may be some cases that Dotfuscator cannot detect. When this happens, you will have to exclude the problematic code items from renaming in order to maintain correct behavior of the app.

The exact renaming exclusions needed vary significantly from app to app.

General Workflow

To configure Dotfuscator's renaming protection:

  1. Enable Renaming for the project. See the Settings Tab for details.

  2. Make renaming exclusions using the Renaming Editor.

  3. Build the Dotfuscator project.

  4. Run the obfuscated app and test its behavior.

  5. Investigate any issues by consulting device logs, exception messages, or other diagnostic tools.

  6. Repeat from step 2 to continue making renaming exclusions as appropriate until the app functions normally.

Detailed Example

The advice above outlines the basics of making renaming exclusions, but it helps to have an example. Here's a detailed set of steps we took to determine renaming exclusions for BugSweeper.Android on Dotfuscator Professional Edition 4.28.2, per our Xamarin how-to. Newer versions of Dotfuscator may require fewer exclusions for this example.

  1. When we launched the protected BugSweeper.Android app on an Android device, we were greeted with this error:

    An "app crashed" dialog box in an Android emulator

    This didn't tell us much, so we dug deeper into the issue.

  2. With the device attached for USB debugging, we opened Android device log in Visual Studio. We filtered the log down to just Error and Warning for clarity.

    Visual Studio tools menu, showing Android Device Log option

    The Android Device Log, filtered to Warnings and Errors

  3. We then tried to launch the app from the device. As it crashed, we saw a number of error messages in the device log, including one starting like this:

    Caused by: android.runtime.JavaProxyThrowable: Xamarin.Forms.Xaml.XamlParseException: Position 1:426. No method OnMainContentViewSizeChanged found on type BugSweeper.BugSweeperPage
    
  4. In Dotfuscator's user interface, we manually excluded the method XamarinApp.MainPage.OnMainContentViewSizeChanged : void(object,System.EventArgs) from renaming by checking its checkbox. We then saved the config file and built the project.

    Dotfuscator showing that the method is excluded from renaming

  5. We built and redeployed BugSweeper.Android. This time, when we launched the app, we saw the following (abridged) error in the device log:

    Caused by: android.runtime.JavaProxyThrowable: System.Exception: Can't resolve name on Element
     at Xamarin.Forms.Xaml.ReferenceExtension.ProvideValue (System.IServiceProvider serviceProvider) [0x000b6] in <cdab8e5cc6744897b152dd4075cc1cb0>:0 
    ...
     at Xamarin.Forms.Xaml.Extensions.LoadFromXaml[TXaml] (TXaml view, System.Type callingType) [0x00000] in <cdab8e5cc6744897b152dd4075cc1cb0>:0 
     at BugSweeper.BugSweeperPage.b () [0x00000] in <7a7fbb7c3c1f42e59202c72d51d629fe>:0 
     at BugSweeper.BugSweeperPage..ctor () [0x00006] in <7a7fbb7c3c1f42e59202c72d51d629fe>:0 
     at BugSweeper.App..ctor () [0x00006] in <7a7fbb7c3c1f42e59202c72d51d629fe>:0 
     at BugSweeper.Droid.MainActivity.OnCreate (Android.OS.Bundle bundle) [0x0000e] in <bf5a3ea557124c988f94e73e801e2727>:0
    ...
    
  6. Based on this stack trace, we saw that the error happened during a method named b() on type BugSweeper.BugSweeperPage. As the BugSweeper source code doesn't have a method by that name on that type, we deduced this must be an obfuscated name. We opened the renaming map file (C:\code\BugSweeper\BugSweeper\BugSweeper.Android\DotfuscatorReports\Release\Renaming.xml) and looked up the appropriate module (BugSweeper.dll), name (BugSweeper.BugSweeperPage), and method (new name of b):

    <mapping>
       <module>
           <name>BugSweeper.dll</name>
           <type>
               <name>BugSweeper.BugSweeperPage</name>
               <methodlist>
                   <method>
                       <signature>void()</signature>
                       <name>InitializeComponent</name>
                       <newname>b</newname>
                   </method>
               </methodlist>
           </type>
       </module>
    </mapping>
    

    The map file indicated the original name of this method was InitializeComponent.

  7. The InitializeComponent method is called from the BugSweeperPage constructor. The contents of the method are auto-generated, but Visual Studio allowed us to navigate to it anyway by right-clicking on the call site and selecting Go to Definition:

    Using "Go to Definition" in Visual Studio

    The method contains a number of private field lookups by compile-time name (the FindByName calls):

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
    private void InitializeComponent() {
       global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(BugSweeperPage));
       mainGrid = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.Grid>(this, "mainGrid");
       textStack = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.StackLayout>(this, "textStack");
       timeLabel = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.Label>(this, "timeLabel");
       board = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::BugSweeper.Board>(this, "board");
       congratulationsText = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.StackLayout>(this, "congratulationsText");
       consolationText = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.StackLayout>(this, "consolationText");
       playAgainButton = global::Xamarin.Forms.NameScopeExtensions.FindByName<global::Xamarin.Forms.Button>(this, "playAgainButton");
    }
    

    Because Dotfuscator renames these private fields, these lookups are failing at runtime.

  8. In the Dotfuscator user interface, we created renaming rules to exclude fields on BugSweeper.BugSweeperPage whose type is in the Xamarin.Forms namespace. You can create this rule as follows:

    • In the Renaming exclusion editor, click Add Type.

    • In the type rule that appears, set the Name property to BugSweeper.BugSweeperPage and uncheck both Regular Expression and Exclude Type (the latter because our goal is to exclude members of this type, not the type name itself).

    • Right-click on the new type rule and select Add Field.

    • In the field sub-rule that appears, set the Name property to .* and the Signature property to Xamarin\.Forms\..*.

    • Click the Preview button and note that all field names corresponding to the BugSweeperPage controls are selected.

  9. We also excluded BugSweeper.BugSweeperPage.board manually by checking its checkbox.

    Dotfuscator showing the rule and the excluded fields

  10. We built and redeployed BugSweeper.Android. This time, when we launched the app, we saw the following error in the device log:

    Caused by: android.runtime.JavaProxyThrowable: Xamarin.Forms.Xaml.XamlParseException: Position 1:1803. No method OnBoardContentViewSizeChanged found on type BugSweeper.BugSweeperPage
    
  11. This is a very similar error to the one we saw in step 3. We decided to exclude all BugSweeperPage methods that begin with On, obsoleting the manual exclusion of OnMainContentViewSizeChanged we did in step 4. You can create this rule as follows:

    • In Dotfuscator's Renaming exclusion editor, right-click on the BugSweeper.BugSweeperPage type rule and select Add Method.

    • In the method sub-rule that appears, set the Name property to On.*.

    • Click the Preview button and note that all methods declared on BugSweeperPage whose names begin with On are selected.

    Dotfuscator showing the rule and excluded methods

  12. We built and redeployed BugSweeper.Android following the same process as before. This time the app ran! However, we noticed the text that reports how many bugs are left to find (e.g., "Flagged 2 out of 10 bugs.") was missing:

    BugSweeper running in an Android emulator, sans some text

  13. In our source code we noted that the BugSweeperPage.xaml file defines this text using two labels, each with a BindingContext to the board field:

    <StackLayout Orientation="Horizontal" Spacing="0" VerticalOptions="CenterAndExpand" HorizontalOptions="Center">
      <Label BindingContext="{x:Reference board}" Text="{Binding FlaggedTileCount, StringFormat='Flagged {0} '}" />
      <Label BindingContext="{x:Reference board}" Text="{Binding BugCount, StringFormat=' out of {0} bugs.'}" />
    </StackLayout>
    
  14. As we had already excluded the board field referenced here from renaming (in step 9), we decided the issue must be due to the FlaggedTileCount and BugCount properties being renamed. We excluded these manually from the Dotfuscator user interface.

    Dotfuscator showing that the properties are excluded from renaming

  15. We built and redeployed BugSweeper.Android. This time the app ran, and there were no problems when playing, winning, or losing the game.

    BugSweeper running in an Android emulator

  16. We committed all changes we've made to DotfuscatorConfig.xml to local source control.

Dotfuscator Version 4.31.0.6091. Copyright © 2017 PreEmptive Solutions, LLC