From 9ecc5a313f29c0b12cb6ff900e5c15828a8482f2 Mon Sep 17 00:00:00 2001 From: de4dot Date: Fri, 16 Mar 2012 23:22:24 +0100 Subject: [PATCH] Support EF obfuscated SL assemblies --- de4dot.code/deobfuscators/DeobUtils.cs | 14 ++-- .../Eazfuscator_NET/AssemblyResolver.cs | 71 +++++++++++++++---- .../deobfuscators/Eazfuscator_NET/EfUtils.cs | 22 ++++++ .../Eazfuscator_NET/StringDecrypter.cs | 46 ++++++++++-- .../Eazfuscator_NET/VersionDetector.cs | 19 +++-- 5 files changed, 143 insertions(+), 29 deletions(-) diff --git a/de4dot.code/deobfuscators/DeobUtils.cs b/de4dot.code/deobfuscators/DeobUtils.cs index f231cd77..f9e8f4fc 100644 --- a/de4dot.code/deobfuscators/DeobUtils.cs +++ b/de4dot.code/deobfuscators/DeobUtils.cs @@ -190,15 +190,21 @@ namespace de4dot.code.deobfuscators { } public static bool hasInteger(MethodDefinition method, int value) { + return indexOfLdci4Instruction(method, value) >= 0; + } + + public static int indexOfLdci4Instruction(MethodDefinition method, int value) { if (method == null || method.Body == null) - return false; - foreach (var instr in method.Body.Instructions) { + return -1; + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count; i++) { + var instr = instrs[i]; if (!DotNetUtils.isLdcI4(instr)) continue; if (DotNetUtils.getLdcI4Value(instr) == value) - return true; + return i; } - return false; + return -1; } } } diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/AssemblyResolver.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/AssemblyResolver.cs index 823bb5aa..c9fbf20c 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/AssemblyResolver.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/AssemblyResolver.cs @@ -36,6 +36,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { MethodDefinition decryptMethod; TypeDefinition otherType; List assemblyInfos = new List(); + FrameworkType frameworkType; byte[] decryptKey; public class AssemblyInfo { @@ -76,6 +77,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { public AssemblyResolver(ModuleDefinition module, DecrypterType decrypterType) { this.module = module; + this.frameworkType = DotNetUtils.getFrameworkType(module); this.decrypterType = decrypterType; } @@ -90,20 +92,65 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code != Code.Call) continue; - if (!checkInitMethod(instr.Operand as MethodDefinition)) - continue; + var calledMethod = instr.Operand as MethodDefinition; + if (calledMethod == null || !calledMethod.IsStatic || calledMethod.Body == null) + return false; + if (!DotNetUtils.isMethod(calledMethod, "System.Void", "()")) + return false; + + if (frameworkType == FrameworkType.Silverlight) { + if (!checkInitMethodSilverlight(calledMethod)) + continue; + } + else { + if (!checkInitMethod(calledMethod)) + continue; + } + + decryptMethod = getDecryptMethod(); + updateDecrypterType(); return true; } return false; } + bool checkInitMethodSilverlight(MethodDefinition method) { + var type = method.DeclaringType; + if (type.NestedTypes.Count != 2) + return false; + + var resolveHandler = getResolveMethodSilverlight(method); + if (resolveHandler == null) + return false; + + initMethod = method; + resolverType = type; + handlerMethod = resolveHandler; + return true; + } + + static MethodDefinition getResolveMethodSilverlight(MethodDefinition initMethod) { + foreach (var instr in initMethod.Body.Instructions) { + if (instr.OpCode.Code != Code.Call) + continue; + var calledMethod = instr.Operand as MethodDefinition; + if (calledMethod == null) + continue; + if (!DotNetUtils.isMethod(calledMethod, "System.Void", "()")) + continue; + if (!DeobUtils.hasInteger(calledMethod, ',') || + !DeobUtils.hasInteger(calledMethod, '|')) + continue; + + return calledMethod; + } + + return null; + } + bool checkInitMethod(MethodDefinition method) { - if (method == null || !method.IsStatic || method.Body == null) - return false; - if (!DotNetUtils.isMethod(method, "System.Void", "()")) - return false; var type = method.DeclaringType; if (type.NestedTypes.Count != 3) return false; @@ -120,8 +167,6 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { initMethod = method; resolverType = type; handlerMethod = resolveHandler; - decryptMethod = getDecryptMethod(); - updateDecrypterType(); return true; } @@ -239,8 +284,9 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { } bool createAssemblyInfos() { + int numElements = DeobUtils.hasInteger(handlerMethod, 3) ? 3 : 2; foreach (var s in DotNetUtils.getCodeStrings(handlerMethod)) { - var infos = createAssemblyInfos(s); + var infos = createAssemblyInfos(s, numElements); if (infos == null) continue; @@ -251,17 +297,16 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { return false; } - List createAssemblyInfos(string s) { + List createAssemblyInfos(string s, int numElements) { try { - return tryCreateAssemblyInfos(s); + return tryCreateAssemblyInfos(s, numElements); } catch (FormatException) { return null; // Convert.FromBase64String() failed } } - List tryCreateAssemblyInfos(string s) { - int numElements = decrypterType.Detected ? 3 : 2; + List tryCreateAssemblyInfos(string s, int numElements) { var ary = s.Split(','); if (ary.Length == 0 || ary.Length % numElements != 0) return null; diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/EfUtils.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/EfUtils.cs index 71cf7259..247a7f0e 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/EfUtils.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/EfUtils.cs @@ -24,6 +24,28 @@ using de4dot.blocks; namespace de4dot.code.deobfuscators.Eazfuscator_NET { static class EfUtils { + public static int indexOfPreviousLdci4Instruction(MethodDefinition method, int index) { + var instrs = method.Body.Instructions; + for (int i = index; i >= 0; i--) { + var instr = instrs[i]; + if (DotNetUtils.isLdcI4(instr)) + return i; + } + return -1; + } + + public static int indexOfNextLdci4Instruction(MethodDefinition method, int index) { + if (index < 0) + return -1; + var instrs = method.Body.Instructions; + for (int i = index; i < instrs.Count; i++) { + var instr = instrs[i]; + if (DotNetUtils.isLdcI4(instr)) + return i; + } + return -1; + } + public static bool getNextInt32(MethodDefinition method, ref int index, out int val) { for (; index < method.Body.Instructions.Count; index++) { var instr = method.Body.Instructions[index]; diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs index a09b4550..2465d35c 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs @@ -23,6 +23,7 @@ using System.IO; using System.Text; using Mono.Cecil; using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; using de4dot.blocks; namespace de4dot.code.deobfuscators.Eazfuscator_NET { @@ -43,6 +44,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { BinaryReader reader; DecrypterType decrypterType; StreamHelperType streamHelperType; + bool isV32OrLater; class StreamHelperType { public TypeDefinition type; @@ -104,6 +106,15 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { this.decrypterType = decrypterType; } + static bool checkIfV32OrLater(TypeDefinition type) { + int numInts = 0; + foreach (var field in type.Fields) { + if (field.FieldType.EType == ElementType.I4) + numInts++; + } + return numInts >= 2; + } + public void find() { foreach (var type in module.Types) { if (!checkType(type)) @@ -115,6 +126,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { stringType = type; stringMethod = method; + isV32OrLater = checkIfV32OrLater(stringType); return; } } @@ -229,7 +241,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { if (dataDecrypterType == null) return false; - if (decrypterType.Detected) { + if (isV32OrLater) { bool initializedAll; if (!findInts(stringMethod, out initializedAll)) return false; @@ -241,7 +253,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { return false; } - if (!decrypterType.initialize()) + if (decrypterType.Detected && !decrypterType.initialize()) return false; } @@ -252,7 +264,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { } void initializeFlags() { - if (!decrypterType.Detected || !DeobUtils.hasInteger(stringMethod, 0xFFFFFFF)) { + if (!isV32OrLater || !DeobUtils.hasInteger(stringMethod, 0xFFFFFFF)) { // <= 3.3.134 rldFlag = 0x40000000; bytesFlag = 0x80000000; @@ -305,8 +317,9 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { else keyLen = reader.ReadInt16() ^ s2; + magic1 = i1 ^ i2; if (decrypterType.Detected) - magic1 = (int)decrypterType.getMagic() ^ i1 ^ i2; + magic1 ^= (int)decrypterType.getMagic(); } public string decrypt(int val) { @@ -316,7 +329,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { byte[] tmpKey; if (theKey == null) { tmpKey = reader.ReadBytes(keyLen == -1 ? (short)(reader.ReadInt16() ^ s3 ^ offset) : keyLen); - if (decrypterType.Detected) { + if (isV32OrLater) { for (int i = 0; i < tmpKey.Length; i++) tmpKey[i] ^= (byte)(magic1 >> ((i & 3) << 3)); } @@ -484,9 +497,30 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { return true; } + // 3.2 (Silverlight) + if (findIntsSilverlight(method, ref initializedAll)) + return true; + return false; } + bool findIntsSilverlight(MethodDefinition method, ref bool initializedAll) { + int index = DeobUtils.indexOfLdci4Instruction(method, 268435314); + if (index < 0) + return false; + index--; + index = EfUtils.indexOfPreviousLdci4Instruction(method, index); + if (index < 0) + return false; + + i1 = 0; + if (!EfUtils.getNextInt32(method, ref index, out i2)) + return false; + + initializedAll = method.Body.Instructions[index].OpCode.Code == Code.Stsfld; + return true; + } + bool findIntsCctor(MethodDefinition cctor) { int index = 0; if (!findCallGetFrame(cctor, ref index)) @@ -516,7 +550,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { } bool findInt3(MethodDefinition method) { - if (!decrypterType.Detected) + if (!isV32OrLater) return findInt3Old(method); return findInt3New(method); } diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs index c421f9c4..75273df6 100644 --- a/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs +++ b/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs @@ -49,6 +49,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { return null; bool hasConstantM2 = DeobUtils.hasInteger(decryptStringMethod, -2); + var frameworkType = DotNetUtils.getFrameworkType(decryptStringType.Module); ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// @@ -345,7 +346,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { !decryptStringMethod.IsSynchronized && decryptStringMethod.Body.MaxStackSize >= 1 && decryptStringMethod.Body.MaxStackSize <= 8 && - decryptStringMethod.Body.ExceptionHandlers.Count == 2 && + (decryptStringMethod.Body.ExceptionHandlers.Count == 2 || + (frameworkType == FrameworkType.Silverlight && decryptStringMethod.Body.ExceptionHandlers.Count == 1)) && new LocalTypes(decryptStringMethod).exactly(locals29) && checkTypeFields(fields29)) { return "2.9"; @@ -395,7 +397,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { !decryptStringMethod.IsSynchronized && decryptStringMethod.Body.MaxStackSize >= 1 && decryptStringMethod.Body.MaxStackSize <= 8 && - decryptStringMethod.Body.ExceptionHandlers.Count == 2 && + (decryptStringMethod.Body.ExceptionHandlers.Count == 2 || + (frameworkType == FrameworkType.Silverlight && decryptStringMethod.Body.ExceptionHandlers.Count == 1)) && new LocalTypes(decryptStringMethod).exactly(locals30) && checkTypeFields(fields30)) { return "3.0"; @@ -445,7 +448,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { !decryptStringMethod.IsSynchronized && decryptStringMethod.Body.MaxStackSize >= 1 && decryptStringMethod.Body.MaxStackSize <= 8 && - decryptStringMethod.Body.ExceptionHandlers.Count == 2 && + (decryptStringMethod.Body.ExceptionHandlers.Count == 2 || + (frameworkType == FrameworkType.Silverlight && decryptStringMethod.Body.ExceptionHandlers.Count == 1)) && new LocalTypes(decryptStringMethod).exactly(locals31) && checkTypeFields(fields31)) { return "3.1"; @@ -497,7 +501,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { !decryptStringMethod.IsSynchronized && decryptStringMethod.Body.MaxStackSize >= 1 && decryptStringMethod.Body.MaxStackSize <= 8 && - decryptStringMethod.Body.ExceptionHandlers.Count == 2 && + (decryptStringMethod.Body.ExceptionHandlers.Count == 2 || + (frameworkType == FrameworkType.Silverlight && decryptStringMethod.Body.ExceptionHandlers.Count == 1)) && new LocalTypes(decryptStringMethod).exactly(locals32) && checkTypeFields(fields32)) { return "3.2"; @@ -552,7 +557,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { !decryptStringMethod.IsSynchronized && decryptStringMethod.Body.MaxStackSize >= 1 && decryptStringMethod.Body.MaxStackSize <= 8 && - decryptStringMethod.Body.ExceptionHandlers.Count == 2 && + (decryptStringMethod.Body.ExceptionHandlers.Count == 2 || + (frameworkType == FrameworkType.Silverlight && decryptStringMethod.Body.ExceptionHandlers.Count == 1)) && new LocalTypes(decryptStringMethod).exactly(locals33) && checkTypeFields(fields33)) { return "3.3.29 - 3.3.57 (BETA)"; @@ -608,7 +614,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET { !decryptStringMethod.IsSynchronized && decryptStringMethod.Body.MaxStackSize >= 1 && decryptStringMethod.Body.MaxStackSize <= 8 && - decryptStringMethod.Body.ExceptionHandlers.Count == 2 && + (decryptStringMethod.Body.ExceptionHandlers.Count == 2 || + (frameworkType == FrameworkType.Silverlight && decryptStringMethod.Body.ExceptionHandlers.Count == 1)) && new LocalTypes(decryptStringMethod).exactly(locals33) && checkTypeFields(fields33)) { return "3.3";