diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs
index 80f81442..031463e2 100644
--- a/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/Eazfuscator_NET/Deobfuscator.cs
@@ -118,7 +118,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
base.DeobfuscateBegin();
stringDecrypter.Initialize(DeobfuscatedFile);
- staticStringInliner.Add(stringDecrypter.Method, (method2, gim, args) => {
+ staticStringInliner.Add(stringDecrypter.RealMethod, (method2, gim, args) => {
return stringDecrypter.Decrypt((int)args[0]);
});
DeobfuscatedFile.StringDecryptersAdded();
diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs
index a16c6729..b71d5e29 100644
--- a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs
+++ b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs
@@ -46,8 +46,10 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
StreamHelperType streamHelperType;
EfConstantsReader stringMethodConsts;
bool isV32OrLater;
+ bool isV50OrLater;
int? validStringDecrypterValue;
DynamicDynocodeIterator dynocode;
+ MethodDef realMethod;
class StreamHelperType {
public TypeDef type;
@@ -112,6 +114,18 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
get { return stringType != null; }
}
+ ///
+ /// In 5.0, the actual string decrypter method doesn't do much, calls a helper method which
+ /// does most of the work (and is mostly the same as the stringMethod from 4.9 and below).
+ ///
+ public bool HasRealMethod {
+ get { return realMethod != null; }
+ }
+
+ public MethodDef RealMethod {
+ get { return (realMethod != null ? realMethod : stringMethod); }
+ }
+
public StringDecrypter(ModuleDefMD module, DecrypterType decrypterType) {
this.module = module;
this.decrypterType = decrypterType;
@@ -135,8 +149,15 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
if (!CheckDecrypterMethod(method))
continue;
+ // 5.0
+ if (CheckIfHelperMethod(method)) {
+ stringMethod = method;
+ realMethod = GetRealDecrypterMethod(method);
+ isV50OrLater = true;
+ }
+ else stringMethod = method;
+
stringType = type;
- stringMethod = method;
isV32OrLater = CheckIfV32OrLater(stringType);
return;
}
@@ -211,9 +232,33 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
if (calledMethod != null && calledMethod.FullName == "System.IO.Stream System.Reflection.Assembly::GetManifestResourceStream(System.String)")
return true;
}
+
return false;
}
+ /// 5.0
+ static bool CheckIfHelperMethod(MethodDef method) {
+ // Helper method will be `private static`, instead of `internal static`
+ return method.DeclaringType.Methods.Count == 4 && !method.IsAssembly;
+ }
+
+ ///
+ /// Get the real decrypter method from a found helper method.
+ ///
+ /// 5.0
+ static MethodDef GetRealDecrypterMethod(MethodDef helper) {
+ var methods = helper.DeclaringType.Methods;
+ var sigComparer = new SigComparer();
+ foreach (var method in methods) {
+ if (method.MDToken != helper.MDToken &&
+ method.IsAssembly &&
+ sigComparer.Equals(method.MethodSig, helper.MethodSig))
+ return method;
+ }
+
+ return null;
+ }
+
public void Initialize(ISimpleDeobfuscator simpleDeobfuscator) {
if (stringType == null)
return;
@@ -250,9 +295,14 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
return false;
if (checkMinus2 && !FindInt5())
return false;
- dataDecrypterType = FindDataDecrypterType(stringMethod);
- if (dataDecrypterType == null)
- return false;
+
+ // The method body of the data decrypter method has been moved into
+ // the string decrypter helper method in 5.0
+ if (!isV50OrLater) {
+ dataDecrypterType = FindDataDecrypterType(stringMethod);
+ if (dataDecrypterType == null)
+ return false;
+ }
if (isV32OrLater) {
bool initializedAll;
diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs
index 9e6e6e73..58a886f8 100644
--- a/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs
+++ b/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs
@@ -777,7 +777,48 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
new LocalTypes(decryptStringMethod).All(locals43) &&
CheckTypeFields2(fields43)) {
- return "4.3";
+ return "4.3 - 4.9";
+ }
+
+ /////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////
+
+ var fields50 = new string[] {
+ GetNestedTypeName(0),
+ GetNestedTypeName(1),
+ "System.Byte[]",
+ "System.Int16",
+ "System.Int32",
+ "System.Byte[]",
+ "System.Int32",
+ "System.Int32",
+ GetNestedTypeName(2),
+ };
+ var locals50 = CreateLocalsArray(
+ // GetNestedTypeName(2) // One of the nested types is the first local (non-enum type)
+ "System.String",
+ "System.String"
+ );
+ var otherMethod50 = otherMethods.Find((m) => {
+ return DotNetUtils.IsMethod(m, "System.Void", "(System.Byte[],System.Int32,System.Byte[])");
+ });
+ decryptStringMethod = stringDecrypter.RealMethod;
+ if (stringDecrypter.HasRealMethod &&
+ otherMethods.Count == 2 &&
+ otherMethod50 != null &&
+ decryptStringType.NestedTypes.Count == 3 &&
+ otherMethod50.IsPrivate &&
+ otherMethod50.IsStatic &&
+ decryptStringMethod.IsNoInlining &&
+ decryptStringMethod.IsAssembly &&
+ !decryptStringMethod.IsSynchronized &&
+ decryptStringMethod.Body.MaxStack >= 1 &&
+ decryptStringMethod.Body.MaxStack <= 8 &&
+ decryptStringMethod.Body.ExceptionHandlers.Count == 1 &&
+ new LocalTypes(decryptStringMethod).All(locals50) &&
+ CheckTypeFields2(fields50)) {
+ return "5.0";
}
}