diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 66a2374a..b3c2e119 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -77,30 +77,32 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -125,6 +127,7 @@
+
diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs
index bb89c51f..d6a553e5 100644
--- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs
+++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs
@@ -584,5 +584,10 @@ namespace de4dot.code.deobfuscators {
public virtual void OnBeforeAddingResources(MetadataBuilder builder) {
}
+
+ public void findAndRemoveInlinedMethods() {
+ var inlinedMethods = InlinedMethodsFinder.find(module);
+ addMethodsToBeRemoved(new UnusedMethodsFinder(module, inlinedMethods).find(), "Inlined method");
+ }
}
}
diff --git a/de4dot.code/deobfuscators/InlinedMethodsFinder.cs b/de4dot.code/deobfuscators/InlinedMethodsFinder.cs
new file mode 100644
index 00000000..9646f438
--- /dev/null
+++ b/de4dot.code/deobfuscators/InlinedMethodsFinder.cs
@@ -0,0 +1,131 @@
+/*
+ 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 System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators {
+ static class InlinedMethodsFinder {
+ public static List find(ModuleDefinition module) {
+ // Not all garbage methods are inlined, possibly because we remove some code that calls
+ // the garbage method before the methods inliner has a chance to inline it. Try to find
+ // all garbage methods and other code will figure out if there are any calls left.
+
+ var inlinedMethods = new List();
+ foreach (var type in module.GetTypes()) {
+ foreach (var method in type.Methods) {
+ if (!method.IsStatic)
+ continue;
+ if (!method.IsAssembly && !method.IsCompilerControlled)
+ continue;
+ if (method.GenericParameters.Count > 0)
+ continue;
+ if (method.Name == ".cctor")
+ continue;
+ if (method.Body == null)
+ continue;
+ var instrs = method.Body.Instructions;
+ if (instrs.Count < 2)
+ continue;
+
+ switch (instrs[0].OpCode.Code) {
+ case Code.Ldc_I4:
+ case Code.Ldc_I4_0:
+ case Code.Ldc_I4_1:
+ case Code.Ldc_I4_2:
+ case Code.Ldc_I4_3:
+ case Code.Ldc_I4_4:
+ case Code.Ldc_I4_5:
+ case Code.Ldc_I4_6:
+ case Code.Ldc_I4_7:
+ case Code.Ldc_I4_8:
+ case Code.Ldc_I4_M1:
+ case Code.Ldc_I4_S:
+ case Code.Ldc_I8:
+ case Code.Ldc_R4:
+ case Code.Ldc_R8:
+ case Code.Ldftn:
+ case Code.Ldnull:
+ case Code.Ldstr:
+ case Code.Ldtoken:
+ case Code.Ldsfld:
+ case Code.Ldsflda:
+ if (instrs[1].OpCode.Code != Code.Ret)
+ continue;
+ break;
+
+ case Code.Ldarg:
+ case Code.Ldarg_S:
+ case Code.Ldarg_0:
+ case Code.Ldarg_1:
+ case Code.Ldarg_2:
+ case Code.Ldarg_3:
+ case Code.Call:
+ if (!isCallMethod(method))
+ continue;
+ break;
+
+ default:
+ continue;
+ }
+
+ inlinedMethods.Add(method);
+ }
+ }
+
+ return inlinedMethods;
+ }
+
+ static bool isCallMethod(MethodDefinition method) {
+ int loadIndex = 0;
+ int methodArgsCount = DotNetUtils.getArgsCount(method);
+ var instrs = method.Body.Instructions;
+ int i = 0;
+ for (; i < instrs.Count && i < methodArgsCount; i++) {
+ var instr = instrs[i];
+ switch (instr.OpCode.Code) {
+ case Code.Ldarg:
+ case Code.Ldarg_S:
+ case Code.Ldarg_0:
+ case Code.Ldarg_1:
+ case Code.Ldarg_2:
+ case Code.Ldarg_3:
+ if (DotNetUtils.getArgIndex(method, instr) != loadIndex)
+ return false;
+ loadIndex++;
+ continue;
+ }
+ break;
+ }
+ if (loadIndex != methodArgsCount)
+ return false;
+ if (i + 1 >= instrs.Count)
+ return false;
+
+ if (instrs[i].OpCode.Code != Code.Call && instrs[i].OpCode.Code != Code.Callvirt)
+ return false;
+ if (instrs[i + 1].OpCode.Code != Code.Ret)
+ return false;
+
+ return true;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/QuickLZ.cs b/de4dot.code/deobfuscators/QuickLZ.cs
similarity index 98%
rename from de4dot.code/deobfuscators/dotNET_Reactor/QuickLZ.cs
rename to de4dot.code/deobfuscators/QuickLZ.cs
index a54a12e3..10d65903 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/QuickLZ.cs
+++ b/de4dot.code/deobfuscators/QuickLZ.cs
@@ -11,7 +11,7 @@
using System;
-namespace de4dot.code.deobfuscators.dotNET_Reactor {
+namespace de4dot.code.deobfuscators {
static class QuickLZ {
static int sig = 0x5A4C4351; // "QCLZ"
diff --git a/de4dot.code/deobfuscators/UnusedMethodsFinder.cs b/de4dot.code/deobfuscators/UnusedMethodsFinder.cs
new file mode 100644
index 00000000..ba4b8590
--- /dev/null
+++ b/de4dot.code/deobfuscators/UnusedMethodsFinder.cs
@@ -0,0 +1,85 @@
+/*
+ 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 System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators {
+ class UnusedMethodsFinder {
+ ModuleDefinition module;
+ Dictionary possiblyUnusedMethods = new Dictionary();
+ Stack notUnusedStack = new Stack();
+
+ public UnusedMethodsFinder(ModuleDefinition module, IEnumerable possiblyUnusedMethods) {
+ this.module = module;
+ foreach (var method in possiblyUnusedMethods) {
+ if (method != module.EntryPoint)
+ this.possiblyUnusedMethods[method] = true;
+ }
+ }
+
+ public IEnumerable find() {
+ if (possiblyUnusedMethods.Count == 0)
+ return possiblyUnusedMethods.Keys;
+
+ foreach (var type in module.GetTypes()) {
+ foreach (var method in type.Methods)
+ check(method);
+ }
+
+ while (notUnusedStack.Count > 0) {
+ var method = notUnusedStack.Pop();
+ if (!possiblyUnusedMethods.Remove(method))
+ continue;
+ check(method);
+ }
+
+ return possiblyUnusedMethods.Keys;
+ }
+
+ void check(MethodDefinition method) {
+ if (method.Body == null)
+ return;
+ if (possiblyUnusedMethods.ContainsKey(method))
+ return;
+
+ foreach (var instr in method.Body.Instructions) {
+ switch (instr.OpCode.Code) {
+ case Code.Call:
+ case Code.Calli:
+ case Code.Callvirt:
+ case Code.Newobj:
+ case Code.Ldtoken:
+ case Code.Ldftn:
+ break;
+ default:
+ continue;
+ }
+
+ var calledMethod = DotNetUtils.getMethod(module, instr.Operand as MethodReference);
+ if (calledMethod == null)
+ continue;
+ if (possiblyUnusedMethods.ContainsKey(calledMethod))
+ notUnusedStack.Push(calledMethod);
+ }
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v3/ApplicationModeDecrypter.cs b/de4dot.code/deobfuscators/dotNET_Reactor3/ApplicationModeDecrypter.cs
similarity index 97%
rename from de4dot.code/deobfuscators/dotNET_Reactor/v3/ApplicationModeDecrypter.cs
rename to de4dot.code/deobfuscators/dotNET_Reactor3/ApplicationModeDecrypter.cs
index 3cd7a242..da2b3fdb 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v3/ApplicationModeDecrypter.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor3/ApplicationModeDecrypter.cs
@@ -21,7 +21,7 @@ using Mono.Cecil;
using de4dot.blocks;
using de4dot.blocks.cflow;
-namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
+namespace de4dot.code.deobfuscators.dotNET_Reactor3 {
class ApplicationModeDecrypter {
ModuleDefinition module;
AssemblyResolver assemblyResolver;
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v3/ApplicationModeUnpacker.cs b/de4dot.code/deobfuscators/dotNET_Reactor3/ApplicationModeUnpacker.cs
similarity index 99%
rename from de4dot.code/deobfuscators/dotNET_Reactor/v3/ApplicationModeUnpacker.cs
rename to de4dot.code/deobfuscators/dotNET_Reactor3/ApplicationModeUnpacker.cs
index 16cb7368..ae2c8d54 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v3/ApplicationModeUnpacker.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor3/ApplicationModeUnpacker.cs
@@ -25,7 +25,7 @@ using System.Text.RegularExpressions;
using Mono.Cecil;
using de4dot.code.PE;
-namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
+namespace de4dot.code.deobfuscators.dotNET_Reactor3 {
class IniFile {
Dictionary nameToValue = new Dictionary(StringComparer.OrdinalIgnoreCase);
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v3/AssemblyResolver.cs b/de4dot.code/deobfuscators/dotNET_Reactor3/AssemblyResolver.cs
similarity index 97%
rename from de4dot.code/deobfuscators/dotNET_Reactor/v3/AssemblyResolver.cs
rename to de4dot.code/deobfuscators/dotNET_Reactor3/AssemblyResolver.cs
index 3501943c..0fb3ffc9 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v3/AssemblyResolver.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor3/AssemblyResolver.cs
@@ -22,7 +22,7 @@ using Mono.Cecil;
using de4dot.blocks;
using de4dot.blocks.cflow;
-namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
+namespace de4dot.code.deobfuscators.dotNET_Reactor3 {
class AssemblyResolver {
DecryptMethod decryptMethod = new DecryptMethod();
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v3/DecryptMethod.cs b/de4dot.code/deobfuscators/dotNET_Reactor3/DecryptMethod.cs
similarity index 97%
rename from de4dot.code/deobfuscators/dotNET_Reactor/v3/DecryptMethod.cs
rename to de4dot.code/deobfuscators/dotNET_Reactor3/DecryptMethod.cs
index f6c43b9b..04ff59ac 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v3/DecryptMethod.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor3/DecryptMethod.cs
@@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using Mono.Cecil;
-namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
+namespace de4dot.code.deobfuscators.dotNET_Reactor3 {
class DecryptMethod {
MethodDefinition decryptionMethod;
byte[] key;
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor3/Deobfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor3/Deobfuscator.cs
new file mode 100644
index 00000000..dd5d0a45
--- /dev/null
+++ b/de4dot.code/deobfuscators/dotNET_Reactor3/Deobfuscator.cs
@@ -0,0 +1,246 @@
+/*
+ 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 System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.MyStuff;
+using de4dot.blocks;
+using de4dot.code.PE;
+
+namespace de4dot.code.deobfuscators.dotNET_Reactor3 {
+ public class DeobfuscatorInfo : DeobfuscatorInfoBase {
+ public const string THE_NAME = ".NET Reactor";
+ public const string THE_TYPE = "dr3";
+ const string DEFAULT_REGEX = DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
+ BoolOption restoreTypes;
+ BoolOption inlineMethods;
+ BoolOption removeInlinedMethods;
+ BoolOption removeNamespaces;
+ BoolOption removeAntiStrongName;
+
+ public DeobfuscatorInfo()
+ : base(DEFAULT_REGEX) {
+ restoreTypes = new BoolOption(null, makeArgName("types"), "Restore types (object -> real type)", true);
+ inlineMethods = new BoolOption(null, makeArgName("inline"), "Inline short methods", true);
+ removeInlinedMethods = new BoolOption(null, makeArgName("remove-inlined"), "Remove inlined methods", true);
+ removeNamespaces = new BoolOption(null, makeArgName("ns1"), "Clear namespace if there's only one class in it", true);
+ removeAntiStrongName = new BoolOption(null, makeArgName("sn"), "Remove anti strong name code", true);
+ }
+
+ public override string Name {
+ get { return THE_NAME; }
+ }
+
+ public override string Type {
+ get { return THE_TYPE; }
+ }
+
+ public override IDeobfuscator createDeobfuscator() {
+ return new Deobfuscator(new Deobfuscator.Options {
+ ValidNameRegex = validNameRegex.get(),
+ RestoreTypes = restoreTypes.get(),
+ InlineMethods = inlineMethods.get(),
+ RemoveInlinedMethods = removeInlinedMethods.get(),
+ RemoveNamespaces = removeNamespaces.get(),
+ RemoveAntiStrongName = removeAntiStrongName.get(),
+ });
+ }
+
+ protected override IEnumerable