/*
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 MemberReference reference;
public CustomAttributeReference(CustomAttribute cattr, int index, MemberReference reference) {
this.cattr = cattr;
this.index = index;
this.reference = reference;
}
}
public class RefToDef where R : MemberReference where D : R {
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, ModuleDefMD.Types);
allMethods = new List(memberRefFinder.methodDefinitions.Keys);
var allTypesList = new List();
foreach (var type in memberRefFinder.typeDefinitions.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.typeReferences.Keys) {
var typeDef = resolver.resolveType(typeRef);
if (typeDef != null)
typeRefsToRename.Add(new RefToDef(typeRef, typeDef.TypeDef));
}
foreach (var methodRef in memberRefFinder.methodReferences.Keys) {
var methodDef = resolver.resolveMethod(methodRef);
if (methodDef != null)
methodRefsToRename.Add(new RefToDef(methodRef, methodDef.MethodDef));
}
foreach (var fieldRef in memberRefFinder.fieldReferences.Keys) {
var fieldDef = resolver.resolveField(fieldRef);
if (fieldDef != null)
fieldRefsToRename.Add(new RefToDef(fieldRef, fieldDef.FieldDef));
}
foreach (var cattr in memberRefFinder.customAttributes.Keys) {
try {
var typeDef = resolver.resolveType(cattr.AttributeType);
if (typeDef == null)
continue;
for (int i = 0; i < cattr.Fields.Count; i++) {
var field = cattr.Fields[i];
var fieldDef = findFieldByName(typeDef, field.Name);
if (fieldDef == null) {
Log.w("Could not find field {0} in attribute {1} ({2:X8})",
Utils.toCsharpString(field.Name),
Utils.toCsharpString(typeDef.TypeDef.Name),
typeDef.TypeDef.MDToken.ToInt32());
continue;
}
customAttributeFieldReferences.Add(new CustomAttributeReference(cattr, i, fieldDef.FieldDef));
}
for (int i = 0; i < cattr.Properties.Count; i++) {
var prop = cattr.Properties[i];
var propDef = findPropertyByName(typeDef, prop.Name);
if (propDef == null) {
Log.w("Could not find property {0} in attribute {1} ({2:X8})",
Utils.toCsharpString(prop.Name),
Utils.toCsharpString(typeDef.TypeDef.Name),
typeDef.TypeDef.MDToken.ToInt32());
continue;
}
customAttributePropertyReferences.Add(new CustomAttributeReference(cattr, i, propDef.PropertyDef));
}
}
catch {
}
}
}
static MFieldDef findFieldByName(MTypeDef typeDef, string name) {
while (typeDef != null) {
foreach (var fieldDef in typeDef.AllFields) {
if (fieldDef.FieldDef.Name == name)
return fieldDef;
}
if (typeDef.baseType == null)
break;
typeDef = typeDef.baseType.typeDef;
}
return null;
}
static MPropertyDef findPropertyByName(MTypeDef typeDef, string name) {
while (typeDef != null) {
foreach (var propDef in typeDef.AllProperties) {
if (propDef.PropertyDef.Name == name)
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;
}
static TypeReference getNonGenericTypeReference(TypeReference typeReference) {
if (typeReference == null)
return null;
if (!typeReference.IsGenericInstance)
return typeReference;
var type = (GenericInstanceType)typeReference;
return type.ElementType;
}
public MTypeDef resolveType(TypeReference typeReference) {
return this.types.find(getNonGenericTypeReference(typeReference));
}
public MMethodDef resolveMethod(MethodReference methodReference) {
var typeDef = this.types.find(getNonGenericTypeReference(methodReference.DeclaringType));
if (typeDef == null)
return null;
return typeDef.find(methodReference);
}
public MFieldDef resolveField(FieldReference fieldReference) {
var typeDef = this.types.find(getNonGenericTypeReference(fieldReference.DeclaringType));
if (typeDef == null)
return null;
return typeDef.find(fieldReference);
}
}
}