/* Copyright (C) 2011-2015 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 dnlib.IO; using dnlib.DotNet; using dnlib.DotNet.Emit; using de4dot.blocks; namespace de4dot.code.deobfuscators.CodeVeil { class AssemblyResolver { ModuleDefMD module; EmbeddedResource bundleData; EmbeddedResource bundleXmlFile; TypeDef bundleType; TypeDef assemblyManagerType; TypeDef bundleStreamProviderIFace; TypeDef xmlParserType; TypeDef bundledAssemblyType; TypeDef 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(ModuleDefMD 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.Data.ReadAllBytes(); var doc = new XmlDocument(); bundleXmlFile.Data.Position = 0; doc.Load(XmlReader.Create(bundleXmlFile.Data.CreateStream())); var manifest = doc.DocumentElement; if (manifest.Name.ToLowerInvariant() != "manifest") { Logger.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") { Logger.w("Unknown element: {0}", assemblyElem.Name); continue; } int offset = GetAttributeValueInt32(assemblyElem, "offset"); if (offset < 0) { Logger.w("Could not find offset attribute"); continue; } var assemblyData = DeobUtils.Inflate(data, offset, data.Length - offset, true); var mod = ModuleDefMD.Load(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; } TypeDef FindBundleType() { foreach (var type in module.Types) { if (type.Namespace != "") continue; if (type.Fields.Count != 2) continue; var ctor = type.FindMethod(".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; } MethodDef FindInitMethod(TypeDef 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; } MethodDef FindGetTempFilenameMethod(TypeDef 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.FieldSig.GetFieldType().TryGetTypeDef(); if (type == null) continue; if (type == bundleType) continue; if (type.Fields.Count != 2) continue; var ctor = type.FindMethod(".ctor"); if (ctor == null) continue; var sig = ctor.MethodSig; if (sig == null || sig.Params.Count != 2) continue; var iface = sig.Params[1].TryGetTypeDef(); 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.FieldSig.GetFieldType().TryGetTypeDef(); if (type == null || type.IsInterface) continue; var ctor = type.FindMethod(".ctor"); if (!DotNetUtils.IsMethod(ctor, "System.Void", "()")) continue; if (type.Fields.Count != 1) continue; var git = type.Fields[0].FieldSig.GetFieldType().ToGenericInstSig(); if (git == null) continue; if (git.GenericType.FullName != "System.Collections.Generic.List`1") continue; if (git.GenericArguments.Count != 1) continue; var type2 = git.GenericArguments[0].TryGetTypeDef(); if (type2 == null) continue; xmlParserType = type; bundledAssemblyType = type2; return; } } void FindStreamProviderType() { if (bundleType == null) return; var ctor = bundleType.FindMethod(".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 MethodDef; 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].Interface != bundleStreamProviderIFace) continue; streamProviderType = type; return; } } } }