Search code examples
c#unity-game-enginemonoobfuscationdotfuscator

Dotfuscator doesn't support Unity3d?


I tested Dotfuscator with some of my DLLs written in C#. It seemed it works really well on .NET environment, so this time I tried them with Unity3D. Those simple DLLs were just coded only with simple standard C# classes and methods, no reflection, no LINQ, no other custom or 3rd party APIs including Unity's. But failed to make them work in my Unity3d project, while original pure DLLs which aren't obfuscated were working fine. After struggling for a few hours, I decided to test with new simple projects. Below is all I got in C#, there are no other code, no other references at all.

[System.Reflection.Obfuscation(Feature = "renaming", Exclude = true)]
public class Class1
{
    [System.Reflection.Obfuscation(Feature = "renaming", Exclude = true)]
    public static int Get()
    {
        return 123;
    }
}

After compiling this to DLL, I put it in an EMPTY project on Unity3D Editor and played, and it worked well. But when I gave another try after obfuscating the DLL with Dotfuscator, it stopped saying "InvalidProgramException: Invalid IL code in Class1:Get (): IL_000c: pop".

As you can see above, I added attributes which prevent the code from being renamed, and of course, I could see in Reflector, the name of both class and method weren't actually renamed.

Yesterday I newly registered and downloaded the evaluation version of the latest Dotfuscator Professional Edition 4.21.0 from PreEmptive's site. I compiled both on Visual Studio 2008 and 2015 with .NET 3.5, also tried with all different Solution Platforms. The version of Unity is 5.3.4f1.

My guess now is Dotfuscator only works with MSIL, not Mono 2.X which Unity3D internally uses.

Am I right? Is there anyone using Dotfuscator with Unity3D or Mono well?

[EDIT] I checked IL code using ILDasm, don't understand what's going on, but interesting to see a bunch of code is modified.

Before applying Dotfuscator

.method public hidebysig static int32  Get() cil managed
{
  .custom instance void [mscorlib]System.Reflection.ObfuscationAttribute::.ctor() = ( 01 00 02 00 54 0E 07 46 65 61 74 75 72 65 08 72   // ....T..Feature.r
                                                                                      65 6E 61 6D 69 6E 67 54 02 07 45 78 63 6C 75 64   // enamingT..Exclud
                                                                                      65 01 )                                           // e.
  // Code Size       6 (0x6)
  .maxstack  8
  IL_0000:  ldc.i4     0x75bcd15
  IL_0005:  ret
} // end of method Class1::Get

After applying Dotfuscator

.method public hidebysig static int32  Get() cil managed
{
  // Code Size       127 (0x7f)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  ldc.i4     0x993
  IL_0005:  stloc      V_0
  IL_0009:  ldloca     V_0
  IL_000d:  ldind.i4
  IL_000e:  ldc.i4     0x993
  IL_0013:  stloc      V_0
  IL_0017:  ldloca     V_0
  IL_001b:  ldind.i4
  IL_001c:  ceq
  IL_001e:  switch     ( 
                        IL_002f,
                        IL_004c,
                        IL_002f)
  IL_002f:  br.s       IL_003e
  IL_0031:  ldc.i4.0
  IL_0032:  stloc      V_0
  IL_0036:  ldloca     V_0
  IL_003a:  ldind.i4
  IL_003b:  pop
  IL_003c:  br.s       IL_004a
  IL_003e:  ldc.i4.0
  IL_003f:  stloc      V_0
  IL_0043:  ldloca     V_0
  IL_0047:  ldind.i4
  IL_0048:  br.s       IL_003b
  IL_004a:  nop
  IL_004b:  nop
  IL_004c:  ldc.i4     0x1
  IL_0051:  stloc      V_0
  IL_0055:  ldloca     V_0
  IL_0059:  ldind.i4
  IL_005a:  br.s       IL_0068
  IL_005c:  ldc.i4.0
  IL_005d:  stloc      V_0
  IL_0061:  ldloca     V_0
  IL_0065:  ldind.i4
  IL_0066:  br.s       IL_0068
  IL_0068:  brfalse.s  IL_006a
  IL_006a:  ldc.i4.0
  IL_006b:  stloc      V_0
  IL_006f:  ldloca     V_0
  IL_0073:  ldind.i4
  IL_0074:  brfalse    IL_0079
  IL_0079:  ldc.i4     0x75bcd15
  IL_007e:  ret
} // end of method Class1::Get

Solution

  • UPDATE: As of version 6.0, Dotfuscator Professional no longer supports Unity. (See changelog for 6.0.0-beta). It continues to support Mono. The original answer follows.


    Yes, Dotfuscator Professional Edition supports Mono and Unity. The reason you're seeing differences in the IL is due to the Control Flow obfuscation that Professional Edition provides. This is a distinct from the Renaming feature from which you have excluded your identifiers.

    By default, Dotfuscator uses as many Control Flow transforms as it can get away with on the .NET Framework (i.e., Microsoft's implementation). However, some of these transforms are not compatible with Mono. Dotfuscator provides an option to disable such transforms.

    After loading your Dotfuscator project in the GUI, this option can be found on the Settings tab, under "Advanced", named "Use only Mono-compatible transforms". Set this option to "Yes", then save and rebuild the project.

    Dotfuscator Professional Edition - Settings Tab, "Use only Mono-compatible transforms" enabled and highlighted

    If that is still giving you problems, you can disable Control Flow entirely to see if that fixes the problem. This is also on the Settings tab, under "Features", "Disable Control Flow". Set this option to "Yes", then save and rebuild the project.

    Full disclosure: I work for the Dotfuscator team at PreEmptive Solutions. If you have more questions, keep in mind that evaluation users like yourself also have full access to PreEmptive support.