Obfuscating Properties with Eazfuscator and Dotfuscator

Last updated 2009-09-17.

If you are making use of reflection to examine the properties of classes, your code will not work once obfuscated with Dotfuscator or Eazfuscator (unless of course you suppress renaming of the properties you're using, which will defeat the purpose of obfuscation).

Consider the following code:


  public class ExampleClass
  {
    private int _iSettingA;
    private int _iSettingB;

    public int SettingA
    {
      get { return _iSettingA; }
      set { _iSettingA = value; }
    }

    public int SettingB
    {
      get { return _iSettingB; }
      set { _iSettingB = value; }
    }
  }


When we reflect on this code, we see that the properties actually imply two methods each:

Found 2 properties in ExampleClass:
        Int32 SettingA { get; set; } [ExampleAttribute]
        Int32 SettingB { get; set; } [ExampleAttribute]

Found 8 methods in ExampleClass:
        Int32 get_SettingA()
        Void set_SettingA(Int32 value)
        Int32 get_SettingB()
        Void set_SettingB(Int32 value)
        String ToString()
        Boolean Equals(Object obj)
        Int32 GetHashCode()
        Type GetType()

... and a glance at the IL shows that the property just wraps the methods:


.property instance int32 SettingA()
{
  .get instance int32 ObfuscatedProperties.ExampleClass::get_SettingA()
  .set instance void ObfuscatedProperties.ExampleClass::set_SettingA(int32)
} // end of property ExampleClass::SettingA

After obfuscation, you can see that the properties have vanished, and the getter and setter methods have been renamed:


Found 0 properties in ExampleClass:

Found 8 methods in ExampleClass:
        Int32 a()
        Void a(Int32 A_0)
        Int32 b()
        Void b(Int32 A_0)
        String ToString()
        Boolean Equals(Object obj)
        Int32 GetHashCode()
        Type GetType()

This means that if you're using reflection to find properties at runtime, your code will fail once you've obfuscated it. You can't get around the problem by marking up the properties with custom attributes either, because they don't apply to the methods they imply. The output above shows that the properties are marked with ExampleAttribute, but the methods they imply (even before obfuscation) are not.

The best approach to deal with this is to abandon properties, and explicitly declare getter and setter methods. You can mark them up with attributes to identify them as 'belonging' to each other:


[PropertyMethod("BBD247D0-65AA-437e-8DF7-0ACECDC32142")]
public virtual int GetSettingA()
{
  return _iSettingA;
}

[PropertyMethod("BBD247D0-65AA-437e-8DF7-0ACECDC32142")]
public virtual void SetSettingA(int value)
{
  _iSettingA = value;
}


At this point, simple heuristics can be used to identify getter / setter pairs after obfuscation. There will be two methods with potentially any name, but with the same custom attribute value. Then, you can assume that the method without parameters is the getter, and the method with one parameter is the setter.

If you do a lot of property manipulation by reflection in your code, you should consider writing a utility class to replace the PropertyInfo class, that provides a friendly PropertyInfo-like interface to marked-up getter and setter methods. Note that you still might want to expose true properties that in turn call the getter and setter methods you've created, in order to expose your components to the Visual Studio Designer.

That way your code will be easy to read, and will also survive thorough obfuscation.