diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 3dcd2afe..796b3536 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -61,6 +61,7 @@ + diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs b/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs index aa39c88b..7e040e9e 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/Deobfuscator.cs @@ -58,6 +58,7 @@ namespace de4dot.deobfuscators.CryptoObfuscator { ResourceDecrypter resourceDecrypter; ResourceResolver resourceResolver; AssemblyResolver assemblyResolver; + StringDecrypter stringDecrypter; internal class Options : OptionsBase { } @@ -88,6 +89,8 @@ namespace de4dot.deobfuscators.CryptoObfuscator { val += 100; else if (foundObfuscatedSymbols) val += 10; + if (stringDecrypter.Detected) + val += 10; return val; } @@ -102,6 +105,9 @@ namespace de4dot.deobfuscators.CryptoObfuscator { } if (checkCryptoObfuscator()) foundObfuscatedSymbols = true; + + stringDecrypter = new StringDecrypter(module); + stringDecrypter.detect(); } void initializeVersion(TypeDefinition attr) { @@ -140,9 +146,24 @@ namespace de4dot.deobfuscators.CryptoObfuscator { resourceResolver.find(); assemblyResolver.find(); + decryptResources(); + stringDecrypter.init(resourceDecrypter); + if (stringDecrypter.StringDecrypterMethod != null) { + staticStringDecrypter.add(stringDecrypter.StringDecrypterMethod, (method, args) => { + return stringDecrypter.decrypt((int)args[0]); + }); + } + dumpEmbeddedAssemblies(); } + void decryptResources() { + var rsrc = resourceResolver.mergeResources(); + if (rsrc == null) + return; + addResourceToBeRemoved(rsrc, "Encrypted resources"); + } + void dumpEmbeddedAssemblies() { foreach (var info in assemblyResolver.AssemblyInfos) { dumpEmbeddedFile(info.resource, info.assemblyName, true); @@ -155,7 +176,16 @@ namespace de4dot.deobfuscators.CryptoObfuscator { void dumpEmbeddedFile(EmbeddedResource resource, string assemblyName, bool isAssembly) { string extension = isAssembly ? ".dll" : ".pdb"; DeobfuscatedFile.createAssemblyFile(resourceDecrypter.decrypt(resource.GetResourceStream()), Utils.getAssemblySimpleName(assemblyName), extension); - addResourceToBeRemoved(resource, string.Format("Embedded assembly{0}: {1}", isAssembly ? "" : " (pdb)", assemblyName)); + string reason = isAssembly ? string.Format("Embedded assembly: {0}", assemblyName) : + string.Format("Embedded pdb: {0}", assemblyName); + addResourceToBeRemoved(resource, reason); + } + + public override IEnumerable getStringDecrypterMethods() { + var list = new List(); + if (stringDecrypter.StringDecrypterMethod != null) + list.Add(stringDecrypter.StringDecrypterMethod.MetadataToken.ToInt32().ToString("X8")); + return list; } } } diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/ResourceResolver.cs b/de4dot.code/deobfuscators/CryptoObfuscator/ResourceResolver.cs index f7cb3f05..5b2790a2 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/ResourceResolver.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/ResourceResolver.cs @@ -17,6 +17,7 @@ along with de4dot. If not, see . */ +using System; using Mono.Cecil; using Mono.Cecil.Cil; using de4dot.blocks; @@ -26,6 +27,7 @@ namespace de4dot.deobfuscators.CryptoObfuscator { ModuleDefinition module; ResourceDecrypter resourceDecrypter; TypeDefinition resolverType; + bool mergedIt = false; public ResourceResolver(ModuleDefinition module, ResourceDecrypter resourceDecrypter) { this.module = module; @@ -48,6 +50,19 @@ namespace de4dot.deobfuscators.CryptoObfuscator { } } + public EmbeddedResource mergeResources() { + if (mergedIt) + return null; + + var resource = DotNetUtils.getResource(module, module.Assembly.Name.Name) as EmbeddedResource; + if (resource == null) + throw new ApplicationException("Could not find encrypted resources"); + + DeobUtils.decryptAndAddResources(module, resource.Name, () => resourceDecrypter.decrypt(resource.GetResourceStream())); + mergedIt = true; + return resource; + } + bool checkType(TypeDefinition type, MethodDefinition initMethod) { if (!initMethod.HasBody) return false; diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs b/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs new file mode 100644 index 00000000..55257218 --- /dev/null +++ b/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs @@ -0,0 +1,120 @@ +/* + Copyright (C) 2011 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System.Text; +using Mono.Cecil; +using de4dot.blocks; + +namespace de4dot.deobfuscators.CryptoObfuscator { + class StringDecrypter { + ModuleDefinition module; + EmbeddedResource stringResource; + TypeDefinition stringDecrypterType; + MethodDefinition stringDecrypterMethod; + byte[] decryptedData; + + public bool Detected { + get { return stringDecrypterType != null; } + } + + public MethodDefinition StringDecrypterMethod { + get { return stringDecrypterMethod; } + } + + public StringDecrypter(ModuleDefinition module) { + this.module = module; + } + + public void detect() { + TypeDefinition type; + MethodDefinition method; + if (!findStringDecrypterType(out type, out method)) + return; + + stringDecrypterType = type; + stringDecrypterMethod = method; + } + + public void init(ResourceDecrypter resourceDecrypter) { + if (decryptedData != null) + return; + + var resourceName = module.Assembly.Name.Name + module.Assembly.Name.Name; + stringResource = DotNetUtils.getResource(module, resourceName) as EmbeddedResource; + if (stringResource == null) + return; + + decryptedData = resourceDecrypter.decrypt(stringResource.GetResourceStream()); + } + + public string decrypt(int index) { + int len; + byte b = decryptedData[index++]; + if ((b & 0x80) == 0) + len = b; + else if ((b & 0x40) == 0) + len = ((b & 0x3F) << 8) + decryptedData[index++]; + else { + len = ((b & 0x3F) << 24) + + ((int)decryptedData[index++] << 16) + + ((int)decryptedData[index++] << 8) + + decryptedData[index++]; + } + + return Encoding.Unicode.GetString(decryptedData, index, len); + } + + bool findStringDecrypterType(out TypeDefinition theType, out MethodDefinition theMethod) { + theType = null; + theMethod = null; + + foreach (var type in module.Types) { + if (type.IsPublic) + continue; + if (type.Fields.Count != 1) + continue; + if (DotNetUtils.findFieldType(type, "System.Byte[]", true) == null) + continue; + if (type.Methods.Count != 3) + continue; + if (type.HasEvents || type.HasProperties) + continue; + + MethodDefinition method = null; + foreach (var m in type.Methods) { + if (m.Name == ".ctor" || m.Name == ".cctor") + continue; + if (DotNetUtils.isMethod(m, "System.String", "(System.Int32)")) { + method = m; + continue; + } + break; + } + if (method == null) + continue; + + theType = type; + theMethod = method; + return true; + } + + return false; + } + } +}