4

In using Obfuscar, I want to prevent enum types from being obfuscated because I need the original enum value names. I invoke ToString() on enum values because they are useful to the user. I had difficulty with the usual configuration where all types are obfuscated except those that appear in the configuration file with a <SkipType name="namespace.EnumType"/> element. I am resorting to what might be the more pessimistic method of using <MarkedOnly /> which obfuscates only that which is marked with an annotation. The fairly minimal configuration file follows.

    <?xml version="1.0"?>
    <configuration>

      <startup><supportedRuntime version="v4.0"
             sku=".NETFramework,Version=v4.0,Profile=Client"/>
      </startup>

      <Obfuscator>

        <Var name="InPath"  
value="\users\user\documents\visual studio 2013\projects\wpfapp\wpfapp\bin\debug" />
        <Var name="OutPath" 
value="\users\user\documents\visual studio 2013\projects\wpfapp\wpfapp\bin\debug" />

        <Module file="$(InPath)\wpfapp.exe" />

        <Var name="KeepPublicApi" value="true" />
        <Var name="HidePrivateApi" value="true" />

        <Var name="MarkedOnly" value="true" />

      </Obfuscator>

    </configuration>

The annotated code is:

namespace WpfApp
{
    public enum Category { Low, High }

    [System.Reflection.Obfuscation]
    public partial class MainWindow : Window
    {
        private ViewModel ViewModel;

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this.ViewModel = new ViewModel();
        }

        private void MyButtonClick(object sender, RoutedEventArgs e)
        {
            this.ViewModel.Process(MyTextBox.Text);
        }
    }

    internal class ViewModel : WpfNotifier
    {
        private const float DefaultKilograms = 80.0f;

        private string _kilograms;
        public string Kilograms // WPF binds here
        {
            get { return this._kilograms; }
            set { this._kilograms = value; NotifyPropertyChanged(); }
        }
        private string _resultText;
        public string ResultText // WPF binds here
        {
            get { return this._resultText; }
            set { this._resultText = value; NotifyPropertyChanged(); }
        }

        internal void Process(string input)
        {
            float kilograms;
            if (Single.TryParse(input, out kilograms))
            {
                Category c = (kilograms > 100.0f) ? Category.High : Category.Low;
                this.ResultText = c.ToString();
            }
            else
            {
                this.Kilograms = ViewModel.DefaultKilograms.ToString();
            }
        }
    }

    public class WpfNotifier : INotifyPropertyChanged
    {
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged; // public for interface

        internal void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            else
                ; // it is harmless to fail to notify before the window has been loaded and rendered
        }
    }
}

As you can see only one type is annotated with [System.Reflection.Obfuscation] and yet the output map shows the enum was renamed. The enum type is called Category.

Renamed Types:

[WpfApp]WpfApp.Category -> [WpfApp]A.a
{
    WpfApp.Category [WpfApp]WpfApp.Category WpfApp.Category::Low -> A
    WpfApp.Category [WpfApp]WpfApp.Category WpfApp.Category::High -> a

    System.Int32 [WpfApp]System.Int32 WpfApp.Category::value__ skipped:  special name
}

Is my usage wrong or is this a bug?

H2ONaCl
  • 10,644
  • 14
  • 70
  • 114
  • Enumvalues are stored as Fields of the struct that the compiler generates. I suspect that you need to exclude them using the `skipFields` atribute ``. It looks like the `` is overwritten by ``, which marks all private/internal members and classes by default. Though why it would obfuscate the public Category enum is beyond me at this point, it may be because it isn't exposed by a public method and thus considered private... – jessehouwing Jan 14 '15 at 11:22
  • The Tests in the source offer a number of ways to skip the fields of an enum: `` is one (that forgets the name of the enum type, but retains the fields). See the SkipEnumtests in the source drop: https://obfuscar.codeplex.com/downloads/get/670899 – jessehouwing Jan 14 '15 at 11:30
  • I tried 4 variants of skipping and so far, it does not skip. They are at this link https://stackoverflow.com/questions/27941434/obfuscar-skiptype-configuration-element-is-not-working-for-enums – H2ONaCl Jan 14 '15 at 12:01

1 Answers1

0

A bug has been identified around "MarkedOnly" option, where it fails to be checked when obfuscating fields and so on. I just fixed it in the master branch.

https://github.com/lextm/obfuscar

Note that after this change "MarkedOnly" option is exclusive to other options. If an element (class/enum/method/field and so on) has no Obfuscation attribute attached it will remain the same. Settings like "KeepPublicApi" and "HidePrivateApi" are ignored.

Lex Li
  • 60,503
  • 9
  • 116
  • 147