SmartAssembly does not seem to obfuscate internal property in an internal class

Hi,

We're evaluating SmartAssembly. Until now everything works perfectly - except for one scenario:
The tool doesn't seem to obfuscate internal properties in an internal class in a c# class library.

I've attached a sample solution with a sample saproj file. SmartAssembly correctly obfuscates class and method names. However, the internal properties are just left with their original name.

Could you please clarify - or point me in a direction on how to solve this.

Many thanks!

- sol
Tagged:

Answers

  • sol_smartsol_smart Posts: 8 New member
    P.s. I know about the ForceObfuscate attribute and that also seems to force the property to be renamed properly when obfuscating. However, it is not feasible/scalable for us to apply that attribute manually to all properties.

    Also, another question: We have some scenarios where an internal interface is also not renamed during obfuscation. I was not able to reproduce it outside our application. But I was wondering why the ForceObfuscate is not applicable to interfaces? (it can only be applied to classes, methods, structs, properties, and fields).
  • sol_smartsol_smart Posts: 8 New member
    After some more testing I've found that enabling pruning actually renames the properties (which you actually also mention in the documentation: https://documentation.red-gate.com/sa7/obfuscating-your-code-with-smartassembly/pruning-code)...

    However, I find it a bit counterintuitive that pruning both removes unused code and also renames properties? Shouldn't renaming properties be the job of the 'name obfuscate' settings?
  • sol_smartsol_smart Posts: 8 New member
    Is it possible that you could provide a command line option / setting, that specifically enables obfuscation of property names?

    We use dependency injection heavily in our application, and since we're registering interfaces and classes by convention, it means that we have a lot "unused" classes (because only their interfaces are referenced). Enabling pruning removes all of those classes (which results in runtime errors), but it fixes the issue with property name obfuscation... in the end we're just stuck with a similar problem where we have to throw around DoNotPrune attributes to all of our classes, which is just as infeasible as writing ForceObfuscate to all of our properties.

    I look forward to hearing from you.

    - sol
  • Jessica RJessica R Posts: 1,044 Rose Gold 3
    Hi and thanks for your post @sol_smart!

    SmartAssembly can't obfuscate attributes and properties in your code since they are technically not methods or classes. However, since they are essentially metadata, they can be removed as "unnecessary code" by the pruning feature.

    I'll talk to our developers about how feasible it is to add a setting to prune only properties - please bear with me!

    Jessica Ramos | Product Support Engineer | Redgate Software

    Have you visited our Help Center?


  • sol_smartsol_smart Posts: 8 New member
    edited October 4, 2019 10:06AM
    Hi Jessica,

    Thanks for your quick reply. I think to sum up on my three previous posts (and sorry for just posting away), what we're really missing, and I think would greatly improve your product, are theese improvements - in order of importance to us:

    1. The ability to only obfuscate (i.e. specifically just rename) properties and events (even though it may technically be 'pruning'). In these days where Dependency Injection is increasingly popular, the concept of 'pruning' is simply too risky to enable, because so many classes and constructors are seen as unused through the eyes of static analysis. What we would love is the ability to just have properties and events renamed - SmartAssembly shouldn't remove anything that it deems "unused". I know we get that flexibility through annotations, but it is simply too big a task to apply those attributes manually. Perhaps it could be an entirely new option? Perhaps it could be a sub-option/switch for pruning?

    2. The ability to apply the 'ForceObfuscate' attribute to interfaces (the use case is 'internal interfaces').

    3. The ability to tell SmartAssembly to treat obfuscation attributes (ForceObfuscate, etc.) as inherited. It would be great to just be able to apply these attributes to a base class and then have them flow down a type inheritance hierarchy.

    4. The ability to do Cross Assembly Renaming. I know this is probably not a small feat, and I know that someone has previously asked you about this on the forum. So perhaps you could just follow up on a status on this?

    All of the above could of course easily be opt-in settings, such that you don't disturb existing setups.

    Again, many many thanks for creating an awesome easy-to-use product. We've evaluated severaly obfuscators and I definitely think that yours is best value-for-money!

    I look forward to hearing from you!

    - sol
  • Hi, a few responses to your numbered points:

    1. The ability to only rename (we assume this can only be by pruning)  just properties and event names. (Added feature request SA-2222)

    2. The ability to apply the 'ForceObfuscate' attribute to interfaces (the use case is 'internal interfaces').
    - This is a bug (SA-2223), but it is easy to fix so expect it to be fixed in the next release (or a near release, depending on our schedule).
    - As a temporary workaround, you can add the code below into you application:
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface)]
        public sealed class ForceObfuscateAttribute : Attribute
        {
            /// <summary>
            /// Force element to be obfuscated, even if it was excluded by safety mechanisms. Takes precedence over <see cref="SmartAssembly.Attributes.DoNotObfuscateAttribute"/>!
            /// </summary>
            /// <param name="useHashAsName">If <c>true</c>, uses MD5 hash of a method name prefixed with <c>"_"</c>. Otherwise, uses default Name Mangling setting.</param>
            public ForceObfuscateAttribute(bool useHashAsName = false) { }
        }

    and use it instead of the current ForceObfuscateAttribute definition.

    3. The ability to tell SmartAssembly to treat obfuscation attributes (ForceObfuscate, etc.) as inherited.
    - This has been requested before (logged as SA-2082). 
    We are still not convinced that it is a good idea to allow users to do something like this given the problems that can arise from obfuscating derived classes but not the base class, or a combination thereof. Still, it remains on the planning list but we haven't decided what to do with it.

    4. The ability to do Cross Assembly Renaming.
    - This has been requested before (SA-1438) so I've added this to the issue and it will be brought up in planning.
    Have you visited our Help Centre?
  • sol_smartsol_smart Posts: 8 New member
    edited October 9, 2019 9:05AM
    Hi Russel,

    Many many many thanks for your detailed response! Really appreciate it!

    1. Just so we're on the same page regarding this feature request. What I would really love is the ability to have SmartAssembly easily rename properties & events into something incomprehensible. Today I can achieve that in two sub-optimal ways:

    A) I can manually apply the [ForceObfuscate] attribute to a property/event (see below) and it works as intended. E.g. if a property was originally named 'MyInternalProperty' it will be renamed to something like '#xyz'. This is great but not feasible in a large solution.

    internal sealed class MyInternalClass
    {
        [ForceObfuscate]
        internal int MyInternalProperty { get; set; }
    }

    B ) I can enable pruning, but that basically does a lot of other stuff which is indesirable, e.g. removing classes and constructors that through the eyes of static analysis is deemed unused, which basically destroys Dependency Injection with convention based registration (which I guess an increasing number of people use these days? ).

    I basically just need SmartAssembly to have a third easy option to automatically only rename all properties & events into gibberish (without doing anything else - it should NOT remove any properties, classes, constructors or anything). I think it would be a good idea to have this as an opt-in setting, because renaming properties can easily do more harm than good in a WPF application. It should definitely not be a code annotation attribute because that already exists in the form of the [ForceObfuscate] attribute. Also the new setting should of course be available through the command line.

    2. Thanks, that actually works! I've just copied the attribute definitions into our solution anyways - so that's an easy change to make!

    3. I understand your argument. But the same could be said about the [ForceObfuscate] attribute. Basically, the argument for having the annotation attributes is that you can tell SmartAssembly - "Hey, I know better than you in this particular situation". You can also break stuff currently by placing incompatible mixes of [ForceObfuscate] in a class hierarchy - or on a public type for that matter. But of course there may be other arguments I'm not aware of.

    Anyways, currently, I can achieve what I want by placing a ForceObfuscate attribute on all relevant base AND sub-classes in the desired class hierachy, and It works perfectly. It would be great to have an option to only having to do this on the base class.

    4. I think this would be a great addition and vastly increase the number of obfuscated types. I know that an alternative solution is assembly merging but I think that comes with its own set of problems, e.g. creating too many discrepancies/differences between ongoing development/debugging in Visual Studio (where assemblies are not yet merged) and production releases where assemblies are merged, which can lead to subtle runtime bugs. Perhaps it could be achieved by specifying Friend Assemblies in the project file unioned with the InternalsVisibleTo attribute, and then scan for cross assembly type references to determine when and where to rename? (Probably easier said than done :smile: )

    Since cross assembly renaming basically also enforces that SmartAssembly must produce a set of compatible output assemblies in one go (which is different from now, where always only 1 output assembly is generated), I could be fine with something like this: I specify 1 input main assembly, and 1 output main assembly. Then I switch on the new feature "Cross assembly obfuscation", which then produces 1 output main assembly together with one assembly for each dependency where a dependent public type was renamed. This shouldn't require any structural changes to your project file format, or how user's are used to use your tool in relation to specifying inputs, outputs and dependencies.

    - sol
  • Excellent, thanks for the additional information - we'll discuss it next week and come back to you.

    I understand your point re 3, and I'm all in favour of letting people break their own applications in whatever ways they want too ;). The reality of that situation though is our experience is it causes more issues than it solves.
    Have you visited our Help Centre?
  • sol_smartsol_smart Posts: 8 New member
    Awesome, thanks!

    Regarding 3: with great power comes great responsibility. If you don't know what you're doing, obfuscation in general can cause more issues than it solves.. If SmartAssembly is able to detect those situations that would cause runtime errors, you could either break out of the obfuscation process and tell the user how to fix it; or just skip obfuscating the implicated classes.
  • Hi @sol_smart we've agreed that we're going to do all of these things, though I can't give any time frames I'm afraid. Our current focus is .net core 3 support and that is very much our priority.

    So just to summarise, SA-2082, SA-1438, SA-2222 are all on the list and will be looked at soon.

    SA-2223 has been fixed and will be released in 7.1.
    Have you visited our Help Centre?
  • sol_smartsol_smart Posts: 8 New member
    edited October 17, 2019 11:30AM
    Awesome, many thanks Russell !!

    Do you have a very rough estimate (without committing to anything) on when you will have .NET Core 3 support? Are we talking weeks, months, half a year, a year? Just very roughly, so I can get a feeling of when the other things are likely to receive some degree of attention.

    Again, many thanks!
    - sol
Sign In or Register to comment.