/* 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 dot10.DotNet; using de4dot.blocks; namespace de4dot.code.renamer.asmmodules { class Module : IResolver { IObfuscatedFile obfuscatedFile; TypeDefDict types = new TypeDefDict(); MemberRefFinder memberRefFinder; IList> typeRefsToRename = new List>(); IList> methodRefsToRename = new List>(); IList> fieldRefsToRename = new List>(); List customAttributeFieldReferences = new List(); List customAttributePropertyReferences = new List(); List allMethods; public class CustomAttributeReference { public CustomAttribute cattr; public int index; public IMemberRef reference; public CustomAttributeReference(CustomAttribute cattr, int index, IMemberRef reference) { this.cattr = cattr; this.index = index; this.reference = reference; } } public class RefToDef where R : ICodedToken where D : ICodedToken { public R reference; public D definition; public RefToDef(R reference, D definition) { this.reference = reference; this.definition = definition; } } public IEnumerable> TypeRefsToRename { get { return typeRefsToRename; } } public IEnumerable> MethodRefsToRename { get { return methodRefsToRename; } } public IEnumerable> FieldRefsToRename { get { return fieldRefsToRename; } } public IEnumerable CustomAttributeFieldReferences { get { return customAttributeFieldReferences; } } public IEnumerable CustomAttributePropertyReferences { get { return customAttributePropertyReferences; } } public IObfuscatedFile ObfuscatedFile { get { return obfuscatedFile; } } public string Filename { get { return obfuscatedFile.Filename; } } public ModuleDefMD ModuleDefMD { get { return obfuscatedFile.ModuleDefMD; } } public Module(IObfuscatedFile obfuscatedFile) { this.obfuscatedFile = obfuscatedFile; } public IEnumerable getAllTypes() { return types.getValues(); } public IEnumerable getAllMethods() { return allMethods; } public void findAllMemberReferences(ref int typeIndex) { memberRefFinder = new MemberRefFinder(); memberRefFinder.findAll(ModuleDefMD); allMethods = new List(memberRefFinder.methodDefs.Keys); var allTypesList = new List(); foreach (var type in memberRefFinder.typeDefs.Keys) { var typeDef = new MTypeDef(type, this, typeIndex++); types.add(typeDef); allTypesList.Add(typeDef); typeDef.addMembers(); } var allTypesCopy = new List(allTypesList); var typeToIndex = new Dictionary(); for (int i = 0; i < allTypesList.Count; i++) typeToIndex[allTypesList[i].TypeDef] = i; foreach (var typeDef in allTypesList) { if (typeDef.TypeDef.NestedTypes == null) continue; foreach (var nestedTypeDefinition in typeDef.TypeDef.NestedTypes) { int index = typeToIndex[nestedTypeDefinition]; var nestedTypeDef = allTypesCopy[index]; allTypesCopy[index] = null; if (nestedTypeDef == null) // Impossible throw new ApplicationException("Nested type belongs to two or more types"); typeDef.add(nestedTypeDef); nestedTypeDef.NestingType = typeDef; } } } public void resolveAllRefs(IResolver resolver) { foreach (var typeRef in memberRefFinder.typeRefs.Keys) { var typeDef = resolver.resolveType(typeRef); if (typeDef != null) typeRefsToRename.Add(new RefToDef(typeRef, typeDef.TypeDef)); } foreach (var memberRef in memberRefFinder.memberRefs.Keys) { if (memberRef.IsMethodRef) { var methodDef = resolver.resolveMethod(memberRef); if (methodDef != null) methodRefsToRename.Add(new RefToDef(memberRef, methodDef.MethodDef)); } else if (memberRef.IsFieldRef) { var fieldDef = resolver.resolveField(memberRef); if (fieldDef != null) fieldRefsToRename.Add(new RefToDef(memberRef, fieldDef.FieldDef)); } } foreach (var cattr in memberRefFinder.customAttributes.Keys) { var typeDef = resolver.resolveType(cattr.AttributeType); if (typeDef == null) continue; if (cattr.NamedArguments == null) continue; for (int i = 0; i < cattr.NamedArguments.Count; i++) { var namedArg = cattr.NamedArguments[i]; if (namedArg.IsField) { var fieldDef = findField(typeDef, namedArg.Name, namedArg.Type); if (fieldDef == null) { Logger.w("Could not find field {0} in attribute {1} ({2:X8})", Utils.toCsharpString(namedArg.Name), Utils.toCsharpString(typeDef.TypeDef.Name), typeDef.TypeDef.MDToken.ToInt32()); continue; } customAttributeFieldReferences.Add(new CustomAttributeReference(cattr, i, fieldDef.FieldDef)); } else { var propDef = findProperty(typeDef, namedArg.Name, namedArg.Type); if (propDef == null) { Logger.w("Could not find property {0} in attribute {1} ({2:X8})", Utils.toCsharpString(namedArg.Name), Utils.toCsharpString(typeDef.TypeDef.Name), typeDef.TypeDef.MDToken.ToInt32()); continue; } customAttributePropertyReferences.Add(new CustomAttributeReference(cattr, i, propDef.PropertyDef)); } } } } static MFieldDef findField(MTypeDef typeDef, UTF8String name, TypeSig fieldType) { while (typeDef != null) { foreach (var fieldDef in typeDef.AllFields) { if (fieldDef.FieldDef.Name != name) continue; if (new SigComparer().Equals(fieldDef.FieldDef.FieldSig.GetFieldType(), fieldType)) return fieldDef; } if (typeDef.baseType == null) break; typeDef = typeDef.baseType.typeDef; } return null; } static MPropertyDef findProperty(MTypeDef typeDef, UTF8String name, TypeSig propType) { while (typeDef != null) { foreach (var propDef in typeDef.AllProperties) { if (propDef.PropertyDef.Name != name) continue; if (new SigComparer().Equals(propDef.PropertyDef.PropertySig.GetRetType(), propType)) return propDef; } if (typeDef.baseType == null) break; typeDef = typeDef.baseType.typeDef; } return null; } public void onTypesRenamed() { var newTypes = new TypeDefDict(); foreach (var typeDef in types.getValues()) { typeDef.onTypesRenamed(); newTypes.add(typeDef); } types = newTypes; bool old = ModuleDefMD.EnableTypeDefFindCache; ModuleDefMD.EnableTypeDefFindCache = false; ModuleDefMD.EnableTypeDefFindCache = old; } static ITypeDefOrRef getNonGenericTypeReference(ITypeDefOrRef typeRef) { var ts = typeRef as TypeSpec; if (ts == null) return typeRef; var gis = ts.ToGenericInstSig(); if (gis == null || gis.GenericType == null) return typeRef; return gis.GenericType.TypeDefOrRef; } public MTypeDef resolveType(ITypeDefOrRef typeReference) { return this.types.find(getNonGenericTypeReference(typeReference)); } public MMethodDef resolveMethod(IMethodDefOrRef methodRef) { var typeDef = this.types.find(getNonGenericTypeReference(methodRef.DeclaringType)); if (typeDef == null) return null; return typeDef.findMethod(methodRef); } public MFieldDef resolveField(MemberRef fieldRef) { var typeDef = this.types.find(getNonGenericTypeReference(fieldRef.DeclaringType)); if (typeDef == null) return null; return typeDef.findField(fieldRef); } } }