@@ -25,6 +25,7 @@ You should have received a copy of the GNU General Public License
2525using dnlib . DotNet . Writer ;
2626using de4dot . blocks ;
2727using de4dot . blocks . cflow ;
28+ using de4dot . code . deobfuscators . dotNET_Reactor . v4 . vm ;
2829
2930namespace de4dot . code . deobfuscators . dotNET_Reactor . v4 {
3031 public class DeobfuscatorInfo : DeobfuscatorInfoBase {
@@ -42,6 +43,7 @@ public class DeobfuscatorInfo : DeobfuscatorInfoBase {
4243 BoolOption removeNamespaces ;
4344 BoolOption removeAntiStrongName ;
4445 BoolOption renameShort ;
46+ BoolOption devirtualize ;
4547
4648 public DeobfuscatorInfo ( )
4749 : base ( DEFAULT_REGEX ) {
@@ -55,6 +57,7 @@ public DeobfuscatorInfo()
5557 removeNamespaces = new BoolOption ( null , MakeArgName ( "ns1" ) , "Clear namespace if there's only one class in it" , true ) ;
5658 removeAntiStrongName = new BoolOption ( null , MakeArgName ( "sn" ) , "Remove anti strong name code" , true ) ;
5759 renameShort = new BoolOption ( null , MakeArgName ( "sname" ) , "Rename short names" , false ) ;
60+ devirtualize = new BoolOption ( null , MakeArgName ( "devirtualize" ) , "Devirtualize methods" , true ) ;
5861 }
5962
6063 public override string Name => THE_NAME ;
@@ -73,6 +76,7 @@ public override IDeobfuscator CreateDeobfuscator() =>
7376 RemoveNamespaces = removeNamespaces . Get ( ) ,
7477 RemoveAntiStrongName = removeAntiStrongName . Get ( ) ,
7578 RenameShort = renameShort . Get ( ) ,
79+ Devirtualize = devirtualize . Get ( ) ,
7680 } ) ;
7781
7882 protected override IEnumerable < Option > GetOptionsInternal ( ) =>
@@ -87,6 +91,7 @@ protected override IEnumerable<Option> GetOptionsInternal() =>
8791 removeNamespaces ,
8892 removeAntiStrongName ,
8993 renameShort ,
94+ devirtualize ,
9095 } ;
9196 }
9297
@@ -106,6 +111,7 @@ class Deobfuscator : DeobfuscatorBase {
106111 AntiStrongName antiStrongname ;
107112 EmptyClass emptyClass ;
108113 ProxyCallFixer proxyCallFixer ;
114+ Devirtualizer devirtualizer ;
109115
110116 bool unpackedNativeFile = false ;
111117 bool canRemoveDecrypterType = true ;
@@ -122,6 +128,7 @@ internal class Options : OptionsBase {
122128 public bool RemoveNamespaces { get ; set ; }
123129 public bool RemoveAntiStrongName { get ; set ; }
124130 public bool RenameShort { get ; set ; }
131+ public bool Devirtualize { get ; set ; }
125132 }
126133
127134 public override string Type => DeobfuscatorInfo . THE_TYPE ;
@@ -205,7 +212,8 @@ protected override int DetectInternal() {
205212 ToInt32 ( stringDecrypter . Detected ) +
206213 ToInt32 ( booleanDecrypter . Detected ) +
207214 ToInt32 ( assemblyResolver . Detected ) +
208- ToInt32 ( resourceResolver . Detected ) ;
215+ ToInt32 ( resourceResolver . Detected ) +
216+ ToInt32 ( devirtualizer . Detected ) ;
209217 if ( sum > 0 )
210218 val += 100 + 10 * ( sum - 1 ) ;
211219
@@ -222,6 +230,8 @@ protected override void ScanForObfuscator() {
222230 methodsDecrypter . Find ( ) ;
223231 proxyCallFixer = new ProxyCallFixer ( module , DeobfuscatedFile ) ;
224232 proxyCallFixer . FindDelegateCreator ( module ) ;
233+ devirtualizer = new Devirtualizer ( DeobfuscatedFile , module ) ;
234+ devirtualizer . Find ( ) ;
225235 stringDecrypter = new StringDecrypter ( module ) ;
226236 stringDecrypter . Find ( DeobfuscatedFile ) ;
227237 booleanDecrypter = new BooleanDecrypter ( module ) ;
@@ -277,6 +287,12 @@ Methods decrypter locals (not showing its own types):
277287 + "System.Byte&"
278288 */
279289
290+ if ( devirtualizer . Detected ) {
291+ if ( devirtualizer . StreamHasPrependedByte )
292+ return DeobfuscatorInfo . THE_NAME + " >= 7.0" ; // not sure when exactly this was introduced, might also be 7.3
293+ return DeobfuscatorInfo . THE_NAME + " >= 6.2" ;
294+ }
295+
280296 LocalTypes localTypes ;
281297 int minVer = - 1 ;
282298 foreach ( var info in stringDecrypter . DecrypterInfos ) {
@@ -430,6 +446,7 @@ public override IDeobfuscator ModuleReloaded(ModuleDefMD module) {
430446 newOne . peImage = new MyPEImage ( fileData ) ;
431447 newOne . methodsDecrypter = new MethodsDecrypter ( module , methodsDecrypter ) ;
432448 newOne . proxyCallFixer = new ProxyCallFixer ( module , proxyCallFixer ) ;
449+ newOne . devirtualizer = new Devirtualizer ( module , devirtualizer ) ;
433450 newOne . stringDecrypter = new StringDecrypter ( module , stringDecrypter ) ;
434451 newOne . booleanDecrypter = new BooleanDecrypter ( module , booleanDecrypter ) ;
435452 newOne . assemblyResolver = new AssemblyResolver ( module , assemblyResolver ) ;
@@ -510,6 +527,10 @@ public override void DeobfuscateBegin() {
510527 proxyCallFixer . Find ( ) ;
511528 proxyCallFixer . DeobfuscateAll ( ) ;
512529
530+ if ( devirtualizer . Detected && options . Devirtualize )
531+ devirtualizer . Devirtualize ( ) ;
532+
533+ // Inlines '<Module>{7212c6df-0f39-43d5-b7b8-3f24c0ebccff}'::m_1b8cd98d5e234215af7340e19a570660 references.
513534 var cflowInliner = new CflowConstantsInliner ( module , DeobfuscatedFile ) ;
514535 cflowInliner . InlineAllConstants ( ) ;
515536 AddTypeToBeRemoved ( cflowInliner . Type , "Cflow constants type" ) ;
@@ -640,7 +661,6 @@ public override void DeobfuscateMethodEnd(Blocks blocks) {
640661 metadataTokenObfuscator . Deobfuscate ( blocks ) ;
641662 FixTypeofDecrypterInstructions ( blocks ) ;
642663 RemoveAntiStrongNameCode ( blocks ) ;
643- stringDecrypter . DeobfuscateXored ( blocks ) ;
644664 base . DeobfuscateMethodEnd ( blocks ) ;
645665 }
646666
@@ -687,6 +707,11 @@ public override void DeobfuscateEnd() {
687707 else
688708 Logger . v ( "Could not remove decrypter type" ) ;
689709
710+ if ( devirtualizer . CanRemoveType ) {
711+ AddTypeToBeRemoved ( devirtualizer . VMType , "VM type" ) ;
712+ AddResourceToBeRemoved ( devirtualizer . Resource , "VM resource" ) ;
713+ }
714+
690715 FixEntryPoint ( ) ;
691716
692717 base . DeobfuscateEnd ( ) ;
0 commit comments