diff --git a/blocks/DotNetUtils.cs b/blocks/DotNetUtils.cs index 9264b7e8..e63ef95c 100644 --- a/blocks/DotNetUtils.cs +++ b/blocks/DotNetUtils.cs @@ -224,6 +224,7 @@ namespace de4dot.blocks { // Returns the variable or null if it's not a ldloc/stloc instruction. It does not return // a local variable if it's a ldloca/ldloca.s instruction. public static VariableDefinition getLocalVar(IList locals, Instruction instr) { + int index; switch (instr.OpCode.Code) { case Code.Ldloc: case Code.Ldloc_S: @@ -235,17 +236,23 @@ namespace de4dot.blocks { case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: - return locals[instr.OpCode.Code - Code.Ldloc_0]; + index = instr.OpCode.Code - Code.Ldloc_0; + break; case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: - return locals[instr.OpCode.Code - Code.Stloc_0]; + index = instr.OpCode.Code - Code.Stloc_0; + break; default: return null; } + + if (index < locals.Count) + return locals[index]; + return null; } public static bool isConditionalBranch(Code code) { @@ -465,7 +472,17 @@ namespace de4dot.blocks { return null; } - public static FieldDefinition getField(TypeDefinition type, string name) { + public static FieldDefinition getField(TypeDefinition type, string typeFullName) { + if (type == null) + return null; + foreach (var field in type.Fields) { + if (field.FieldType.FullName == typeFullName) + return field; + } + return null; + } + + public static FieldDefinition getFieldByName(TypeDefinition type, string name) { if (type == null) return null; foreach (var field in type.Fields) { @@ -670,6 +687,8 @@ namespace de4dot.blocks { if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; var methodRef = call.Operand as MethodReference; + if (methodRef == null) + continue; var type = getType(module, methodRef.DeclaringType); var methodDef = getMethod(type, methodRef); if (methodDef != null) { diff --git a/cecil b/cecil index 9b28c58c..d168993c 160000 --- a/cecil +++ b/cecil @@ -1 +1 @@ -Subproject commit 9b28c58c35470f7cef5f03d3c50c9ba1e65b6843 +Subproject commit d168993c52f46069f113bc2a85cef60da0834c68 diff --git a/de4dot.code/PE/PeImage.cs b/de4dot.code/PE/PeImage.cs index ab702f0d..b9a880af 100644 --- a/de4dot.code/PE/PeImage.cs +++ b/de4dot.code/PE/PeImage.cs @@ -47,6 +47,10 @@ namespace de4dot.code.PE { get { return resources; } } + internal SectionHeader[] Sections { + get { return sectionHeaders; } + } + public uint FileHeaderOffset { get { return fileHeader.Offset; } } diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 151b5601..deef087e 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -44,6 +44,7 @@ ..\ICSharpCode.SharpZipLib.dll + @@ -79,6 +80,20 @@ + + + + + + + + + + + + + + @@ -227,6 +242,15 @@ + + + + + + + + + diff --git a/de4dot.code/deobfuscators/ArrayFinder.cs b/de4dot.code/deobfuscators/ArrayFinder.cs index 2c751110..2d413143 100644 --- a/de4dot.code/deobfuscators/ArrayFinder.cs +++ b/de4dot.code/deobfuscators/ArrayFinder.cs @@ -113,6 +113,17 @@ namespace de4dot.code.deobfuscators { return resultArray; } + public static uint[] getInitializedUInt32Array(int arraySize, MethodDefinition method, ref int newarrIndex) { + var resultArray = getInitializedInt32Array(arraySize, method, ref newarrIndex); + if (resultArray == null) + return null; + + var ary = new uint[resultArray.Length]; + for (int i = 0; i < ary.Length; i++) + ary[i] = (uint)resultArray[i]; + return ary; + } + public static Value[] getInitializedArray(int arraySize, MethodDefinition method, ref int newarrIndex, Code stelemOpCode) { var resultValueArray = new Value[arraySize]; @@ -143,7 +154,7 @@ namespace de4dot.code.deobfuscators { case Code.Starg_S: case Code.Stsfld: case Code.Stfld: - if (emulator.peek() == theArray && i != newarrIndex + 1) + if (emulator.peek() == theArray && i != newarrIndex + 1 && i != newarrIndex + 2) goto done; break; } diff --git a/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs index 0677f8d7..cfa2b9f3 100644 --- a/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs @@ -156,7 +156,7 @@ namespace de4dot.code.deobfuscators.Babel_NET { } void checkVersion(TypeDefinition attr) { - var versionField = DotNetUtils.getField(attr, "Version"); + var versionField = DotNetUtils.getFieldByName(attr, "Version"); if (versionField != null && versionField.IsLiteral && versionField.Constant != null && versionField.Constant is string) { var val = Regex.Match((string)versionField.Constant, @"^(\d+\.\d+\.\d+\.\d+)$"); if (val.Groups.Count < 2) diff --git a/de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs b/de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs index ebcd0d0c..f239f4eb 100644 --- a/de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs +++ b/de4dot.code/deobfuscators/CliSecure/ProxyDelegateFinder.cs @@ -37,10 +37,6 @@ namespace de4dot.code.deobfuscators.CliSecure { setDelegateCreatorMethod(lookup(method, "Could not find delegate creator method")); } - T lookup(T def, string errorMessage) where T : MemberReference { - return DeobUtils.lookup(module, def, errorMessage); - } - public void findDelegateCreator() { foreach (var type in module.Types) { var methodName = "System.Void " + type.FullName + "::icgd(System.Int32)"; diff --git a/de4dot.code/deobfuscators/CodeVeil/AssemblyResolver.cs b/de4dot.code/deobfuscators/CodeVeil/AssemblyResolver.cs new file mode 100644 index 00000000..04d8ccd2 --- /dev/null +++ b/de4dot.code/deobfuscators/CodeVeil/AssemblyResolver.cs @@ -0,0 +1,314 @@ +/* + Copyright (C) 2011-2012 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.Collections.Generic; +using System.IO; +using System.Xml; +using Mono.Cecil; +using Mono.Cecil.Cil; +using de4dot.blocks; + +namespace de4dot.code.deobfuscators.CodeVeil { + class AssemblyResolver { + ModuleDefinition module; + EmbeddedResource bundleData; + EmbeddedResource bundleXmlFile; + TypeDefinition bundleType; + TypeDefinition assemblyManagerType; + TypeDefinition bundleStreamProviderIFace; + TypeDefinition xmlParserType; + TypeDefinition bundledAssemblyType; + TypeDefinition streamProviderType; + List infos = new List(); + + public class AssemblyInfo { + public string fullName; + public string simpleName; + public string extension; + public byte[] data; + + public AssemblyInfo(string fullName, string extension, byte[] data) { + this.fullName = fullName; + this.simpleName = Utils.getAssemblySimpleName(fullName); + this.extension = extension; + this.data = data; + } + + public override string ToString() { + return fullName; + } + } + + public bool CanRemoveTypes { + get { + return bundleType != null && + assemblyManagerType != null && + bundleStreamProviderIFace != null && + xmlParserType != null && + bundledAssemblyType != null && + streamProviderType != null; + } + } + + public IEnumerable BundleTypes { + get { + var list = new List(); + if (!CanRemoveTypes) + return list; + + list.Add(bundleType); + list.Add(assemblyManagerType); + list.Add(bundleStreamProviderIFace); + list.Add(xmlParserType); + list.Add(bundledAssemblyType); + list.Add(streamProviderType); + + return list; + } + } + + public IEnumerable AssemblyInfos { + get { return infos; } + } + + public EmbeddedResource BundleDataResource { + get { return bundleData; } + } + + public EmbeddedResource BundleXmlFileResource { + get { return bundleXmlFile; } + } + + public AssemblyResolver(ModuleDefinition module) { + this.module = module; + } + + public void initialize() { + if (!findTypeAndResources()) + return; + + findEmbeddedAssemblies(); + } + + bool findTypeAndResources() { + var bundleDataTmp = DotNetUtils.getResource(module, ".bundle.dat") as EmbeddedResource; + var bundleXmlFileTmp = DotNetUtils.getResource(module, ".bundle.manifest") as EmbeddedResource; + if (bundleDataTmp == null || bundleXmlFileTmp == null) + return false; + + var bundleTypeTmp = findBundleType(); + if (bundleTypeTmp == null) + return false; + + bundleData = bundleDataTmp; + bundleXmlFile = bundleXmlFileTmp; + bundleType = bundleTypeTmp; + findOtherTypes(); + return true; + } + + void findEmbeddedAssemblies() { + var data = bundleData.GetResourceData(); + + var doc = new XmlDocument(); + doc.Load(XmlReader.Create(bundleXmlFile.GetResourceStream())); + var manifest = doc.DocumentElement; + if (manifest.Name.ToLowerInvariant() != "manifest") { + Log.w("Could not find Manifest element"); + return; + } + foreach (var tmp in manifest.ChildNodes) { + var assemblyElem = tmp as XmlElement; + if (assemblyElem == null) + continue; + + if (assemblyElem.Name.ToLowerInvariant() != "assembly") { + Log.w("Unknown element: {0}", assemblyElem.Name); + continue; + } + + int offset = getAttributeValueInt32(assemblyElem, "offset"); + if (offset < 0) { + Log.w("Could not find offset attribute"); + continue; + } + + var assemblyData = DeobUtils.inflate(data, offset, data.Length - offset, true); + var mod = ModuleDefinition.ReadModule(new MemoryStream(assemblyData)); + infos.Add(new AssemblyInfo(mod.Assembly.FullName, DeobUtils.getExtension(mod.Kind), assemblyData)); + } + } + + static int getAttributeValueInt32(XmlElement elem, string attrName) { + var str = elem.GetAttribute(attrName); + if (string.IsNullOrEmpty(str)) + return -1; + + int value; + if (!int.TryParse(str, out value)) + return -1; + + return value; + } + + TypeDefinition findBundleType() { + foreach (var type in module.Types) { + if (type.Namespace != "") + continue; + if (type.Fields.Count != 2) + continue; + + var ctor = DotNetUtils.getMethod(type, ".ctor"); + if (ctor == null || !ctor.IsPrivate) + continue; + if (!DotNetUtils.isMethod(ctor, "System.Void", "(System.Reflection.Assembly)")) + continue; + + var initMethodTmp = findInitMethod(type); + if (initMethodTmp == null) + continue; + var getTempFilenameMethod = findGetTempFilenameMethod(type); + if (getTempFilenameMethod == null) + continue; + + return type; + } + + return null; + } + + MethodDefinition findInitMethod(TypeDefinition type) { + foreach (var method in type.Methods) { + if (!method.IsStatic || method.Body == null) + continue; + if (!method.IsPublic && !method.IsAssembly) + continue; + if (!DotNetUtils.isMethod(method, "System.Void", "(System.Reflection.Assembly)")) + continue; + + return method; + } + + return null; + } + + MethodDefinition findGetTempFilenameMethod(TypeDefinition type) { + foreach (var method in type.Methods) { + if (method.IsStatic || method.Body == null) + continue; + if (!method.IsPublic && !method.IsAssembly) + continue; + if (!DotNetUtils.isMethod(method, "System.String", "(System.String)")) + continue; + + return method; + } + + return null; + } + + void findOtherTypes() { + findAssemblyManagerType(); + findXmlParserType(); + findStreamProviderType(); + } + + void findAssemblyManagerType() { + if (bundleType == null) + return; + + foreach (var field in bundleType.Fields) { + var type = field.FieldType as TypeDefinition; + if (type == null) + continue; + if (type == bundleType) + continue; + if (type.Fields.Count != 2) + continue; + + var ctor = DotNetUtils.getMethod(type, ".ctor"); + if (ctor == null || ctor.Parameters.Count != 2) + continue; + var iface = ctor.Parameters[1].ParameterType as TypeDefinition; + if (iface == null || !iface.IsInterface) + continue; + + assemblyManagerType = type; + bundleStreamProviderIFace = iface; + return; + } + } + + void findXmlParserType() { + if (assemblyManagerType == null) + return; + foreach (var field in assemblyManagerType.Fields) { + var type = field.FieldType as TypeDefinition; + if (type == null || type.IsInterface) + continue; + var ctor = DotNetUtils.getMethod(type, ".ctor"); + if (!DotNetUtils.isMethod(ctor, "System.Void", "()")) + continue; + if (type.Fields.Count != 1) + continue; + var git = type.Fields[0].FieldType as GenericInstanceType; + if (git == null) + continue; + if (git.ElementType.FullName != "System.Collections.Generic.List`1") + continue; + if (git.GenericArguments.Count != 1) + continue; + var type2 = git.GenericArguments[0] as TypeDefinition; + if (type2 == null) + continue; + + xmlParserType = type; + bundledAssemblyType = type2; + return; + } + } + + void findStreamProviderType() { + if (bundleType == null) + return; + var ctor = DotNetUtils.getMethod(bundleType, ".ctor"); + if (!DotNetUtils.isMethod(ctor, "System.Void", "(System.Reflection.Assembly)")) + return; + foreach (var instr in ctor.Body.Instructions) { + if (instr.OpCode.Code != Code.Newobj) + continue; + var newobjCtor = instr.Operand as MethodDefinition; + if (newobjCtor == null) + continue; + if (newobjCtor.DeclaringType == assemblyManagerType) + continue; + if (!DotNetUtils.isMethod(newobjCtor, "System.Void", "(System.Reflection.Assembly,System.String)")) + continue; + var type = newobjCtor.DeclaringType; + if (type.Interfaces.Count != 1) + continue; + if (type.Interfaces[0] != bundleStreamProviderIFace) + continue; + + streamProviderType = type; + return; + } + } + } +} diff --git a/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs b/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs new file mode 100644 index 00000000..133b2e48 --- /dev/null +++ b/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs @@ -0,0 +1,286 @@ +/* + Copyright (C) 2011-2012 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; +using System.Collections.Generic; +using Mono.Cecil; +using Mono.MyStuff; +using de4dot.blocks; + +namespace de4dot.code.deobfuscators.CodeVeil { + public class DeobfuscatorInfo : DeobfuscatorInfoBase { + public const string THE_NAME = "CodeVeil"; + public const string THE_TYPE = "cv"; + const string DEFAULT_REGEX = @"!^[A-Za-z]{1,2}$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX; + + public DeobfuscatorInfo() + : base(DEFAULT_REGEX) { + } + + public override string Name { + get { return THE_NAME; } + } + + public override string Type { + get { return THE_TYPE; } + } + + public override IDeobfuscator createDeobfuscator() { + return new Deobfuscator(new Deobfuscator.Options { + ValidNameRegex = validNameRegex.get(), + }); + } + + protected override IEnumerable