In my company, we use this product https://www.eziriz.com/dotnet_reactor.htm to protect the source code and avoid tampering.
Starting with Revit 2021 we get a "Null reference exception" somewhere between the call of the constructor for the IExternalApplication implementation and the call of OnStartup().
It seems it is because we use the following feature:
Anti ILDASM/Suppress Decompilation
-suppressildasm [1/0] Enable this option to suppress disassembly to IL using the ildasm.exe tool. Even if this option it set to FALSE your source code is still secure!
[1] = Enable {default}
[0] = Disable
Can someones give me an explanation why this happens in Revit 2021 and works fine for the older products?
Solved! Go to Solution.
Solved by jeremytammik. Go to Solution.
Perhaps the late attachment of this attribute above is interfering with the attributes used by the API that specify regeneration mode etc? Could perhaps attach manually as above so see if that helps.
Note that most decompiles probably use reflection or some other means so setting this attribute seems like more hindrance than help i.e. the attribute is something that ildasm reads and respects whilst other decompilers don't have to. Have also a vague awareness that resulting bit flag of this can be adjusted in the assembly directly so that it can actually be decompiled.
Dear Friend,
I usually use configuration below in Eziriz:
-necrobit 1 -necrobit_comp 1 -suppressildasm 1 -obfuscation 0 -mapping_file 0 -antitamp 1 -stringencryption 1 -resourceencryption 1 -control_flow_obfuscation 1 -flow_level 9
Maybe -suppressildasm is not the reason, decrease flow level step by step may be helpful.
And I strongly remind that Eziriz has already been decrypted by De4dot ( an open source decomplier). After I tried many encryption tools, I recommend the "dotnet protector" created by PVLog.
Wish it could be helpful for you 🙂
Best Regards
Frank Liang
The development team have indeed identified a problem in this area.
The good news:
The problem is fixed in the next major release of Revit.
The associated development ticket REVIT-160709 has also been nominated for merging into an update release of Revit 2021.
Best regards,
Jeremy
Thanks for the information about De4dot , I will take this into consideration.
Thank you for your appreciation.
The development added some background information to the ticket REVIT-160709 [RVTPR-00662: AddinManager Error for Obfuscated Add-ins] which on one hand is pretty obvious, on the other may point the way to an effective workaround for some cases:
I can confirm that the fix that was submitted to dev last week is complete. The null check on version string submitted last week is the only fix needed and we should be good.
The `TypeLoadException` issue on the customer add-in can be explained as below. I can reproduce this on a fresh add-in using the `.NET Reactor` obfuscation tool.
Revit Addins register class names for `IExternalCommand`, `IExternalCommandAvailability` `IExternalApplication` etc. as a string. For example
PushButton pushButton = ribbonPanel.AddItem(
new PushButtonData("MyButton", "Button",
Assembly.GetExecutingAssembly().Location,
"MyNamespace.MyCommandClass") as PushButton;
Revit then looks up `"MyNamespace.MyCommandClass"` in the assembly dll using `System.Reflection`. This all works well in an regular (unobfuscated) addin, for `public` as well as `internal` class `"MyNamespace.MyCommandClass"`.
If we run the `".NET Reactor"` obfuscation tool on the above code as is, it also works for both `public` as well as `internal` class `"MyNamespace.MyCommandClass"`. For a public class `"MyNamespace.MyCommandClass"`, the obfuscator will keep the same class name and its reference in the above code will also be retained as is. If the class `"MyNamespace.MyCommandClass"` was `internal`, then the obfuscation tool will mangle the class name and correctly fix the reference above in the `PushButtonData` constructor. It will fix the reference as long as it can find the string `"MyNamespace.MyCommandClass"` as is.
So far so good.
However, in a case where the class `"MyNamespace.MyCommandClass"` is `internal` and the class name is broken like this (and there could be valid reasons to be doing this or similar):
string str1 = "MyNamespace";
string str2 = "MyCommandClass";
PushButton pushButton = ribbonPanel.AddItem(
new PushButtonData("MyButton", "Button",
Assembly.GetExecutingAssembly().Location,
str1 + str2) as PushButton;
In such a case, the obfuscation tool will fail to connect the dots. Revit will end up looking for "MyNamespace.MyCommandClass", but the `internal` class would have been named as something else. To avoid this, one could either provide the full class name as is `"MyNamespace.MyCommandClass"` or make the class be public.
We shall merge the original fix to an update release of Revit 2021 as well.
Best regards,
Jeremy
Not sure if '.Net Reactor' respects the standard obfuscation attributes such as below. There is probably an option to do so or not. Some obfuscators will rename both type and method regardless, to avoid this I generally use the following attribute on classes implementing IExternalApplication, IExternalCommand etc.
<System.Reflection.Obfuscation(ApplyToMembers:=True, Exclude:=True)>
The good thing about this attribute rather than obfuscator settings is that it stays with the source code.
This was fixed in the update release Revit 2021.1.
Can you please confirm that the fix solves the problem?
Thank you!