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; + } + } +}