What are the challenges you face when working across database platforms? Take the survey
Options

Runtime problem with obfuscated product that goes away if I obfuscate with Personal edition.

esmithesmith Posts: 4 New member
edited April 20, 2021 10:02PM in SmartAssembly
Somebody else on my team will probably follow up with details. But I wanted to get the ball rolling as this is blocking us.

Version
We use SmartAssembly 7.5.2.4508.

Background
We've been using SA7 for a couple months with no problems. We used SA6 before that for years and it has gone fine.

The Problem
If we obfuscate our product with SA7 in Professional mode (licensed), the obfuscated executable fails quietly at runtime and I get this in the Windows Event Viewer for trying to run it:

Application: OurProductName.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IndexOutOfRangeException
   at SmartAssembly.StringsEncoding.Strings.GetFromResource(Int32)
   at SmartAssembly.StringsEncoding.Strings.GetCachedOrResource(Int32)
   at DynamicClass.(Int32)
   at OurName.OurProductName.Wpf.UI.App.InitializeComponent()
   at OurName.OurProductName.Wpf.UI.App.Main()

Note: The stack trace in Event Viewer was actually obfuscated.

Surprisingly, if we deactivate our SA7 license (and, to be safe, reboot the computer), then rebuild it (same source code) with SA7 in Personal edition/mode, the obfuscated product does not produce that runtime failure. This was a surprise. We discovered this oddity by accident. Is this point about Personal edition/mode helpful?

String Encoding Settings in .saproj Files
The stack trace mentions "StringsEncoding" so we tried something. Our product has multiple .saproj files. All of them were set this way regarding string encoding:

<StringsEncoding Compress="1" Encode="1" UseCache="1" UseImprovedEncoding="1" />

Those represent one radio button and three subordinate-to-it checkboxes in the SA7 user interface.

We set those all (in all of our .saproj files) to zeroes:

<StringsEncoding Compress="0" Encode="0" UseCache="0" UseImprovedEncoding="0" />

And we built that in Professional edition/mode. The build does not fail at runtime. That's good, but we need to figure out what is causing the problem because we want as much protection as possible so we'd rather not turn those string encoding options off.

We will now play with the radio button and its checkboxes to see which combination brings the problem back.

Ideas?
Based on the data I've provided, does the community or Redgate have any ideas on where to start?

Thanks!


Answers

  • Options
    esmithesmith Posts: 4 New member
    Note: The stack trace in Windows Event Viewer was actually obfuscated. I posted the decoded stack trace in my post above.

  • Options
    esmithesmith Posts: 4 New member
    edited April 21, 2021 1:53PM
    We have narrowed the problem down to one of the string encoding options — UseImprovedEncoding.

    <StringsEncoding Compress="0" Encode="0" UseCache="0" UseImprovedEncoding="0" /> works
    <StringsEncoding Compress="0" Encode="1" UseCache="0" UseImprovedEncoding="0" /> works
    <StringsEncoding Compress="0" Encode="1" UseCache="1" UseImprovedEncoding="0" /> works
    <StringsEncoding Compress="0" Encode="1" UseCache="1" UseImprovedEncoding="1" /> fails
    <StringsEncoding Compress="1" Encode="1" UseCache="1" UseImprovedEncoding="0" /> works

    This feature is presented in the SA7 UI as:
    > You can improve protection by dynamically binding the encoded strings to the assembly structure. This prevents modification of the assembly.
    > [x] I want to use strings encoding with improved protection.
    > This feature protects against assembly modification; you will not be able to post-process the built assembly.

    Any ideas as to what we should do next, Redgate folks? We would prefer to be able to use that setting. Do we need to provide a tiny sample program, or is there enough info here already to provide some guidance?
  • Options
    vahemvahem Posts: 1 New member
    edited April 21, 2021 7:05PM
    More context

    We have a WPF app which uses SmartAssembly as obfuscation framework for a long time already. It worked OK until last commit introduced this strange "IndexOutOfRangeException" during application startup. We tried to gradually reduce the lines of code in the last commit to find out the smallest possible piece of code which causes our app to crash.

    So, here are some code snippets that cause our app to crash when added.

    Note: We tried to decorate this method with [DoNotObfuscate] attribute, but it was not making any difference. There are no strings in this method, so we are quite surprised that this is causing "StringsEncoding" with "UseImprovedEncoding" to fail.

    Note 2: The method also was called from another method in this static class.

    Note 3: We tried to reproduce the issue with the help of a simple console application but we didn't succeed. But we are able to create a successful build with SmartAssembly 7.5 Pro if we exclude this method from the source code.
    public static void VisitEntriesRecursive(CFStorage storage, Action<CFItem> itemAction, List<CFStorage> substorages = null) 
    {           
                storage.VisitEntries(item => 
                {               
                    itemAction(item);            
                }, false);         
    }
    }public static void VisitEntriesRecursive(CFStorage storage, Action<CFItem> itemAction, List<CFStorage> substorages = null) 
    {            
                List<string> localSubstorages = new List<string>();
                storage.VisitEntries(item => 
                {               
                    if (item.IsStorage)
                    {      
                         localSubstorages.Add(storage.Name);
                    }           
                }, false);         
    
    Also here are some code snippets which DO NOT cause our app to crash.
    public static void VisitEntriesRecursive(CFStorage storage, Action<CFItem> itemAction, List<CFStorage> substorages = null) 
    {           
                storage.VisitEntries(itemAction(item), false);         
    }
    public static void VisitEntriesRecursive(CFStorage storage, Action<CFItem> itemAction, List<CFStorage> substorages = null) 
    {           
                storage.VisitEntries(item =>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                }, false);         
    }
    }public static void VisitEntriesRecursive(CFStorage storage, Action<CFItem> itemAction, List<CFStorage> substorages = null) 
    {            
                storage.VisitEntries(item => 
                {               
                    if (item.IsStorage)
                    {      
                         var storageItem = (CFStorage)item;
                         storage.Name?.Substring();
                    }           
                }, false);         
    
  • Options
    esmithesmith Posts: 4 New member
    Hi, Redgate. One or two people on my team posted comments here but they're not showing up. Are they stuck in a moderation bucket?
Sign In or Register to comment.