From 94596d6fb75b256201f61b72805f6ff132615069 Mon Sep 17 00:00:00 2001 From: saneki Date: Tue, 4 Aug 2015 17:52:02 -0500 Subject: [PATCH] Added support for Eazfuscator.NET 5.0 --- .../Eazfuscator_NET/Deobfuscator.cs | 2 +- .../Eazfuscator_NET/StringDecrypter.cs | 58 +++++++++++++++++-- .../Eazfuscator_NET/VersionDetector.cs | 43 +++++++++++++- 3 files changed, 97 insertions(+), 6 deletions(-) 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"; } }