/* 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 dot10.DotNet.Emit; using dot10.DotNet.MD; namespace de4dot.blocks { public enum FrameworkType { Unknown, Desktop, Silverlight, // and WindowsPhone, XNA Xbox360 CompactFramework, XNA, Zune, } #if PORT class TypeCache { ModuleDefinition module; de4dot.blocks.OLD_REMOVE.TypeDefinitionDict typeRefToDef = new de4dot.blocks.OLD_REMOVE.TypeDefinitionDict(); public TypeCache(ModuleDefinition module) { this.module = module; init(); } void init() { foreach (var type in module.GetTypes()) typeRefToDef.add(type, type); } public TypeDefinition lookup(TypeReference typeReference) { return typeRefToDef.find(typeReference); } } #endif #if PORT public class TypeCaches { Dictionary typeCaches = new Dictionary(); // Should be called when the whole module is reloaded or when a lot of types have been // modified (eg. renamed) public void invalidate(ModuleDefinition module) { if (module == null) return; typeCaches.Remove(module); } // Call this to invalidate all modules public List invalidateAll() { var list = new List(typeCaches.Keys); typeCaches.Clear(); return list; } public TypeDefinition lookup(ModuleDefinition module, TypeReference typeReference) { TypeCache typeCache; if (!typeCaches.TryGetValue(module, out typeCache)) typeCaches[module] = typeCache = new TypeCache(module); return typeCache.lookup(typeReference); } } #endif #if PORT public class CallCounter { Dictionary calls = new Dictionary(); public void add(MethodReference calledMethod) { int count; var key = new de4dot.blocks.OLD_REMOVE.MethodReferenceAndDeclaringTypeKey(calledMethod); calls.TryGetValue(key, out count); calls[key] = count + 1; } public MethodReference most() { int numCalls; return most(out numCalls); } public MethodReference most(out int numCalls) { MethodReference method = null; int callCount = 0; foreach (var key in calls.Keys) { if (calls[key] > callCount) { callCount = calls[key]; method = key.MethodReference; } } numCalls = callCount; return method; } } #endif #if PORT public class MethodCalls { Dictionary methodCalls = new Dictionary(StringComparer.Ordinal); public void addMethodCalls(MethodDef method) { if (!method.HasBody) return; foreach (var instr in method.Body.Instructions) { var calledMethod = instr.Operand as MethodReference; if (calledMethod != null) add(calledMethod); } } public void add(MethodReference method) { string key = method.FullName; if (!methodCalls.ContainsKey(key)) methodCalls[key] = 0; methodCalls[key]++; } public int count(string methodFullName) { int count; methodCalls.TryGetValue(methodFullName, out count); return count; } public bool called(string methodFullName) { return count(methodFullName) != 0; } } #endif public static class DotNetUtils { #if PORT public static readonly TypeCaches typeCaches = new TypeCaches(); #endif public static TypeDef getModuleType(ModuleDef module) { return module.GlobalType; } public static MethodDef getModuleTypeCctor(ModuleDef module) { return module.GlobalType.FindClassConstructor(); } public static bool isEmpty(MethodDef method) { if (method.Body == null) return false; foreach (var instr in method.Body.Instructions) { var code = instr.OpCode.Code; if (code != Code.Nop && code != Code.Ret) return false; } return true; } public static bool isEmptyObfuscated(MethodDef method) { if (method.Body == null) return false; int index = 0; var instr = getInstruction(method.Body.Instructions, ref index); if (instr == null || instr.OpCode.Code != Code.Ret) return false; return true; } public static FieldDef findFieldType(TypeDef typeDefinition, string typeName, bool isStatic) { if (typeDefinition == null) return null; foreach (var field in typeDefinition.Fields) { if (field.IsStatic == isStatic && field.FieldSig.GetFieldType().GetFullName() == typeName) return field; } return null; } public static IEnumerable findMethods(IEnumerable methods, string returnType, string[] argsTypes) { return findMethods(methods, returnType, argsTypes, true); } public static IEnumerable findMethods(IEnumerable methods, string returnType, string[] argsTypes, bool isStatic) { foreach (var method in methods) { var sig = method.MethodSig; if (sig == null || !method.HasBody || !sig.IsDefault) continue; if (method.IsStatic != isStatic || sig.Params.Count != argsTypes.Length) continue; if (sig.GenParamCount > 0) continue; if (sig.RetType.GetFullName() != returnType) continue; for (int i = 0; i < argsTypes.Length; i++) { if (sig.Params[i].GetFullName() != argsTypes[i]) goto next; } yield return method; next: ; } } public static bool isDelegate(IType type) { if (type == null) return false; var fn = type.FullName; return fn == "System.Delegate" || fn == "System.MulticastDelegate"; } public static bool derivesFromDelegate(TypeDef type) { return type != null && isDelegate(type.BaseType); } #if PORT public static bool isSameAssembly(TypeReference type, string assembly) { return MemberReferenceHelper.getCanonicalizedScopeName(type.Scope) == assembly.ToLowerInvariant(); } public static bool isMethod(MethodReference method, string returnType, string parameters) { return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters; } #endif public static bool isMethod(IMethod method, string returnType, string parameters) { return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters; } public static string getDllName(string dll) { if (dll.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) return dll.Substring(0, dll.Length - 4); return dll; } public static bool hasPinvokeMethod(TypeDef type, string methodName) { return getPInvokeMethod(type, methodName) != null; } public static MethodDef getPInvokeMethod(TypeDef type, string methodName) { if (type == null) return null; var mname = new UTF8String(methodName); foreach (var method in type.Methods) { if (method.ImplMap == null) continue; if (UTF8String.Equals(method.ImplMap.Name, mname)) return method; } return null; } public static MethodDef getPInvokeMethod(TypeDef type, string dll, string funcName) { foreach (var method in type.Methods) { if (isPinvokeMethod(method, dll, funcName)) return method; } return null; } public static bool isPinvokeMethod(MethodDef method, string dll, string funcName) { if (method == null) return false; if (method.ImplMap == null || method.ImplMap.Name.String != funcName) return false; return getDllName(dll).Equals(getDllName(method.ImplMap.Scope.Name.String), StringComparison.OrdinalIgnoreCase); } #if PORT public static MethodDef getMethod(TypeDefinition type, string name) { if (type == null) return null; foreach (var method in type.Methods) { if (method.Name == name) return method; } return null; } public static MethodDef getMethod(TypeDefinition type, MethodReference methodReference) { if (type == null || methodReference == null) return null; if (methodReference is MethodDef) return (MethodDef)methodReference; foreach (var method in type.Methods) { if (MemberReferenceHelper.compareMethodReference(method, methodReference)) return method; } return null; } public static MethodDef getMethod(ModuleDefinition module, MethodReference method) { if (method == null) return null; return getMethod(module, method, method.DeclaringType); } #endif public static MethodDef getMethod2(ModuleDefMD module, IMethod method) { if (method == null) return null; if (method is MethodDef) return (MethodDef)method; var git = method.DeclaringType.ToGenericInstSig(); var dt = git == null ? method.DeclaringType : git.GenericType.TypeDefOrRef; return getMethod(module, method, dt); } static MethodDef getMethod(ModuleDefMD module, IMethod method, ITypeDefOrRef declaringType) { if (method == null) return null; if (method is MethodDef) return (MethodDef)method; return getMethod(getType(module, declaringType), method); } public static MethodDef getMethod(TypeDef type, string returnType, string parameters) { foreach (var method in type.Methods) { if (isMethod(method, returnType, parameters)) return method; } return null; } public static MethodDef getMethod2(ModuleDef module, IMethod method) { if (method == null) return null; return getMethod(module, method, method.DeclaringType.ScopeType); } public static TypeDef getType(ModuleDef module, TypeSig type) { type = type.RemovePinnedAndModifiers(); var tdr = type as TypeDefOrRefSig; if (tdr == null) return null; return getType(module, tdr.TypeDefOrRef); } public static TypeDef getType(ModuleDef module, ITypeDefOrRef type) { var td = type as TypeDef; if (td == null) { var tr = type as TypeRef; if (tr != null) { var trAsm = tr.DefinitionAssembly; var modAsm = module.Assembly; if (trAsm != null && modAsm != null && trAsm.Name == modAsm.Name) td = tr.Resolve(); } } return td != null && td.OwnerModule == module ? td : null; } static MethodDef getMethod(ModuleDef module, IMethod method, ITypeDefOrRef declaringType) { if (method == null) return null; if (method is MethodDef) return (MethodDef)method; return getMethod(getType(module, declaringType), method); } public static MethodDef getMethod(TypeDef type, IMethod methodRef) { if (type == null || methodRef == null) return null; if (methodRef is MethodDef) return (MethodDef)methodRef; return type.FindMethod(methodRef.Name, methodRef.MethodSig); } #if PORT public static IEnumerable getNormalMethods(TypeDefinition type) { foreach (var method in type.Methods) { if (method.HasPInvokeInfo) continue; if (method.Name == ".ctor" || method.Name == ".cctor") continue; yield return method; } } public static TypeDefinition getType(ModuleDefinition module, TypeReference typeReference) { if (typeReference == null) return null; if (typeReference is TypeDefinition) return (TypeDefinition)typeReference; return typeCaches.lookup(module, typeReference); } public static FieldDefinition getField(ModuleDefinition module, FieldReference field) { if (field == null) return null; if (field is FieldDefinition) return (FieldDefinition)field; return getField(getType(module, field.DeclaringType), field); } #endif public static FieldDef getField(TypeDef type, IField fieldReference) { if (type == null || fieldReference == null) return null; if (fieldReference is FieldDef) return (FieldDef)fieldReference; return type.FindField(fieldReference.Name, fieldReference.FieldSig); } public static FieldDef getField(TypeDef type, string typeFullName) { if (type == null) return null; foreach (var field in type.Fields) { if (field.FieldSig.GetFieldType().GetFullName() == typeFullName) return field; } return null; } #if PORT public static FieldDefinition getFieldByName(TypeDefinition type, string name) { if (type == null) return null; foreach (var field in type.Fields) { if (field.Name == name) return field; } return null; } public static IEnumerable getMethodCalls(MethodDef method) { var list = new List(); if (method.HasBody) { foreach (var instr in method.Body.Instructions) { var calledMethod = instr.Operand as MethodReference; if (calledMethod != null) list.Add(calledMethod); } } return list; } public static MethodCalls getMethodCallCounts(MethodDef method) { var methodCalls = new MethodCalls(); methodCalls.addMethodCalls(method); return methodCalls; } public static bool hasString(MethodDef method, string s) { if (method == null || method.Body == null) return false; foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Ldstr && (string)instr.Operand == s) return true; } return false; } public static IList getCodeStrings(MethodDef method) { var strings = new List(); if (method != null && method.Body != null) { foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Ldstr) strings.Add((string)instr.Operand); } } return strings; } #endif public static IList getCodeStrings(MethodDef method) { var strings = new List(); if (method != null && method.Body != null) { foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Ldstr) strings.Add((string)instr.Operand); } } return strings; } public static Resource getResource(ModuleDef module, string name) { return getResource(module, new List { name }); } public static Resource getResource(ModuleDef module, IEnumerable strings) { if (!module.HasResources) return null; var resources = module.Resources; foreach (var tmp in strings) { var resourceName = removeFromNullChar(tmp); if (resourceName == null) continue; var name = new UTF8String(resourceName); foreach (var resource in resources) { if (UTF8String.Equals(resource.Name, name)) return resource; } } return null; } static string removeFromNullChar(string s) { int index = s.IndexOf((char)0); if (index < 0) return s; return s.Substring(0, index); } #if PORT // Copies most things but not everything public static MethodDef clone(MethodDef method) { var newMethod = new MethodDef(method.Name, method.Attributes, method.MethodReturnType.ReturnType); newMethod.MetadataToken = method.MetadataToken; newMethod.Attributes = method.Attributes; newMethod.ImplAttributes = method.ImplAttributes; newMethod.HasThis = method.HasThis; newMethod.ExplicitThis = method.ExplicitThis; newMethod.CallingConvention = method.CallingConvention; newMethod.SemanticsAttributes = method.SemanticsAttributes; newMethod.DeclaringType = method.DeclaringType; foreach (var arg in method.Parameters) newMethod.Parameters.Add(new ParameterDefinition(arg.Name, arg.Attributes, arg.ParameterType)); foreach (var gp in method.GenericParameters) newMethod.GenericParameters.Add(new GenericParameter(gp.Name, newMethod) { Attributes = gp.Attributes }); copyBodyFromTo(method, newMethod); return newMethod; } #endif // Copies most things but not everything public static MethodDef clone(MethodDef method) { var newMethod = new MethodDefUser(method.Name, method.MethodSig, method.ImplFlags, method.Flags); newMethod.Rid = method.Rid; newMethod.DeclaringType2 = method.DeclaringType; foreach (var pd in method.ParamList) newMethod.ParamList.Add(new ParamDefUser(pd.Name, pd.Sequence, pd.Flags)); foreach (var gp in method.GenericParams) { var newGp = new GenericParamUser(gp.Number, gp.Flags, gp.Name); foreach (var gpc in newGp.GenericParamConstraints) newGp.GenericParamConstraints.Add(new GenericParamConstraintUser(gpc.Constraint)); newMethod.GenericParams.Add(newGp); } copyBodyFromTo(method, newMethod); return method; } #if PORT public static Instruction clone(Instruction instr) { return new Instruction { Offset = instr.Offset, OpCode = instr.OpCode, Operand = instr.Operand, SequencePoint = instr.SequencePoint, }; } public static void copyBody(MethodDef method, out IList instructions, out IList exceptionHandlers) { if (method == null || !method.HasBody) { instructions = new List(); exceptionHandlers = new List(); return; } var oldInstrs = method.Body.Instructions; var oldExHandlers = method.Body.ExceptionHandlers; instructions = new List(oldInstrs.Count); exceptionHandlers = new List(oldExHandlers.Count); var oldToIndex = Utils.createObjectToIndexDictionary(oldInstrs); foreach (var oldInstr in oldInstrs) instructions.Add(clone(oldInstr)); foreach (var newInstr in instructions) { var operand = newInstr.Operand; if (operand is Instruction) newInstr.Operand = instructions[oldToIndex[(Instruction)operand]]; else if (operand is Instruction[]) { var oldArray = (Instruction[])operand; var newArray = new Instruction[oldArray.Length]; for (int i = 0; i < oldArray.Length; i++) newArray[i] = instructions[oldToIndex[oldArray[i]]]; newInstr.Operand = newArray; } } foreach (var oldEx in oldExHandlers) { var newEx = new ExceptionHandler(oldEx.HandlerType) { TryStart = getInstruction(instructions, oldToIndex, oldEx.TryStart), TryEnd = getInstruction(instructions, oldToIndex, oldEx.TryEnd), FilterStart = getInstruction(instructions, oldToIndex, oldEx.FilterStart), HandlerStart= getInstruction(instructions, oldToIndex, oldEx.HandlerStart), HandlerEnd = getInstruction(instructions, oldToIndex, oldEx.HandlerEnd), CatchType = oldEx.CatchType, }; exceptionHandlers.Add(newEx); } } static Instruction getInstruction(IList instructions, IDictionary instructionToIndex, Instruction instruction) { if (instruction == null) return null; return instructions[instructionToIndex[instruction]]; } #endif public static void copyBody(MethodDef method, out IList instructions, out IList exceptionHandlers) { if (method == null || !method.HasBody) { instructions = new List(); exceptionHandlers = new List(); return; } var oldInstrs = method.Body.Instructions; var oldExHandlers = method.Body.ExceptionHandlers; instructions = new List(oldInstrs.Count); exceptionHandlers = new List(oldExHandlers.Count); var oldToIndex = Utils.createObjectToIndexDictionary(oldInstrs); foreach (var oldInstr in oldInstrs) instructions.Add(oldInstr.Clone()); foreach (var newInstr in instructions) { var operand = newInstr.Operand; if (operand is Instruction) newInstr.Operand = instructions[oldToIndex[(Instruction)operand]]; else if (operand is IList) { var oldArray = (IList)operand; var newArray = new Instruction[oldArray.Count]; for (int i = 0; i < oldArray.Count; i++) newArray[i] = instructions[oldToIndex[oldArray[i]]]; newInstr.Operand = newArray; } } foreach (var oldEx in oldExHandlers) { var newEx = new ExceptionHandler(oldEx.HandlerType) { TryStart = getInstruction(instructions, oldToIndex, oldEx.TryStart), TryEnd = getInstruction(instructions, oldToIndex, oldEx.TryEnd), FilterStart = getInstruction(instructions, oldToIndex, oldEx.FilterStart), HandlerStart = getInstruction(instructions, oldToIndex, oldEx.HandlerStart), HandlerEnd = getInstruction(instructions, oldToIndex, oldEx.HandlerEnd), CatchType = oldEx.CatchType, }; exceptionHandlers.Add(newEx); } } static Instruction getInstruction(IList instructions, IDictionary instructionToIndex, Instruction instruction) { if (instruction == null) return null; return instructions[instructionToIndex[instruction]]; } #if PORT public static void restoreBody(MethodDef method, IEnumerable instructions, IEnumerable exceptionHandlers) { if (method == null || !method.HasBody) return; var bodyInstrs = method.Body.Instructions; bodyInstrs.Clear(); foreach (var instr in instructions) bodyInstrs.Add(instr); var bodyExceptionHandlers = method.Body.ExceptionHandlers; bodyExceptionHandlers.Clear(); foreach (var eh in exceptionHandlers) bodyExceptionHandlers.Add(eh); } #endif public static void restoreBody(MethodDef method, IEnumerable instructions, IEnumerable exceptionHandlers) { if (method == null || method.Body == null) return; var bodyInstrs = method.Body.Instructions; bodyInstrs.Clear(); foreach (var instr in instructions) bodyInstrs.Add(instr); var bodyExceptionHandlers = method.Body.ExceptionHandlers; bodyExceptionHandlers.Clear(); foreach (var eh in exceptionHandlers) bodyExceptionHandlers.Add(eh); } public static void copyBodyFromTo(MethodDef fromMethod, MethodDef toMethod) { if (fromMethod == toMethod) return; IList instructions; IList exceptionHandlers; copyBody(fromMethod, out instructions, out exceptionHandlers); restoreBody(toMethod, instructions, exceptionHandlers); copyLocalsFromTo(fromMethod, toMethod); updateInstructionOperands(fromMethod, toMethod); } static void copyLocalsFromTo(MethodDef fromMethod, MethodDef toMethod) { var fromBody = fromMethod.Body; var toBody = toMethod.Body; toBody.LocalList.Clear(); foreach (var local in fromBody.LocalList) toBody.LocalList.Add(new Local(local.Type)); } static void updateInstructionOperands(MethodDef fromMethod, MethodDef toMethod) { var fromBody = fromMethod.Body; var toBody = toMethod.Body; toBody.InitLocals = fromBody.InitLocals; toBody.MaxStack = fromBody.MaxStack; var newOperands = new Dictionary(); var fromParams = fromMethod.Parameters; var toParams = toMethod.Parameters; for (int i = 0; i < fromParams.Count; i++) newOperands[fromParams[i]] = toParams[i]; for (int i = 0; i < fromBody.LocalList.Count; i++) newOperands[fromBody.LocalList[i]] = toBody.LocalList[i]; foreach (var instr in toBody.Instructions) { if (instr.Operand == null) continue; object newOperand; if (newOperands.TryGetValue(instr.Operand, out newOperand)) instr.Operand = newOperand; } } #if PORT public static IEnumerable findAttributes(ICustomAttributeProvider custAttrProvider, TypeReference attr) { var list = new List(); if (custAttrProvider == null) return list; foreach (var cattr in custAttrProvider.CustomAttributes) { if (MemberReferenceHelper.compareTypes(attr, cattr.AttributeType)) list.Add(cattr); } return list; } #endif public static string getCustomArgAsString(CustomAttribute cattr, int arg) { if (cattr == null || arg >= cattr.Arguments.Count) return null; var carg = cattr.Arguments[arg]; if (carg.Type.GetElementType() != ElementType.String) return null; return UTF8String.ToSystemStringOrEmpty((UTF8String)carg.Value); } public static IEnumerable getCalledMethods(ModuleDef module, MethodDef method) { if (method != null && method.HasBody) { foreach (var call in method.Body.Instructions) { if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; var methodRef = call.Operand as IMethod; if (methodRef == null) continue; var type = getType(module, methodRef.DeclaringType); var methodDef = getMethod(type, methodRef); if (methodDef != null) yield return methodDef; } } } public static IList getInstructions(IList instructions, int i, params OpCode[] opcodes) { if (i + opcodes.Length > instructions.Count) return null; if (opcodes.Length == 0) return new List(); if (opcodes[0] != instructions[i].OpCode) return null; var list = new List(opcodes.Length); for (int j = 0; j < opcodes.Length; j++) { var instr = instructions[i + j]; if (instr.OpCode != opcodes[j]) return null; list.Add(instr); } return list; } #if PORT public static bool hasReturnValue(IMethodSignature method) { var type = method.MethodReturnType.ReturnType; while (type.IsOptionalModifier || type.IsRequiredModifier) type = ((TypeSpecification)type).ElementType; return type.EType != ElementType.Void; } #endif public static bool hasReturnValue(IMethod method) { if (method == null || method.MethodSig == null || method.MethodSig.RetType == null) return false; return method.MethodSig.RetType.RemovePinnedAndModifiers().ElementType != ElementType.Void; } #if PORT public static void updateStack(Instruction instr, ref int stack, bool methodHasReturnValue) { int pushes, pops; calculateStackUsage(instr, methodHasReturnValue, out pushes, out pops); if (pops == -1) stack = 0; else stack += pushes - pops; } // Sets pops to -1 if the stack is supposed to be cleared public static void calculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) { if (instr.OpCode.FlowControl == FlowControl.Call) calculateStackUsage_call(instr, out pushes, out pops); else calculateStackUsage_nonCall(instr, methodHasReturnValue, out pushes, out pops); } static void calculateStackUsage_call(Instruction instr, out int pushes, out int pops) { pushes = 0; pops = 0; var method = (IMethodSignature)instr.Operand; bool implicitThis = method.HasThis && !method.ExplicitThis; if (hasReturnValue(method) || (instr.OpCode.Code == Code.Newobj && method.HasThis)) pushes++; if (method.HasParameters) pops += method.Parameters.Count; if (implicitThis && instr.OpCode.Code != Code.Newobj) pops++; if (instr.OpCode.Code == Code.Calli) pops++; } // Sets pops to -1 if the stack is supposed to be cleared static void calculateStackUsage_nonCall(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) { StackBehaviour stackBehavior; pushes = 0; pops = 0; stackBehavior = instr.OpCode.StackBehaviourPush; switch (stackBehavior) { case StackBehaviour.Push0: break; case StackBehaviour.Push1: case StackBehaviour.Pushi: case StackBehaviour.Pushi8: case StackBehaviour.Pushr4: case StackBehaviour.Pushr8: case StackBehaviour.Pushref: pushes++; break; case StackBehaviour.Push1_push1: pushes += 2; break; case StackBehaviour.Varpush: // only call, calli, callvirt which are handled elsewhere default: throw new ApplicationException(string.Format("Unknown push StackBehavior {0}", stackBehavior)); } stackBehavior = instr.OpCode.StackBehaviourPop; switch (stackBehavior) { case StackBehaviour.Pop0: break; case StackBehaviour.Pop1: case StackBehaviour.Popi: case StackBehaviour.Popref: pops++; break; case StackBehaviour.Pop1_pop1: case StackBehaviour.Popi_pop1: case StackBehaviour.Popi_popi: case StackBehaviour.Popi_popi8: case StackBehaviour.Popi_popr4: case StackBehaviour.Popi_popr8: case StackBehaviour.Popref_pop1: case StackBehaviour.Popref_popi: pops += 2; break; case StackBehaviour.Popi_popi_popi: case StackBehaviour.Popref_popi_popi: case StackBehaviour.Popref_popi_popi8: case StackBehaviour.Popref_popi_popr4: case StackBehaviour.Popref_popi_popr8: case StackBehaviour.Popref_popi_popref: pops += 3; break; case StackBehaviour.PopAll: pops = -1; break; case StackBehaviour.Varpop: // call, calli, callvirt, newobj (all handled elsewhere), and ret if (methodHasReturnValue) pops++; break; default: throw new ApplicationException(string.Format("Unknown pop StackBehavior {0}", stackBehavior)); } } public static AssemblyNameReference getAssemblyNameReference(TypeReference type) { var scope = type.Scope; if (scope == null) return null; if (scope is ModuleDefinition) { var moduleDefinition = (ModuleDefinition)scope; return moduleDefinition.Assembly.Name; } if (scope is AssemblyNameReference) return (AssemblyNameReference)scope; if (scope is ModuleReference && type.Module.Assembly != null) { foreach (var module in type.Module.Assembly.Modules) { if (scope.Name == module.Name) return type.Module.Assembly.Name; } } throw new ApplicationException(string.Format("Unknown IMetadataScope type: {0}", scope.GetType())); } public static string getFullAssemblyName(TypeReference type) { var asmRef = getAssemblyNameReference(type); return asmRef == null ? null : asmRef.FullName; } public static bool isAssembly(IMetadataScope scope, string assemblySimpleName) { return scope.Name == assemblySimpleName || scope.Name.StartsWith(assemblySimpleName + ",", StringComparison.Ordinal); } public static bool isReferenceToModule(ModuleReference moduleReference, IMetadataScope scope) { switch (scope.MetadataScopeType) { case MetadataScopeType.AssemblyNameReference: var asmRef = (AssemblyNameReference)scope; var module = moduleReference as ModuleDefinition; return module != null && module.Assembly != null && module.Assembly.Name.FullName == asmRef.FullName; case MetadataScopeType.ModuleDefinition: return moduleReference == scope; case MetadataScopeType.ModuleReference: return moduleReference.Name == ((ModuleReference)scope).Name; default: throw new ApplicationException("Unknown MetadataScopeType"); } } public static int getArgIndex(Instruction instr) { switch (instr.OpCode.Code) { case Code.Ldarg_0: return 0; case Code.Ldarg_1: return 1; case Code.Ldarg_2: return 2; case Code.Ldarg_3: return 3; case Code.Ldarga: case Code.Ldarga_S: case Code.Ldarg: case Code.Ldarg_S: return getArgIndex(instr.Operand as ParameterDefinition); } return -1; } public static int getArgIndex(ParameterDefinition arg) { if (arg == null) return -1; return arg.Sequence; } public static List getParameters(MethodReference method) { var args = new List(method.Parameters.Count + 1); if (method.HasImplicitThis) { var methodDef = method as MethodDef; if (methodDef != null && methodDef.Body != null) args.Add(methodDef.Body.ThisParameter); else args.Add(new ParameterDefinition(method.DeclaringType, method)); } foreach (var arg in method.Parameters) args.Add(arg); return args; } public static ParameterDefinition getParameter(MethodReference method, Instruction instr) { return getParameter(getParameters(method), instr); } public static ParameterDefinition getParameter(IList parameters, Instruction instr) { return getParameter(parameters, getArgIndex(instr)); } public static ParameterDefinition getParameter(IList parameters, int index) { if (0 <= index && index < parameters.Count) return parameters[index]; return null; } #endif public static Parameter getParameter(IList parameters, int index) { if (0 <= index && index < parameters.Count) return parameters[index]; return null; } public static TypeSig getArg(IList args, int index) { if (0 <= index && index < args.Count) return args[index]; return null; } #if PORT public static List getArgs(MethodReference method) { var args = new List(method.Parameters.Count + 1); if (method.HasImplicitThis) args.Add(method.DeclaringType); foreach (var arg in method.Parameters) args.Add(arg.ParameterType); return args; } #endif public static List getArgs(IMethod method) { var sig = method.MethodSig; var args = new List(sig.Params.Count + 1); if (sig.ImplicitThis) args.Add(method.DeclaringType.ToTypeSig()); foreach (var arg in sig.Params) args.Add(arg); return args; } #if PORT public static TypeReference getArgType(MethodReference method, Instruction instr) { return getArgType(getArgs(method), instr); } public static TypeReference getArgType(IList methodArgs, Instruction instr) { return getArgType(methodArgs, getArgIndex(instr)); } public static TypeReference getArgType(IList methodArgs, int index) { if (0 <= index && index < methodArgs.Count) return methodArgs[index]; return null; } public static int getArgsCount(MethodReference method) { int count = method.Parameters.Count; if (method.HasImplicitThis) count++; return count; } #endif public static int getArgsCount(IMethod method) { var sig = method.MethodSig; if (sig == null) return 0; int count = sig.Params.Count; if (sig.ImplicitThis) count++; return count; } #if PORT // Doesn't fix everything (eg. T[] aren't replaced with eg. int[], but T -> int will be fixed) public static IList replaceGenericParameters(GenericInstanceType typeOwner, GenericInstanceMethod methodOwner, IList types) { //TODO: You should use MemberRefInstance.cs for (int i = 0; i < types.Count; i++) types[i] = getGenericArgument(typeOwner, methodOwner, types[i]); return types; } public static TypeReference getGenericArgument(GenericInstanceType typeOwner, GenericInstanceMethod methodOwner, TypeReference type) { var gp = type as GenericParameter; if (gp == null) return type; if (typeOwner != null && MemberReferenceHelper.compareTypes(typeOwner.ElementType, gp.Owner as TypeReference)) return typeOwner.GenericArguments[gp.Position]; if (methodOwner != null && MemberReferenceHelper.compareMethodReferenceAndDeclaringType(methodOwner.ElementMethod, gp.Owner as MethodReference)) return methodOwner.GenericArguments[gp.Position]; return type; } public static Instruction getInstruction(IList instructions, ref int index) { for (int i = 0; i < 10; i++) { if (index < 0 || index >= instructions.Count) return null; var instr = instructions[index++]; if (instr.OpCode.Code == Code.Nop) continue; if (instr.OpCode.OpCodeType == OpCodeType.Prefix) continue; if (instr == null || (instr.OpCode.Code != Code.Br && instr.OpCode.Code != Code.Br_S)) return instr; instr = instr.Operand as Instruction; if (instr == null) return null; index = instructions.IndexOf(instr); } return null; } #endif public static Instruction getInstruction(IList instructions, ref int index) { for (int i = 0; i < 10; i++) { if (index < 0 || index >= instructions.Count) return null; var instr = instructions[index++]; if (instr.OpCode.Code == Code.Nop) continue; if (instr.OpCode.OpCodeType == OpCodeType.Prefix) continue; if (instr == null || (instr.OpCode.Code != Code.Br && instr.OpCode.Code != Code.Br_S)) return instr; instr = instr.Operand as Instruction; if (instr == null) return null; index = instructions.IndexOf(instr); } return null; } #if PORT public static PropertyDefinition createPropertyDefinition(string name, TypeReference propType, MethodDef getter, MethodDef setter) { return new PropertyDefinition(name, PropertyAttributes.None, propType) { MetadataToken = nextPropertyToken(), GetMethod = getter, SetMethod = setter, }; } public static EventDefinition createEventDefinition(string name, TypeReference eventType) { return new EventDefinition(name, EventAttributes.None, eventType) { MetadataToken = nextEventToken(), }; } public static FieldDefinition createFieldDefinition(string name, FieldAttributes attributes, TypeReference fieldType) { return new FieldDefinition(name, attributes, fieldType) { MetadataToken = nextFieldToken(), }; } static int nextTokenRid = 0x00FFFFFF; public static MetadataToken nextTypeRefToken() { return new MetadataToken(TokenType.TypeRef, nextTokenRid--); } public static MetadataToken nextTypeDefToken() { return new MetadataToken(TokenType.TypeDef, nextTokenRid--); } public static MetadataToken nextFieldToken() { return new MetadataToken(TokenType.Field, nextTokenRid--); } public static MetadataToken nextMethodToken() { return new MetadataToken(TokenType.Method, nextTokenRid--); } public static MetadataToken nextPropertyToken() { return new MetadataToken(TokenType.Property, nextTokenRid--); } public static MetadataToken nextEventToken() { return new MetadataToken(TokenType.Event, nextTokenRid--); } public static TypeReference findTypeReference(ModuleDefinition module, string asmSimpleName, string fullName) { foreach (var type in module.GetTypeReferences()) { if (type.FullName != fullName) continue; var asmRef = type.Scope as AssemblyNameReference; if (asmRef == null || asmRef.Name != asmSimpleName) continue; return type; } return null; } public static TypeReference findOrCreateTypeReference(ModuleDefinition module, AssemblyNameReference asmRef, string ns, string name, bool isValueType) { var typeRef = findTypeReference(module, asmRef.Name, ns + "." + name); if (typeRef != null) return typeRef; typeRef = new TypeReference(ns, name, module, asmRef); typeRef.MetadataToken = nextTypeRefToken(); typeRef.IsValueType = isValueType; return typeRef; } #endif public static TypeDefOrRefSig findOrCreateTypeReference(ModuleDef module, AssemblyRef asmRef, string ns, string name, bool isValueType) { var typeRef = module.UpdateRowId(new TypeRefUser(module, ns, name, asmRef)); if (isValueType) return new ValueTypeSig(typeRef); else return new ClassSig(typeRef); } public static FrameworkType getFrameworkType(ModuleDefMD module) { foreach (var modRef in module.GetAssemblyRefs()) { if (modRef.Name != "mscorlib") continue; if (PublicKeyBase.IsNullOrEmpty2(modRef.PublicKeyOrToken)) continue; switch (BitConverter.ToString(modRef.PublicKeyOrToken.Data).Replace("-", "").ToLowerInvariant()) { case "b77a5c561934e089": return FrameworkType.Desktop; case "7cec85d7bea7798e": return FrameworkType.Silverlight; case "969db8053d3322ac": return FrameworkType.CompactFramework; case "1c9e259686f921e0": return FrameworkType.XNA; case "e92a8b81eba7ceb7": return FrameworkType.Zune; } } return FrameworkType.Unknown; } public static int getMethodCalls(MethodDef method, string methodFullName) { if (method == null || method.Body == null) return 0; int count = 0; foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj) continue; var calledMethod = instr.Operand as IMethod; if (calledMethod == null) continue; if (calledMethod.FullName == methodFullName) count++; } return count; } public static bool callsMethod(MethodDef method, string methodFullName) { if (method == null || method.Body == null) return false; foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj) continue; var calledMethod = instr.Operand as IMethod; if (calledMethod == null) continue; if (calledMethod.FullName == methodFullName) return true; } return false; } public static bool callsMethod(MethodDef method, string returnType, string parameters) { if (method == null || method.Body == null) return false; foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj) continue; if (isMethod(instr.Operand as IMethod, returnType, parameters)) return true; } return false; } #if PORT public static IList getArgPushes(IList instrs, int index) { return getArgPushes(instrs, ref index); } public static IList getArgPushes(IList instrs, ref int index) { if (index < 0 || index >= instrs.Count) return null; var startInstr = instrs[index]; int pushes, pops; calculateStackUsage(startInstr, false, out pushes, out pops); index--; int numArgs = pops; var args = new List(numArgs); int stackSize = numArgs; while (index >= 0 && args.Count != numArgs) { var instr = instrs[index--]; calculateStackUsage(instr, false, out pushes, out pops); if (instr.OpCode.Code == Code.Dup) { args.Add(instr); stackSize--; } else { if (pushes == 1) args.Add(instr); else if (pushes > 1) throw new NotImplementedException(); stackSize -= pushes; if (pops != 0) { index++; if (getArgPushes(instrs, ref index) == null) return null; } } if (stackSize < 0) return null; } if (args.Count != numArgs) return null; args.Reverse(); return args; } public static AssemblyNameReference addAssemblyReference(ModuleDefinition module, AssemblyNameReference asmRef) { foreach (var modAsmRef in module.AssemblyReferences) { if (modAsmRef.FullName == asmRef.FullName) return modAsmRef; } var newAsmRef = AssemblyNameReference.Parse(asmRef.FullName); module.AssemblyReferences.Add(newAsmRef); return newAsmRef; } public static ModuleReference addModuleReference(ModuleDefinition module, ModuleReference modRef) { foreach (var modModRef in module.ModuleReferences) { if (modModRef.Name == modRef.Name) return modModRef; } var newModRef = new ModuleReference(modRef.Name); module.ModuleReferences.Add(newModRef); return newModRef; } #endif } }