diff --git a/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs b/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs index 796ee12e..ec4c4bb4 100644 --- a/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs +++ b/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs @@ -76,7 +76,8 @@ namespace de4dot.code.deobfuscators.DeepSea { simpleDeobfuscator.deobfuscate(handler); List fieldInfosTmp; - if (checkHandlerV4(handler, out fieldInfosTmp)) { + if (checkHandlerV4(handler, out fieldInfosTmp) || + checkHandlerV4_0_4(handler, out fieldInfosTmp)) { isV3 = false; fieldInfos = fieldInfosTmp; return true; @@ -110,29 +111,93 @@ namespace de4dot.code.deobfuscators.DeepSea { return new LocalTypes(handler).all(handlerLocalTypes_SL); } + // 4.0.1.18 .. 4.0.3 bool checkHandlerV4(MethodDefinition handler, out List fieldInfos) { fieldInfos = new List(); var instrs = handler.Body.Instructions; - for (int i = 0; i < instrs.Count - 2; i++) { - var ldtoken = instrs[i]; + for (int i = 0; i < instrs.Count - 3; i++) { + int index = i; + + var ldtoken = instrs[index++]; if (ldtoken.OpCode.Code != Code.Ldtoken) continue; var field = ldtoken.Operand as FieldDefinition; if (field == null || field.InitialValue == null || field.InitialValue.Length == 0) return false; - var ldci4_len = instrs[i + 1]; + var ldci4_len = instrs[index++]; if (!DotNetUtils.isLdcI4(ldci4_len)) return false; if (DotNetUtils.getLdcI4Value(ldci4_len) != field.InitialValue.Length) return false; - var ldci4_magic = instrs[i + 2]; + var ldci4_magic = instrs[index++]; if (!DotNetUtils.isLdcI4(ldci4_magic)) return false; int magic = DotNetUtils.getLdcI4Value(ldci4_magic); + var call = instrs[index++]; + if (call.OpCode.Code == Code.Tail) + call = instrs[index++]; + if (call.OpCode.Code != Code.Call) + return false; + if (!DotNetUtils.isMethod(call.Operand as MethodReference, "System.Reflection.Assembly", "(System.RuntimeFieldHandle,System.Int32,System.Int32)")) + return false; + + fieldInfos.Add(new FieldInfo(field, magic)); + } + + return fieldInfos.Count != 0; + } + + // 4.0.4+ + bool checkHandlerV4_0_4(MethodDefinition handler, out List fieldInfos) { + fieldInfos = new List(); + + var instrs = handler.Body.Instructions; + for (int i = 0; i < instrs.Count - 8; i++) { + int index = i; + + var ldci4_len = instrs[index++]; + if (!DotNetUtils.isLdcI4(ldci4_len)) + continue; + if (instrs[index++].OpCode.Code != Code.Newarr) + continue; + if (!DotNetUtils.isStloc(instrs[index++])) + continue; + if (!DotNetUtils.isLdloc(instrs[index++])) + continue; + + var ldtoken = instrs[index++]; + if (ldtoken.OpCode.Code != Code.Ldtoken) + continue; + var field = ldtoken.Operand as FieldDefinition; + if (field == null || field.InitialValue == null || field.InitialValue.Length == 0) + continue; + + var call1 = instrs[index++]; + if (call1.OpCode.Code != Code.Call) + continue; + if (!DotNetUtils.isMethod(call1.Operand as MethodReference, "System.Void", "(System.Array,System.RuntimeFieldHandle)")) + continue; + + if (!DotNetUtils.isLdloc(instrs[index++])) + continue; + + var ldci4_magic = instrs[index++]; + if (!DotNetUtils.isLdcI4(ldci4_magic)) + continue; + int magic = DotNetUtils.getLdcI4Value(ldci4_magic); + + var call2 = instrs[index++]; + if (call2.OpCode.Code == Code.Tail) + call2 = instrs[index++]; + if (call2.OpCode.Code != Code.Call) + continue; + if (!DotNetUtils.isMethod(call2.Operand as MethodReference, "System.Reflection.Assembly", "(System.Byte[],System.Int32)")) + continue; + fieldInfos.Add(new FieldInfo(field, magic)); } @@ -145,7 +210,7 @@ namespace de4dot.code.deobfuscators.DeepSea { return getAssemblyInfosV4(); } - public IEnumerable getAssemblyInfosV3() { + IEnumerable getAssemblyInfosV3() { var infos = new List(); foreach (var tmp in module.Resources) { @@ -180,7 +245,7 @@ namespace de4dot.code.deobfuscators.DeepSea { return new AssemblyInfo(decryptedData, fullName, simpleName, extension, resource); } - public IEnumerable getAssemblyInfosV4() { + IEnumerable getAssemblyInfosV4() { var infos = new List(); if (fieldInfos == null) diff --git a/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs b/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs index 98af2ec1..97ed2461 100644 --- a/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs @@ -208,6 +208,7 @@ done: addCallToBeRemoved(module.EntryPoint, resourceResolver.InitMethod); addMethodToBeRemoved(resourceResolver.InitMethod, "Resource resolver init method"); addMethodToBeRemoved(resourceResolver.HandlerMethod, "Resource resolver handler method"); + addMethodToBeRemoved(resourceResolver.GetDataMethod, "Resource resolver 'get resource data' method"); } void dumpEmbeddedAssemblies() { diff --git a/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs b/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs index d3cf2c1a..44383596 100644 --- a/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs +++ b/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs @@ -18,6 +18,7 @@ */ using System; +using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; using de4dot.blocks; @@ -80,16 +81,16 @@ namespace de4dot.code.deobfuscators.DeepSea { if (!checkResolverInitMethodInternal(resolverInitMethod)) return false; - var resolveHandlerMethod = getLdftnMethod(resolverInitMethod); - if (resolveHandlerMethod == null) - return false; + foreach (var resolveHandlerMethod in getLdftnMethods(resolverInitMethod)) { + if (!checkHandlerMethod(resolveHandlerMethod)) + continue; - if (!checkHandlerMethod(resolveHandlerMethod)) - return false; + initMethod = resolverInitMethod; + resolveHandler = resolveHandlerMethod; + return true; + } - initMethod = resolverInitMethod; - resolveHandler = resolveHandlerMethod; - return true; + return false; } protected abstract bool checkResolverInitMethodInternal(MethodDefinition resolverInitMethod); @@ -107,15 +108,16 @@ namespace de4dot.code.deobfuscators.DeepSea { return false; } - MethodDefinition getLdftnMethod(MethodDefinition method) { + IEnumerable getLdftnMethods(MethodDefinition method) { + var list = new List(); foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code != Code.Ldftn) continue; var loadedMethod = instr.Operand as MethodDefinition; if (loadedMethod != null) - return loadedMethod; + list.Add(loadedMethod); } - return null; + return list; } bool checkHandlerMethod(MethodDefinition handler) { diff --git a/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs b/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs index 8ad11b37..74a9f123 100644 --- a/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs +++ b/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs @@ -25,9 +25,14 @@ namespace de4dot.code.deobfuscators.DeepSea { class ResourceResolver : ResolverBase { EmbeddedResource resource; FieldDefinition resourceField; + MethodDefinition getDataMethod; int magicV4; bool isV3; + public MethodDefinition GetDataMethod { + get { return getDataMethod; } + } + public EmbeddedResource Resource { get { return resource; } } @@ -47,10 +52,12 @@ namespace de4dot.code.deobfuscators.DeepSea { } FieldDefinition resourceFieldTmp; + MethodDefinition getDataMethodTmp; simpleDeobfuscator.deobfuscate(handler); - if (checkHandlerV4(handler, out resourceFieldTmp, out magicV4)) { + if (checkHandlerV4(handler, out resourceFieldTmp, out getDataMethodTmp, out magicV4)) { isV3 = false; resourceField = resourceFieldTmp; + getDataMethod = getDataMethodTmp; return true; } @@ -72,25 +79,65 @@ namespace de4dot.code.deobfuscators.DeepSea { return new LocalTypes(handler).all(handlerLocalTypes_V3); } - static bool checkHandlerV4(MethodDefinition handler, out FieldDefinition resourceField, out int magic) { - magic = 0; - resourceField = getResourceField(handler); - if (resourceField == null) - return false; + static bool checkHandlerV4(MethodDefinition handler, out FieldDefinition resourceField, out MethodDefinition getDataMethod, out int magic) { + var instrs = handler.Body.Instructions; + for (int i = 0; i < instrs.Count; i++) { + int index = i; - bool foundFieldLen = false; - foreach (var instr in handler.Body.Instructions) { - if (!DotNetUtils.isLdcI4(instr)) + if (instrs[index++].OpCode.Code != Code.Ldarg_1) continue; - int constant = DotNetUtils.getLdcI4Value(instr); - if (constant == resourceField.InitialValue.Length && !foundFieldLen) { - foundFieldLen = true; + + var ldtoken = instrs[index++]; + if (ldtoken.OpCode.Code != Code.Ldtoken) continue; + var field = ldtoken.Operand as FieldDefinition; + + string methodSig = "(System.ResolveEventArgs,System.RuntimeFieldHandle,System.Int32,System.String,System.Int32)"; + var method = ldtoken.Operand as MethodDefinition; + if (method != null) { + // >= 4.0.4 + if (!DotNetUtils.isMethod(method, "System.Byte[]", "()")) + continue; + field = getResourceField(method); + methodSig = "(System.ResolveEventArgs,System.RuntimeMethodHandle,System.Int32,System.String,System.Int32)"; } - magic = constant; + else { + // 4.0.1.18 .. 4.0.3 + } + + if (field.InitialValue == null || field.InitialValue.Length == 0) + continue; + + var ldci4_len = instrs[index++]; + if (!DotNetUtils.isLdcI4(ldci4_len)) + continue; + if (DotNetUtils.getLdcI4Value(ldci4_len) != field.InitialValue.Length) + continue; + + if (instrs[index++].OpCode.Code != Code.Ldstr) + continue; + + var ldci4_magic = instrs[index++]; + if (!DotNetUtils.isLdcI4(ldci4_magic)) + continue; + magic = DotNetUtils.getLdcI4Value(ldci4_magic); + + var call = instrs[index++]; + if (call.OpCode.Code == Code.Tail) + call = instrs[index++]; + if (call.OpCode.Code != Code.Call) + continue; + if (!DotNetUtils.isMethod(call.Operand as MethodReference, "System.Reflection.Assembly", methodSig)) + continue; + + resourceField = field; + getDataMethod = method; return true; } + magic = 0; + resourceField = null; + getDataMethod = null; return false; }