diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 35f4c408..5133e7ac 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -81,6 +81,7 @@
+
diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs
index 3694d6d2..a0a0688a 100644
--- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs
+++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs
@@ -244,6 +244,10 @@ namespace de4dot.deobfuscators {
methodCallRemover.add(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor"), methodToBeRemoved);
}
+ public void addCtorInitCallToBeRemoved(MethodReference methodToBeRemoved) {
+ methodCallRemover.add(".ctor", methodToBeRemoved);
+ }
+
public void addCallToBeRemoved(MethodDefinition method, MethodReference methodToBeRemoved) {
methodCallRemover.add(method, methodToBeRemoved);
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs
index 8220fef8..bd8cbfc0 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs
@@ -105,6 +105,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
AssemblyResolver assemblyResolver;
ResourceResolver resourceResolver;
AntiStrongName antiStrongname;
+ EmptyClass emptyClass;
bool canRemoveDecrypterType = true;
bool startedDeobfuscating = false;
@@ -390,6 +391,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
stringDecrypter.init(peImage, fileData, DeobfuscatedFile);
booleanDecrypter.init(fileData, DeobfuscatedFile);
boolValueInliner = new BoolValueInliner();
+ emptyClass = new EmptyClass(module);
if (options.DecryptBools) {
boolValueInliner.add(booleanDecrypter.Method, (method, args) => {
@@ -461,6 +463,11 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
if (options.InlineMethods)
addTypeToBeRemoved(metadataTokenObfuscator.Type, "Metadata token obfuscator");
+ addCctorInitCallToBeRemoved(emptyClass.Method);
+ addCtorInitCallToBeRemoved(emptyClass.Method);
+ addCallToBeRemoved(module.EntryPoint, emptyClass.Method);
+ addTypeToBeRemoved(emptyClass.Type, "Empty class");
+
startedDeobfuscating = true;
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/EmptyClass.cs b/de4dot.code/deobfuscators/dotNET_Reactor/EmptyClass.cs
new file mode 100644
index 00000000..ca5017dc
--- /dev/null
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/EmptyClass.cs
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2011 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using Mono.Cecil;
+using de4dot.blocks;
+
+namespace de4dot.deobfuscators.dotNET_Reactor {
+ // Detect some empty class that is called from most .ctor's
+ class EmptyClass {
+ ModuleDefinition module;
+ MethodDefinition emptyMethod;
+
+ public MethodDefinition Method {
+ get { return emptyMethod; }
+ }
+
+ public TypeDefinition Type {
+ get { return emptyMethod != null ? emptyMethod.DeclaringType : null; }
+ }
+
+ public EmptyClass(ModuleDefinition module) {
+ this.module = module;
+ init();
+ }
+
+ void init() {
+ var callCounter = new CallCounter();
+ int count = 0;
+ foreach (var type in module.GetTypes()) {
+ if (count >= 40)
+ break;
+ foreach (var method in type.Methods) {
+ if (method.Name != ".ctor")
+ continue;
+ foreach (var tuple in DotNetUtils.getCalledMethods(module, method)) {
+ var calledMethod = tuple.Item2;
+ if (!calledMethod.IsStatic || calledMethod.Body == null)
+ continue;
+ if (!DotNetUtils.isMethod(calledMethod, "System.Void", "()"))
+ continue;
+ if (isEmptyClass(calledMethod)) {
+ callCounter.add(calledMethod);
+ count++;
+ }
+ }
+ }
+ }
+
+ emptyMethod = (MethodDefinition)callCounter.most();
+ }
+
+ bool isEmptyClass(MethodDefinition emptyMethod) {
+ if (!DotNetUtils.isEmptyObfuscated(emptyMethod))
+ return false;
+
+ var type = emptyMethod.DeclaringType;
+ if (type.HasEvents || type.HasProperties)
+ return false;
+ if (type.Fields.Count != 1)
+ return false;
+ if (type.Fields[0].FieldType.FullName != "System.Boolean")
+ return false;
+
+ foreach (var method in type.Methods) {
+ if (method.Name == ".ctor" || method.Name == ".cctor")
+ continue;
+ if (method == emptyMethod)
+ continue;
+ return false;
+ }
+
+ return true;
+ }
+ }
+}