/*
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;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.renamer.asmmodules {
class MemberRefFinder {
public Dictionary eventDefinitions = new Dictionary();
public Dictionary fieldReferences = new Dictionary();
public Dictionary fieldDefinitions = new Dictionary();
public Dictionary methodReferences = new Dictionary();
public Dictionary methodDefinitions = new Dictionary();
public Dictionary genericInstanceMethods = new Dictionary();
public Dictionary propertyDefinitions = new Dictionary();
public Dictionary typeReferences = new Dictionary();
public Dictionary typeDefinitions = new Dictionary();
public Dictionary genericParameters = new Dictionary();
public Dictionary arrayTypes = new Dictionary();
public Dictionary functionPointerTypes = new Dictionary();
public Dictionary genericInstanceTypes = new Dictionary();
public Dictionary optionalModifierTypes = new Dictionary();
public Dictionary requiredModifierTypes = new Dictionary();
public Dictionary pinnedTypes = new Dictionary();
public Dictionary pointerTypes = new Dictionary();
public Dictionary byReferenceTypes = new Dictionary();
public Dictionary sentinelTypes = new Dictionary();
Stack memberRefStack;
public void removeTypeDefinition(TypeDefinition td) {
if (!typeDefinitions.Remove(td))
throw new ApplicationException(string.Format("Could not remove TypeDefinition: {0}", td));
}
public void removeEventDefinition(EventDefinition ed) {
if (!eventDefinitions.Remove(ed))
throw new ApplicationException(string.Format("Could not remove EventDefinition: {0}", ed));
}
public void removeFieldDefinition(FieldDefinition fd) {
if (!fieldDefinitions.Remove(fd))
throw new ApplicationException(string.Format("Could not remove FieldDefinition: {0}", fd));
}
public void removeMethodDefinition(MethodDefinition md) {
if (!methodDefinitions.Remove(md))
throw new ApplicationException(string.Format("Could not remove MethodDefinition: {0}", md));
}
public void removePropertyDefinition(PropertyDefinition pd) {
if (!propertyDefinitions.Remove(pd))
throw new ApplicationException(string.Format("Could not remove PropertyDefinition: {0}", pd));
}
public void findAll(ModuleDefinition module, IEnumerable types) {
// This needs to be big. About 2048 entries should be enough for most though...
memberRefStack = new Stack(0x1000);
foreach (var type in types)
pushMember(type);
addModule(module);
processAll();
memberRefStack = null;
}
Dictionary exceptionMessages = new Dictionary(StringComparer.Ordinal);
void access(Action action) {
string exMessage = null;
try {
action();
}
catch (ResolutionException ex) {
exMessage = ex.Message;
}
catch (AssemblyResolutionException ex) {
exMessage = ex.Message;
}
if (exMessage != null) {
if (!exceptionMessages.ContainsKey(exMessage)) {
exceptionMessages[exMessage] = true;
Log.w("Could not resolve a reference. ERROR: {0}", exMessage);
}
}
}
void pushMember(MemberReference memberReference) {
if (memberReference == null)
return;
memberRefStack.Push(memberReference);
}
void addModule(ModuleDefinition module) {
pushMember(module.EntryPoint);
access(() => addCustomAttributes(module.CustomAttributes));
if (module.Assembly != null && module == module.Assembly.MainModule) {
var asm = module.Assembly;
access(() => addCustomAttributes(asm.CustomAttributes));
addSecurityDeclarations(asm.SecurityDeclarations);
}
}
void processAll() {
while (memberRefStack.Count > 0)
process(memberRefStack.Pop());
}
void process(MemberReference memberRef) {
if (memberRef == null)
return;
var type = MemberReferenceHelper.getMemberReferenceType(memberRef);
switch (type) {
case CecilType.ArrayType:
doArrayType((ArrayType)memberRef);
break;
case CecilType.ByReferenceType:
doByReferenceType((ByReferenceType)memberRef);
break;
case CecilType.EventDefinition:
doEventDefinition((EventDefinition)memberRef);
break;
case CecilType.FieldDefinition:
doFieldDefinition((FieldDefinition)memberRef);
break;
case CecilType.FieldReference:
doFieldReference((FieldReference)memberRef);
break;
case CecilType.FunctionPointerType:
doFunctionPointerType((FunctionPointerType)memberRef);
break;
case CecilType.GenericInstanceMethod:
doGenericInstanceMethod((GenericInstanceMethod)memberRef);
break;
case CecilType.GenericInstanceType:
doGenericInstanceType((GenericInstanceType)memberRef);
break;
case CecilType.GenericParameter:
doGenericParameter((GenericParameter)memberRef);
break;
case CecilType.MethodDefinition:
doMethodDefinition((MethodDefinition)memberRef);
break;
case CecilType.MethodReference:
doMethodReference((MethodReference)memberRef);
break;
case CecilType.OptionalModifierType:
doOptionalModifierType((OptionalModifierType)memberRef);
break;
case CecilType.PinnedType:
doPinnedType((PinnedType)memberRef);
break;
case CecilType.PointerType:
doPointerType((PointerType)memberRef);
break;
case CecilType.PropertyDefinition:
doPropertyDefinition((PropertyDefinition)memberRef);
break;
case CecilType.RequiredModifierType:
doRequiredModifierType((RequiredModifierType)memberRef);
break;
case CecilType.SentinelType:
doSentinelType((SentinelType)memberRef);
break;
case CecilType.TypeDefinition:
doTypeDefinition((TypeDefinition)memberRef);
break;
case CecilType.TypeReference:
doTypeReference((TypeReference)memberRef);
break;
default:
throw new ApplicationException(string.Format("Unknown cecil type {0}", type));
}
}
void addCustomAttributes(IEnumerable attributes) {
if (attributes == null)
return;
foreach (var attr in attributes)
addCustomAttribute(attr);
}
void addCustomAttributeArguments(IEnumerable args) {
if (args == null)
return;
foreach (var arg in args)
addCustomAttributeArgument(arg);
}
void addCustomAttributeNamedArguments(IEnumerable args) {
if (args == null)
return;
foreach (var arg in args)
addCustomAttributeNamedArgument(arg);
}
void addParameterDefinitions(IEnumerable parameters) {
if (parameters == null)
return;
foreach (var param in parameters)
addParameterDefinition(param);
}
void addSecurityDeclarations(IEnumerable decls) {
if (decls == null)
return;
foreach (var decl in decls)
addSecurityDeclaration(decl);
}
void addSecurityAttributes(IEnumerable attrs) {
if (attrs == null)
return;
foreach (var attr in attrs)
addSecurityAttribute(attr);
}
void addExceptionHandlers(IEnumerable handlers) {
if (handlers == null)
return;
foreach (var h in handlers)
addExceptionHandler(h);
}
void addVariableDefinitions(IEnumerable vars) {
if (vars == null)
return;
foreach (var v in vars)
addVariableDefinition(v);
}
void addScopes(IEnumerable scopes) {
if (scopes == null)
return;
foreach (var s in scopes)
addScope(s);
}
void addInstructions(IEnumerable instrs) {
if (instrs == null)
return;
foreach (var instr in instrs) {
switch (instr.OpCode.OperandType) {
case OperandType.InlineTok:
case OperandType.InlineType:
case OperandType.InlineMethod:
case OperandType.InlineField:
pushMember(instr.Operand as MemberReference);
break;
case OperandType.InlineSig:
addCallSite(instr.Operand as CallSite);
break;
case OperandType.InlineVar:
case OperandType.ShortInlineVar:
addVariableDefinition(instr.Operand as VariableDefinition);
break;
case OperandType.InlineArg:
case OperandType.ShortInlineArg:
addParameterDefinition(instr.Operand as ParameterDefinition);
break;
}
}
}
void addTypeReferences(IEnumerable types) {
if (types == null)
return;
foreach (var typeRef in types)
pushMember(typeRef);
}
void addTypeDefinitions(IEnumerable types) {
if (types == null)
return;
foreach (var type in types)
pushMember(type);
}
void addMethodReferences(IEnumerable methodRefs) {
if (methodRefs == null)
return;
foreach (var m in methodRefs)
pushMember(m);
}
void addMethodDefinitions(IEnumerable methods) {
if (methods == null)
return;
foreach (var m in methods)
pushMember(m);
}
void addGenericParameters(IEnumerable parameters) {
if (parameters == null)
return;
foreach (var param in parameters)
pushMember(param);
}
void addFieldDefinitions(IEnumerable fields) {
if (fields == null)
return;
foreach (var f in fields)
pushMember(f);
}
void addEventDefinitions(IEnumerable events) {
if (events == null)
return;
foreach (var e in events)
pushMember(e);
}
void addPropertyDefinitions(IEnumerable props) {
if (props == null)
return;
foreach (var p in props)
pushMember(p);
}
void addMemberReference(MemberReference memberReference) {
if (memberReference == null)
return;
pushMember(memberReference.DeclaringType);
}
void addEventReference(EventReference eventReference) {
if (eventReference == null)
return;
addMemberReference(eventReference);
pushMember(eventReference.EventType);
}
void addEventDefinition(EventDefinition eventDefinition) {
if (eventDefinition == null)
return;
addEventReference(eventDefinition);
pushMember(eventDefinition.AddMethod);
pushMember(eventDefinition.InvokeMethod);
pushMember(eventDefinition.RemoveMethod);
addMethodDefinitions(eventDefinition.OtherMethods);
access(() => addCustomAttributes(eventDefinition.CustomAttributes));
}
void addCustomAttribute(CustomAttribute attr) {
if (attr == null)
return;
pushMember(attr.Constructor);
// Some obfuscators don't rename custom ctor arguments to the new name, causing
// Mono.Cecil to use a null reference.
try { access(() => addCustomAttributeArguments(attr.ConstructorArguments)); } catch (NullReferenceException) { }
try { access(() => addCustomAttributeNamedArguments(attr.Fields)); } catch (NullReferenceException) { }
try { access(() => addCustomAttributeNamedArguments(attr.Properties)); } catch (NullReferenceException) { }
}
void addCustomAttributeArgument(CustomAttributeArgument arg) {
pushMember(arg.Type);
}
void addCustomAttributeNamedArgument(CustomAttributeNamedArgument field) {
addCustomAttributeArgument(field.Argument);
}
void addFieldReference(FieldReference fieldReference) {
if (fieldReference == null)
return;
addMemberReference(fieldReference);
pushMember(fieldReference.FieldType);
}
void addFieldDefinition(FieldDefinition fieldDefinition) {
if (fieldDefinition == null)
return;
addFieldReference(fieldDefinition);
access(() => addCustomAttributes(fieldDefinition.CustomAttributes));
}
void addMethodReference(MethodReference methodReference) {
if (methodReference == null)
return;
addMemberReference(methodReference);
addParameterDefinitions(methodReference.Parameters);
addMethodReturnType(methodReference.MethodReturnType);
addGenericParameters(methodReference.GenericParameters);
}
void addParameterReference(ParameterReference param) {
if (param == null)
return;
pushMember(param.ParameterType);
}
void addParameterDefinition(ParameterDefinition param) {
if (param == null)
return;
addParameterReference(param);
pushMember(param.Method as MemberReference);
access(() => addCustomAttributes(param.CustomAttributes));
}
void addMethodReturnType(MethodReturnType methodReturnType) {
if (methodReturnType == null)
return;
pushMember(methodReturnType.Method as MemberReference);
pushMember(methodReturnType.ReturnType);
addParameterDefinition(methodReturnType.Parameter);
}
void addGenericParameter(GenericParameter param) {
if (param == null)
return;
addTypeReference(param);
pushMember(param.Owner as MemberReference);
access(() => addCustomAttributes(param.CustomAttributes));
addTypeReferences(param.Constraints);
}
void addTypeReference(TypeReference typeReference) {
if (typeReference == null)
return;
addMemberReference(typeReference);
addGenericParameters(typeReference.GenericParameters);
}
void addMethodDefinition(MethodDefinition methodDefinition) {
if (methodDefinition == null)
return;
addMethodReference(methodDefinition);
access(() => addCustomAttributes(methodDefinition.CustomAttributes));
addSecurityDeclarations(methodDefinition.SecurityDeclarations);
addMethodReferences(methodDefinition.Overrides);
addMethodBody(methodDefinition.Body);
}
void addSecurityDeclaration(SecurityDeclaration decl) {
if (decl == null)
return;
access(() => addSecurityAttributes(decl.SecurityAttributes));
}
void addSecurityAttribute(SecurityAttribute attr) {
if (attr == null)
return;
pushMember(attr.AttributeType);
addCustomAttributeNamedArguments(attr.Fields);
addCustomAttributeNamedArguments(attr.Properties);
}
void addMethodBody(MethodBody body) {
if (body == null)
return;
pushMember(body.Method);
addParameterDefinition(body.ThisParameter);
addExceptionHandlers(body.ExceptionHandlers);
addVariableDefinitions(body.Variables);
addScope(body.Scope);
addInstructions(body.Instructions);
}
void addExceptionHandler(ExceptionHandler handler) {
if (handler == null)
return;
pushMember(handler.CatchType);
}
void addVariableDefinition(VariableDefinition v) {
if (v == null)
return;
addVariableReference(v);
}
void addVariableReference(VariableReference v) {
if (v == null)
return;
pushMember(v.VariableType);
}
void addScope(Scope scope) {
if (scope == null)
return;
addVariableDefinitions(scope.Variables);
addScopes(scope.Scopes);
}
void addGenericInstanceMethod(GenericInstanceMethod genericInstanceMethod) {
if (genericInstanceMethod == null)
return;
addMethodSpecification(genericInstanceMethod);
addTypeReferences(genericInstanceMethod.GenericArguments);
}
void addMethodSpecification(MethodSpecification methodSpecification) {
if (methodSpecification == null)
return;
addMethodReference(methodSpecification);
pushMember(methodSpecification.ElementMethod);
}
void addPropertyReference(PropertyReference propertyReference) {
if (propertyReference == null)
return;
addMemberReference(propertyReference);
pushMember(propertyReference.PropertyType);
}
void addPropertyDefinition(PropertyDefinition propertyDefinition) {
if (propertyDefinition == null)
return;
addPropertyReference(propertyDefinition);
access(() => addCustomAttributes(propertyDefinition.CustomAttributes));
pushMember(propertyDefinition.GetMethod);
pushMember(propertyDefinition.SetMethod);
addMethodDefinitions(propertyDefinition.OtherMethods);
}
void addTypeDefinition(TypeDefinition typeDefinition) {
if (typeDefinition == null)
return;
addTypeReference(typeDefinition);
pushMember(typeDefinition.BaseType);
addTypeReferences(typeDefinition.Interfaces);
addTypeDefinitions(typeDefinition.NestedTypes);
addMethodDefinitions(typeDefinition.Methods);
addFieldDefinitions(typeDefinition.Fields);
addEventDefinitions(typeDefinition.Events);
addPropertyDefinitions(typeDefinition.Properties);
access(() => addCustomAttributes(typeDefinition.CustomAttributes));
addSecurityDeclarations(typeDefinition.SecurityDeclarations);
}
void addTypeSpecification(TypeSpecification ts) {
if (ts == null)
return;
addTypeReference(ts);
pushMember(ts.ElementType);
}
void addArrayType(ArrayType at) {
if (at == null)
return;
addTypeSpecification(at);
}
void addFunctionPointerType(FunctionPointerType fpt) {
if (fpt == null)
return;
addTypeSpecification(fpt);
// It's an anon MethodReference created by the class. Not useful to us.
//pushMember(fpt.function);
}
void addGenericInstanceType(GenericInstanceType git) {
if (git == null)
return;
addTypeSpecification(git);
addTypeReferences(git.GenericArguments);
}
void addOptionalModifierType(OptionalModifierType omt) {
if (omt == null)
return;
addTypeSpecification(omt);
pushMember(omt.ModifierType);
}
void addRequiredModifierType(RequiredModifierType rmt) {
if (rmt == null)
return;
addTypeSpecification(rmt);
pushMember(rmt.ModifierType);
}
void addPinnedType(PinnedType pt) {
if (pt == null)
return;
addTypeSpecification(pt);
}
void addPointerType(PointerType pt) {
if (pt == null)
return;
addTypeSpecification(pt);
}
void addByReferenceType(ByReferenceType brt) {
if (brt == null)
return;
addTypeSpecification(brt);
}
void addSentinelType(SentinelType st) {
if (st == null)
return;
addTypeSpecification(st);
}
void addCallSite(CallSite cs) {
pushMember(cs.signature);
}
void doEventDefinition(EventDefinition eventDefinition) {
bool present;
if (eventDefinitions.TryGetValue(eventDefinition, out present))
return;
eventDefinitions[eventDefinition] = true;
addEventDefinition(eventDefinition);
}
void doFieldReference(FieldReference fieldReference) {
bool present;
if (fieldReferences.TryGetValue(fieldReference, out present))
return;
fieldReferences[fieldReference] = true;
addFieldReference(fieldReference);
}
void doFieldDefinition(FieldDefinition fieldDefinition) {
bool present;
if (fieldDefinitions.TryGetValue(fieldDefinition, out present))
return;
fieldDefinitions[fieldDefinition] = true;
addFieldDefinition(fieldDefinition);
}
void doMethodReference(MethodReference methodReference) {
bool present;
if (methodReferences.TryGetValue(methodReference, out present))
return;
methodReferences[methodReference] = true;
addMethodReference(methodReference);
}
void doMethodDefinition(MethodDefinition methodDefinition) {
bool present;
if (methodDefinitions.TryGetValue(methodDefinition, out present))
return;
methodDefinitions[methodDefinition] = true;
addMethodDefinition(methodDefinition);
}
void doGenericInstanceMethod(GenericInstanceMethod genericInstanceMethod) {
bool present;
if (genericInstanceMethods.TryGetValue(genericInstanceMethod, out present))
return;
genericInstanceMethods[genericInstanceMethod] = true;
addGenericInstanceMethod(genericInstanceMethod);
}
void doPropertyDefinition(PropertyDefinition propertyDefinition) {
bool present;
if (propertyDefinitions.TryGetValue(propertyDefinition, out present))
return;
propertyDefinitions[propertyDefinition] = true;
addPropertyDefinition(propertyDefinition);
}
void doTypeReference(TypeReference typeReference) {
bool present;
if (typeReferences.TryGetValue(typeReference, out present))
return;
typeReferences[typeReference] = true;
addTypeReference(typeReference);
}
void doTypeDefinition(TypeDefinition typeDefinition) {
bool present;
if (typeDefinitions.TryGetValue(typeDefinition, out present))
return;
typeDefinitions[typeDefinition] = true;
addTypeDefinition(typeDefinition);
}
void doGenericParameter(GenericParameter genericParameter) {
bool present;
if (genericParameters.TryGetValue(genericParameter, out present))
return;
genericParameters[genericParameter] = true;
addGenericParameter(genericParameter);
}
void doArrayType(ArrayType arrayType) {
bool present;
if (arrayTypes.TryGetValue(arrayType, out present))
return;
arrayTypes[arrayType] = true;
addArrayType(arrayType);
}
void doFunctionPointerType(FunctionPointerType functionPointerType) {
bool present;
if (functionPointerTypes.TryGetValue(functionPointerType, out present))
return;
functionPointerTypes[functionPointerType] = true;
addFunctionPointerType(functionPointerType);
}
void doGenericInstanceType(GenericInstanceType genericInstanceType) {
bool present;
if (genericInstanceTypes.TryGetValue(genericInstanceType, out present))
return;
genericInstanceTypes[genericInstanceType] = true;
addGenericInstanceType(genericInstanceType);
}
void doOptionalModifierType(OptionalModifierType optionalModifierType) {
bool present;
if (optionalModifierTypes.TryGetValue(optionalModifierType, out present))
return;
optionalModifierTypes[optionalModifierType] = true;
addOptionalModifierType(optionalModifierType);
}
void doRequiredModifierType(RequiredModifierType requiredModifierType) {
bool present;
if (requiredModifierTypes.TryGetValue(requiredModifierType, out present))
return;
requiredModifierTypes[requiredModifierType] = true;
addRequiredModifierType(requiredModifierType);
}
void doPinnedType(PinnedType pinnedType) {
bool present;
if (pinnedTypes.TryGetValue(pinnedType, out present))
return;
pinnedTypes[pinnedType] = true;
addPinnedType(pinnedType);
}
void doPointerType(PointerType pointerType) {
bool present;
if (pointerTypes.TryGetValue(pointerType, out present))
return;
pointerTypes[pointerType] = true;
addPointerType(pointerType);
}
void doByReferenceType(ByReferenceType byReferenceType) {
bool present;
if (byReferenceTypes.TryGetValue(byReferenceType, out present))
return;
byReferenceTypes[byReferenceType] = true;
addByReferenceType(byReferenceType);
}
void doSentinelType(SentinelType sentinelType) {
bool present;
if (sentinelTypes.TryGetValue(sentinelType, out present))
return;
sentinelTypes[sentinelType] = true;
addSentinelType(sentinelType);
}
}
}