diff --git a/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs b/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs index 55607e4d..3a738f25 100644 --- a/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs +++ b/de4dot.code/deobfuscators/DeepSea/AssemblyResolver.cs @@ -41,8 +41,8 @@ namespace de4dot.code.deobfuscators.DeepSea { } } - public AssemblyResolver(ModuleDefinition module) - : base(module) { + public AssemblyResolver(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) + : base(module, simpleDeobfuscator, deob) { } static string[] handlerLocalTypes = new string[] { @@ -78,7 +78,7 @@ namespace de4dot.code.deobfuscators.DeepSea { AssemblyInfo getAssemblyInfos(EmbeddedResource resource) { try { - var decrypted = decryptResource(resource); + var decrypted = decryptResourceV3(resource); var asm = AssemblyDefinition.ReadAssembly(new MemoryStream(decrypted)); var fullName = asm.Name.FullName; var simpleName = asm.Name.Name; diff --git a/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs b/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs index 210f51cb..00039adc 100644 --- a/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs @@ -126,9 +126,9 @@ namespace de4dot.code.deobfuscators.DeepSea { protected override void scanForObfuscator() { stringDecrypter = new StringDecrypter(module); stringDecrypter.find(DeobfuscatedFile); - resourceResolver = new ResourceResolver(module); + resourceResolver = new ResourceResolver(module, DeobfuscatedFile, this); resourceResolver.find(); - assemblyResolver = new AssemblyResolver(module); + assemblyResolver = new AssemblyResolver(module, DeobfuscatedFile, this); assemblyResolver.find(); obfuscatorName = detectVersion(); } @@ -177,7 +177,7 @@ done: } DeobfuscatedFile.stringDecryptersAdded(); - resourceResolver.initialize(DeobfuscatedFile, this); + resourceResolver.initialize(); decryptResources(); dumpEmbeddedAssemblies(); @@ -188,8 +188,8 @@ done: void decryptResources() { if (!options.DecryptResources) return; - var rsrc = resourceResolver.mergeResources(); - if (rsrc == null) + EmbeddedResource rsrc; + if (!resourceResolver.mergeResources(out rsrc)) return; addResourceToBeRemoved(rsrc, "Encrypted resources"); addCctorInitCallToBeRemoved(resourceResolver.InitMethod); diff --git a/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs b/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs index fd44b9b5..691250e2 100644 --- a/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs +++ b/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs @@ -25,6 +25,8 @@ using de4dot.blocks; namespace de4dot.code.deobfuscators.DeepSea { abstract class ResolverBase { protected ModuleDefinition module; + protected ISimpleDeobfuscator simpleDeobfuscator; + protected IDeobfuscator deob; protected MethodDefinition initMethod; protected MethodDefinition resolveHandler; @@ -40,8 +42,10 @@ namespace de4dot.code.deobfuscators.DeepSea { get { return initMethod != null; } } - public ResolverBase(ModuleDefinition module) { + public ResolverBase(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) { this.module = module; + this.simpleDeobfuscator = simpleDeobfuscator; + this.deob = deob; } public void find() { @@ -106,17 +110,27 @@ namespace de4dot.code.deobfuscators.DeepSea { protected abstract bool checkHandlerMethodInternal(MethodDefinition handler); - protected static byte[] decryptResource(EmbeddedResource resource) { - var data = resource.GetResourceData(); - const int baseIndex = 1; - for (int i = baseIndex; i < data.Length; i++) - data[i] ^= (byte)((i - baseIndex) + data[0]); + protected static byte[] decryptResourceV3(EmbeddedResource resource) { + return decryptResourceV3(resource.GetResourceData()); + } - if (BitConverter.ToInt16(data, baseIndex) != 0x5A4D) - return DeobUtils.inflate(data, 1, data.Length - 1, true); + protected static byte[] decryptResourceV3(byte[] data) { + return decryptResource(data, 1, data.Length - 1, data[0]); + } - var data2 = new byte[data.Length - baseIndex]; - Array.Copy(data, baseIndex, data2, 0, data2.Length); + protected static byte[] decryptResourceV4(byte[] data, int magic) { + return decryptResource(data, 0, data.Length, magic); + } + + protected static byte[] decryptResource(byte[] data, int start, int len, int magic) { + for (int i = start; i < start + len; i++) + data[i] ^= (byte)(i - start + magic); + + if (BitConverter.ToInt16(data, start) != 0x5A4D) + return DeobUtils.inflate(data, start, len, true); + + var data2 = new byte[len]; + Array.Copy(data, start, data2, 0, data2.Length); return data2; } } diff --git a/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs b/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs index bcb89f4f..0ed5fa9d 100644 --- a/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs +++ b/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs @@ -18,20 +18,42 @@ */ using Mono.Cecil; +using Mono.Cecil.Cil; +using de4dot.blocks; namespace de4dot.code.deobfuscators.DeepSea { class ResourceResolver : ResolverBase { EmbeddedResource resource; + FieldDefinition resourceField; + int magicV4; + bool isV3; public EmbeddedResource Resource { get { return resource; } } - public ResourceResolver(ModuleDefinition module) - : base(module) { + public ResourceResolver(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) + : base(module, simpleDeobfuscator, deob) { } - static string[] handlerLocalTypes = new string[] { + protected override bool checkHandlerMethodInternal(MethodDefinition handler) { + if (checkHandlerV3(handler)) { + isV3 = true; + return true; + } + + FieldDefinition resourceFieldTmp; + simpleDeobfuscator.deobfuscate(handler); + if (checkHandlerV4(handler, out resourceFieldTmp, out magicV4)) { + isV3 = false; + resourceField = resourceFieldTmp; + return true; + } + + return false; + } + + static string[] handlerLocalTypes_V3 = new string[] { "System.AppDomain", "System.Byte[]", "System.Collections.Generic.Dictionary`2", @@ -42,29 +64,77 @@ namespace de4dot.code.deobfuscators.DeepSea { "System.String", "System.String[]", }; - protected override bool checkHandlerMethodInternal(MethodDefinition handler) { - return new LocalTypes(handler).all(handlerLocalTypes); + static bool checkHandlerV3(MethodDefinition handler) { + return new LocalTypes(handler).all(handlerLocalTypes_V3); } - public void initialize(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) { + static bool checkHandlerV4(MethodDefinition handler, out FieldDefinition resourceField, out int magic) { + magic = 0; + resourceField = getResourceField(handler); + if (resourceField == null) + return false; + + bool foundFieldLen = false; + foreach (var instr in handler.Body.Instructions) { + if (!DotNetUtils.isLdcI4(instr)) + continue; + int constant = DotNetUtils.getLdcI4Value(instr); + if (constant == resourceField.InitialValue.Length && !foundFieldLen) { + foundFieldLen = true; + continue; + } + magic = constant; + return true; + } + + return false; + } + + static FieldDefinition getResourceField(MethodDefinition method) { + foreach (var instr in method.Body.Instructions) { + if (instr.OpCode.Code != Code.Ldtoken) + continue; + var field = instr.Operand as FieldDefinition; + if (field == null || field.InitialValue == null || field.InitialValue.Length == 0) + continue; + return field; + } + return null; + } + + public void initialize() { if (resolveHandler == null) return; - simpleDeobfuscator.deobfuscate(resolveHandler); - simpleDeobfuscator.decryptStrings(resolveHandler, deob); - resource = DeobUtils.getEmbeddedResourceFromCodeStrings(module, resolveHandler); - if (resource == null) { - Log.w("Could not find resource of encrypted resources"); - return; + if (isV3) { + simpleDeobfuscator.deobfuscate(resolveHandler); + simpleDeobfuscator.decryptStrings(resolveHandler, deob); + resource = DeobUtils.getEmbeddedResourceFromCodeStrings(module, resolveHandler); + if (resource == null) { + Log.w("Could not find resource of encrypted resources"); + return; + } } } - public EmbeddedResource mergeResources() { - if (resource == null) - return null; + public bool mergeResources(out EmbeddedResource rsrc) { + rsrc = null; - DeobUtils.decryptAndAddResources(module, resource.Name, () => decryptResource(resource)); - return resource; + if (isV3) { + if (resource == null) + return false; + + DeobUtils.decryptAndAddResources(module, resource.Name, () => decryptResourceV3(resource)); + } + else { + if (resourceField == null) + return false; + + string name = string.Format("Embedded data field {0:X8} RVA {0:X8}", resourceField.MetadataToken.ToInt32(), resourceField.RVA); + DeobUtils.decryptAndAddResources(module, name, () => decryptResourceV4(resourceField.InitialValue, magicV4)); + resourceField.InitialValue = new byte[0]; + } + return true; } } }