diff --git a/de4dot.code/FilesDeobfuscator.cs b/de4dot.code/FilesDeobfuscator.cs index 5407318c..b159c611 100644 --- a/de4dot.code/FilesDeobfuscator.cs +++ b/de4dot.code/FilesDeobfuscator.cs @@ -22,7 +22,7 @@ using System.IO; using System.Collections.Generic; using Mono.Cecil; using de4dot.blocks; -using de4dot.old_renamer; +using de4dot.renamer; using de4dot.deobfuscators; using de4dot.AssemblyClient; @@ -91,7 +91,7 @@ namespace de4dot { file.deobfuscateEnd(); if (options.RenameSymbols) - new DefinitionsRenamer(new List { file }).renameAll(); + new Renamer(new List { file }).rename(); file.save(); @@ -339,7 +339,7 @@ namespace de4dot { void renameAllFiles(IEnumerable allFiles) { if (!options.RenameSymbols) return; - new DefinitionsRenamer(allFiles).renameAll(); + new Renamer(allFiles).rename(); } void saveAllFiles(IEnumerable allFiles) { diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index a723c03c..d46a2032 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -153,6 +153,19 @@ + + + + + + + + + + + + + diff --git a/de4dot.code/old_renamer/MemberRefFinder.cs b/de4dot.code/old_renamer/MemberRefFinder.cs index bfc32574..a77ace02 100644 --- a/de4dot.code/old_renamer/MemberRefFinder.cs +++ b/de4dot.code/old_renamer/MemberRefFinder.cs @@ -23,7 +23,7 @@ using Mono.Cecil; using Mono.Cecil.Cil; using de4dot.blocks; -namespace de4dot { +namespace de4dot.old_renamer { // If it's a non-generic memberref, you could use GetMemberReference() to get a cached // instance. For non-generics though, there's no other way than to scan every single // type and all its fields, recursively, to find all of those refererences... That's diff --git a/de4dot.code/renamer/Renamer.cs b/de4dot.code/renamer/Renamer.cs new file mode 100644 index 00000000..3b2db69a --- /dev/null +++ b/de4dot.code/renamer/Renamer.cs @@ -0,0 +1,45 @@ +/* + 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.Collections.Generic; +using de4dot.renamer.asmmodules; + +namespace de4dot.renamer { + class Renamer { + bool renameSymbols = true; + bool renameFields = true; + bool renameProperties = true; + bool renameEvents = true; + bool renameMethods = true; + Modules modules = new Modules(); + + public Renamer(IEnumerable files) { + foreach (var file in files) + modules.add(new Module(file)); + } + + public void rename() { + if (modules.Empty) + return; + Log.n("Renaming all obfuscated symbols"); + + modules.initialize(); + } + } +} diff --git a/de4dot.code/renamer/asmmodules/EventDef.cs b/de4dot.code/renamer/asmmodules/EventDef.cs new file mode 100644 index 00000000..002b7058 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/EventDef.cs @@ -0,0 +1,46 @@ +/* + 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.Collections.Generic; +using Mono.Cecil; + +namespace de4dot.renamer.asmmodules { + class EventDef : Ref { + public EventDefinition EventDefinition { + get { return (EventDefinition)memberReference; } + } + + public EventDef(EventDefinition eventDefinition, TypeDef owner, int index) + : base(eventDefinition, owner, index) { + } + + public IEnumerable methodDefinitions() { + if (EventDefinition.AddMethod != null) + yield return EventDefinition.AddMethod; + if (EventDefinition.RemoveMethod != null) + yield return EventDefinition.RemoveMethod; + if (EventDefinition.InvokeMethod != null) + yield return EventDefinition.InvokeMethod; + if (EventDefinition.OtherMethods != null) { + foreach (var m in EventDefinition.OtherMethods) + yield return m; + } + } + } +} diff --git a/de4dot.code/renamer/asmmodules/ExternalAssemblies.cs b/de4dot.code/renamer/asmmodules/ExternalAssemblies.cs new file mode 100644 index 00000000..0a8b75da --- /dev/null +++ b/de4dot.code/renamer/asmmodules/ExternalAssemblies.cs @@ -0,0 +1,104 @@ +/* + 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.Collections.Generic; +using Mono.Cecil; +using de4dot.blocks; + +namespace de4dot.renamer.asmmodules { + class ExternalAssembly { + AssemblyDefinition asmDef; + + public ExternalAssembly(AssemblyDefinition asmDef) { + this.asmDef = asmDef; + } + + public TypeDefinition resolve(TypeReference type) { + foreach (var module in asmDef.Modules) { + var typeDef = DotNetUtils.getType(module, type); + if (typeDef != null) + return typeDef; + } + + return null; + } + + public void unload() { + foreach (var module in asmDef.Modules) + DotNetUtils.typeCaches.invalidate(module); + } + } + + // Loads assemblies that aren't renamed + class ExternalAssemblies { + Dictionary assemblies = new Dictionary(); + + ExternalAssembly load(TypeReference type) { + var asmFullName = DotNetUtils.getFullAssemblyName(type.Scope); + ExternalAssembly asm; + if (assemblies.TryGetValue(asmFullName, out asm)) + return asm; + + AssemblyDefinition asmDef = null; + try { + asmDef = GlobalAssemblyResolver.Instance.Resolve(asmFullName); + } + catch (ResolutionException) { + } + catch (AssemblyResolutionException) { + } + if (asmDef == null) { + // If we can't load it now, we can't load it later. Make sure above code returns null. + assemblies[asmFullName] = null; + Log.w("Could not load assembly {0}", asmFullName); + return null; + } + if (assemblies.ContainsKey(asmDef.Name.FullName)) { + assemblies[asmFullName] = assemblies[asmDef.Name.FullName]; + return assemblies[asmDef.Name.FullName]; + } + + if (asmFullName == asmDef.Name.FullName) + Log.v("Loaded assembly {0}", asmFullName); + else + Log.v("Loaded assembly {0} (but wanted {1})", asmDef.Name.FullName, asmFullName); + + asm = new ExternalAssembly(asmDef); + assemblies[asmFullName] = asm; + assemblies[asmDef.Name.FullName] = asm; + return asm; + } + + public TypeDefinition resolve(TypeReference type) { + var asm = load(type); + if (asm == null) + return null; + return asm.resolve(type); + } + + public void unloadAll() { + foreach (var asm in assemblies.Values) { + if (asm == null) + continue; + asm.unload(); + } + assemblies.Clear(); + } + } +} diff --git a/de4dot.code/renamer/asmmodules/FieldDef.cs b/de4dot.code/renamer/asmmodules/FieldDef.cs new file mode 100644 index 00000000..9c1798c4 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/FieldDef.cs @@ -0,0 +1,32 @@ +/* + 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 Mono.Cecil; + +namespace de4dot.renamer.asmmodules { + class FieldDef : Ref { + public FieldDefinition FieldDefinition { + get { return (FieldDefinition)memberReference; } + } + + public FieldDef(FieldDefinition fieldDefinition, TypeDef owner, int index) + : base(fieldDefinition, owner, index) { + } + } +} diff --git a/de4dot.code/renamer/asmmodules/IResolver.cs b/de4dot.code/renamer/asmmodules/IResolver.cs new file mode 100644 index 00000000..8276e1d8 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/IResolver.cs @@ -0,0 +1,28 @@ +/* + 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 Mono.Cecil; + +namespace de4dot.renamer.asmmodules { + interface IResolver { + TypeDef resolve(TypeReference typeReference); + MethodDef resolve(MethodReference methodReference); + FieldDef resolve(FieldReference fieldReference); + } +} diff --git a/de4dot.code/renamer/asmmodules/MemberRefFinder.cs b/de4dot.code/renamer/asmmodules/MemberRefFinder.cs new file mode 100644 index 00000000..102f3b84 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/MemberRefFinder.cs @@ -0,0 +1,703 @@ +/* + 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.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); + } + } +} diff --git a/de4dot.code/renamer/asmmodules/MethodDef.cs b/de4dot.code/renamer/asmmodules/MethodDef.cs new file mode 100644 index 00000000..0a777ca9 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/MethodDef.cs @@ -0,0 +1,32 @@ +/* + 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 Mono.Cecil; + +namespace de4dot.renamer.asmmodules { + class MethodDef : Ref { + public MethodDefinition MethodDefinition { + get { return (MethodDefinition)memberReference; } + } + + public MethodDef(MethodDefinition methodDefinition, TypeDef owner, int index) + : base(methodDefinition, owner, index) { + } + } +} diff --git a/de4dot.code/renamer/asmmodules/Module.cs b/de4dot.code/renamer/asmmodules/Module.cs new file mode 100644 index 00000000..9f3580af --- /dev/null +++ b/de4dot.code/renamer/asmmodules/Module.cs @@ -0,0 +1,137 @@ +/* + 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 de4dot.blocks; + +namespace de4dot.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>(); + + 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 string Filename { + get { return obfuscatedFile.Filename; } + } + + public ModuleDefinition ModuleDefinition { + get { return obfuscatedFile.ModuleDefinition; } + } + + public Module(IObfuscatedFile obfuscatedFile) { + this.obfuscatedFile = obfuscatedFile; + } + + public IEnumerable getAllTypes() { + return types.getAll(); + } + + public void findAllMemberReferences(ref int typeIndex) { + memberRefFinder = new MemberRefFinder(); + memberRefFinder.findAll(ModuleDefinition, ModuleDefinition.Types); + + var allTypesList = new List(); + foreach (var type in memberRefFinder.typeDefinitions.Keys) { + var typeDef = new TypeDef(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].TypeDefinition] = i; + foreach (var typeDef in allTypesList) { + if (typeDef.TypeDefinition.NestedTypes == null) + continue; + foreach (var nestedTypeDefinition in typeDef.TypeDefinition.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.resolve(typeRef); + if (typeDef != null) + typeRefsToRename.Add(new RefToDef(typeRef, typeDef.TypeDefinition)); + } + + foreach (var methodRef in memberRefFinder.methodReferences.Keys) { + var methodDef = resolver.resolve(methodRef); + if (methodDef != null) + methodRefsToRename.Add(new RefToDef(methodRef, methodDef.MethodDefinition)); + } + + foreach (var fieldRef in memberRefFinder.fieldReferences.Keys) { + var fieldDef = resolver.resolve(fieldRef); + if (fieldDef != null) + fieldRefsToRename.Add(new RefToDef(fieldRef, fieldDef.FieldDefinition)); + } + } + + static TypeReference getNonGenericTypeReference(TypeReference typeReference) { + if (typeReference == null) + return null; + if (!typeReference.IsGenericInstance) + return typeReference; + var type = (GenericInstanceType)typeReference; + return type.ElementType; + } + + public TypeDef resolve(TypeReference typeReference) { + return this.types.find(getNonGenericTypeReference(typeReference)); + } + + public MethodDef resolve(MethodReference methodReference) { + var typeDef = this.types.find(getNonGenericTypeReference(methodReference.DeclaringType)); + if (typeDef == null) + return null; + return typeDef.find(methodReference); + } + + public FieldDef resolve(FieldReference fieldReference) { + var typeDef = this.types.find(getNonGenericTypeReference(fieldReference.DeclaringType)); + if (typeDef == null) + return null; + return typeDef.find(fieldReference); + } + } +} diff --git a/de4dot.code/renamer/asmmodules/Modules.cs b/de4dot.code/renamer/asmmodules/Modules.cs new file mode 100644 index 00000000..64e65c5c --- /dev/null +++ b/de4dot.code/renamer/asmmodules/Modules.cs @@ -0,0 +1,349 @@ +/* + 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 de4dot.blocks; + +namespace de4dot.renamer.asmmodules { + class Modules : IResolver { + bool initializeCalled = false; + List modules = new List(); + Dictionary modulesDict = new Dictionary(); + AssemblyHash assemblyHash = new AssemblyHash(); + + List allTypes = new List(); //TODO: Do we need this? + List baseTypes = new List(); //TODO: Do we need this? + List nonNestedTypes; //TODO: Do we need this? + + class AssemblyHash { + IDictionary assemblyHash = new Dictionary(StringComparer.Ordinal); + + public void add(Module module) { + ModuleHash moduleHash; + var key = getModuleKey(module); + if (!assemblyHash.TryGetValue(key, out moduleHash)) + assemblyHash[key] = moduleHash = new ModuleHash(); + moduleHash.add(module); + } + + string getModuleKey(Module module) { + if (module.ModuleDefinition.Assembly != null) + return module.ModuleDefinition.Assembly.ToString(); + return Utils.getBaseName(module.ModuleDefinition.FullyQualifiedName); + } + + public ModuleHash lookup(string assemblyName) { + ModuleHash moduleHash; + if (assemblyHash.TryGetValue(assemblyName, out moduleHash)) + return moduleHash; + return null; + } + } + + class ModuleHash { + ModulesDict modulesDict = new ModulesDict(); + Module mainModule = null; + + public void add(Module module) { + var asm = module.ModuleDefinition.Assembly; + if (asm != null && ReferenceEquals(asm.MainModule, module.ModuleDefinition)) { + if (mainModule != null) { + throw new UserException(string.Format( + "Two modules in the same assembly are main modules.\n" + + "Is one 32-bit and the other 64-bit?\n" + + " Module1: \"{0}\"" + + " Module2: \"{1}\"", + module.ModuleDefinition.FullyQualifiedName, + mainModule.ModuleDefinition.FullyQualifiedName)); + } + mainModule = module; + } + + modulesDict.add(module); + } + + public Module lookup(string moduleName) { + return modulesDict.lookup(moduleName); + } + + public IEnumerable Modules { + get { return modulesDict.Modules; } + } + } + + class ModulesDict { + IDictionary modulesDict = new Dictionary(StringComparer.Ordinal); + + public void add(Module module) { + var moduleName = module.ModuleDefinition.Name; + if (lookup(moduleName) != null) + throw new ApplicationException(string.Format("Module \"{0}\" was found twice", moduleName)); + modulesDict[moduleName] = module; + } + + public Module lookup(string moduleName) { + Module module; + if (modulesDict.TryGetValue(moduleName, out module)) + return module; + return null; + } + + public IEnumerable Modules { + get { return modulesDict.Values; } + } + } + + public bool Empty { + get { return modules.Count == 0; } + } + + public void add(Module module) { + if (initializeCalled) + throw new ApplicationException("initialize() has been called"); + Module otherModule; + if (modulesDict.TryGetValue(module.ModuleDefinition, out otherModule)) + return; + modulesDict[module.ModuleDefinition] = module; + modules.Add(module); + assemblyHash.add(module); + } + + public void initialize() { + initializeCalled = true; + findAllMemberReferences(); + resolveAllRefs(); + initAllTypes(); + } + + void findAllMemberReferences() { + Log.v("Finding all MemberReferences"); + int index = 0; + foreach (var module in modules) { + if (modules.Count > 1) + Log.v("Finding all MemberReferences ({0})", module.Filename); + Log.indent(); + module.findAllMemberReferences(ref index); + Log.deIndent(); + } + } + + void resolveAllRefs() { + Log.v("Resolving references"); + foreach (var module in modules) { + if (modules.Count > 1) + Log.v("Resolving references ({0})", module.Filename); + Log.indent(); + module.resolveAllRefs(this); + Log.deIndent(); + } + } + + void initAllTypes() { + foreach (var module in modules) + allTypes.AddRange(module.getAllTypes()); + + var typeToTypeDef = new Dictionary(allTypes.Count); + foreach (var typeDef in allTypes) + typeToTypeDef[typeDef.TypeDefinition] = typeDef; + + // Initialize Owner + foreach (var typeDef in allTypes) { + if (typeDef.TypeDefinition.DeclaringType != null) + typeDef.Owner = typeToTypeDef[typeDef.TypeDefinition.DeclaringType]; + } + + // Initialize baseType and derivedTypes + foreach (var typeDef in allTypes) { + var baseType = typeDef.TypeDefinition.BaseType; + if (baseType == null) + continue; + var baseTypeDef = resolve(baseType) ?? resolveOther(baseType); + if (baseTypeDef != null) { + typeDef.addBaseType(baseTypeDef, baseType); + baseTypeDef.derivedTypes.Add(typeDef); + } + } + + // Initialize interfaces + foreach (var typeDef in allTypes) { + if (typeDef.TypeDefinition.Interfaces == null) + continue; + foreach (var iface in typeDef.TypeDefinition.Interfaces) { + var ifaceTypeDef = resolve(iface) ?? resolveOther(iface); + if (ifaceTypeDef != null) + typeDef.addInterface(ifaceTypeDef, iface); + } + } + + // Find all non-nested types + var allTypesDict = new Dictionary(); + foreach (var t in allTypes) + allTypesDict[t] = true; + foreach (var t in allTypes) { + foreach (var t2 in t.NestedTypes) + allTypesDict.Remove(t2); + } + nonNestedTypes = new List(allTypesDict.Keys); + + foreach (var typeDef in allTypes) { + if (typeDef.baseType == null || !typeDef.baseType.typeDef.HasModule) + baseTypes.Add(typeDef); + } + } + + Dictionary otherTypesDict = new Dictionary(); + ExternalAssemblies externalAssemblies = new ExternalAssemblies(); + TypeDef resolveOther(TypeReference type) { + if (type == null) + return null; + type = type.GetElementType(); + + TypeDef typeDef; + var key = new TypeReferenceKey(type); + if (otherTypesDict.TryGetValue(key, out typeDef)) + return typeDef; + otherTypesDict[key] = null; // In case of a circular reference + + TypeDefinition typeDefinition = externalAssemblies.resolve(type); + if (typeDefinition == null) + return null; + + typeDef = new TypeDef(typeDefinition, null, 0); + typeDef.addMembers(); + foreach (var iface in typeDef.TypeDefinition.Interfaces) { + var ifaceDef = resolveOther(iface); + if (ifaceDef == null) + continue; + typeDef.addInterface(ifaceDef, iface); + } + var baseDef = resolveOther(typeDef.TypeDefinition.BaseType); + if (baseDef != null) + typeDef.addBaseType(baseDef, typeDef.TypeDefinition.BaseType); + return otherTypesDict[key] = typeDef; + } + + // Returns null if it's a non-loaded module/assembly + IEnumerable findModules(TypeReference type) { + var scope = type.Scope; + + if (scope is AssemblyNameReference) + return findModules((AssemblyNameReference)scope); + + if (scope is ModuleDefinition) { + var modules = findModules((ModuleDefinition)scope); + if (modules != null) + return modules; + } + + if (scope is ModuleReference) { + var moduleReference = (ModuleReference)scope; + if (moduleReference.Name == type.Module.Name) { + var modules = findModules(type.Module); + if (modules != null) + return modules; + } + + var asm = type.Module.Assembly; + if (asm == null) + return null; + var moduleHash = assemblyHash.lookup(asm.ToString()); + if (moduleHash == null) + return null; + var module = moduleHash.lookup(moduleReference.Name); + if (module == null) + return null; + return new List { module }; + } + + throw new ApplicationException(string.Format("scope is an unsupported type: {0}", scope.GetType())); + } + + IEnumerable findModules(AssemblyNameReference assemblyRef) { + var moduleHash = assemblyHash.lookup(assemblyRef.ToString()); + if (moduleHash != null) + return moduleHash.Modules; + return null; + } + + IEnumerable findModules(ModuleDefinition moduleDefinition) { + Module module; + if (modulesDict.TryGetValue(moduleDefinition, out module)) + return new List { module }; + return null; + } + + bool isAutoCreatedType(TypeReference typeReference) { + return typeReference is ArrayType || typeReference is PointerType || typeReference is FunctionPointerType; + } + + public TypeDef resolve(TypeReference typeReference) { + var modules = findModules(typeReference); + if (modules == null) + return null; + foreach (var module in modules) { + var rv = module.resolve(typeReference); + if (rv != null) + return rv; + } + if (isAutoCreatedType(typeReference)) + return null; + Log.e("Could not resolve TypeReference {0} ({1:X8})", typeReference, typeReference.MetadataToken.ToInt32()); + //TODO: Return null when you've tested all code + throw new ApplicationException(string.Format("Could not resolve TypeReference {0} ({1:X8})", typeReference, typeReference.MetadataToken.ToInt32())); + } + + public MethodDef resolve(MethodReference methodReference) { + if (methodReference.DeclaringType == null) + return null; + var modules = findModules(methodReference.DeclaringType); + if (modules == null) + return null; + foreach (var module in modules) { + var rv = module.resolve(methodReference); + if (rv != null) + return rv; + } + if (isAutoCreatedType(methodReference.DeclaringType)) + return null; + Log.e("Could not resolve MethodReference {0} ({1:X8})", methodReference, methodReference.MetadataToken.ToInt32()); + //TODO: Return null when you've tested all code + throw new ApplicationException(string.Format("Could not resolve MethodReference {0} ({1:X8})", methodReference, methodReference.MetadataToken.ToInt32())); + } + + public FieldDef resolve(FieldReference fieldReference) { + if (fieldReference.DeclaringType == null) + return null; + var modules = findModules(fieldReference.DeclaringType); + if (modules == null) + return null; + foreach (var module in modules) { + var rv = module.resolve(fieldReference); + if (rv != null) + return rv; + } + if (isAutoCreatedType(fieldReference.DeclaringType)) + return null; + Log.e("Could not resolve FieldReference {0} ({1:X8})", fieldReference, fieldReference.MetadataToken.ToInt32()); + //TODO: Return null when you've tested all code + throw new ApplicationException(string.Format("Could not resolve FieldReference {0} ({1:X8})", fieldReference, fieldReference.MetadataToken.ToInt32())); + } + } +} diff --git a/de4dot.code/renamer/asmmodules/PropertyDef.cs b/de4dot.code/renamer/asmmodules/PropertyDef.cs new file mode 100644 index 00000000..a4592127 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/PropertyDef.cs @@ -0,0 +1,44 @@ +/* + 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.Collections.Generic; +using Mono.Cecil; + +namespace de4dot.renamer.asmmodules { + class PropertyDef : Ref { + public PropertyDefinition PropertyDefinition { + get { return (PropertyDefinition)memberReference; } + } + + public PropertyDef(PropertyDefinition propertyDefinition, TypeDef owner, int index) + : base(propertyDefinition, owner, index) { + } + + public IEnumerable methodDefinitions() { + if (PropertyDefinition.GetMethod != null) + yield return PropertyDefinition.GetMethod; + if (PropertyDefinition.SetMethod != null) + yield return PropertyDefinition.SetMethod; + if (PropertyDefinition.OtherMethods != null) { + foreach (var m in PropertyDefinition.OtherMethods) + yield return m; + } + } + } +} diff --git a/de4dot.code/renamer/asmmodules/Ref.cs b/de4dot.code/renamer/asmmodules/Ref.cs new file mode 100644 index 00000000..12e325d0 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/Ref.cs @@ -0,0 +1,38 @@ +/* + 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 Mono.Cecil; + +namespace de4dot.renamer.asmmodules { + abstract class Ref { + protected readonly MemberReference memberReference; + public int Index { get; set; } + public TypeDef Owner { get; set; } + + protected Ref(MemberReference memberReference, TypeDef owner, int index) { + this.memberReference = memberReference; + Owner = owner; + Index = index; + } + + public override string ToString() { + return memberReference != null ? memberReference.ToString() : null; + } + } +} diff --git a/de4dot.code/renamer/asmmodules/RefDict.cs b/de4dot.code/renamer/asmmodules/RefDict.cs new file mode 100644 index 00000000..f9a126dc --- /dev/null +++ b/de4dot.code/renamer/asmmodules/RefDict.cs @@ -0,0 +1,214 @@ +/* + 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.Collections.Generic; +using Mono.Cecil; +using de4dot.blocks; + +namespace de4dot.renamer.asmmodules { + interface RefDict where TRef : Ref where TMRef : MemberReference { + IEnumerable getAll(); + IEnumerable getSorted(); + TRef find(TMRef tmref); + void add(TRef tref); + void onTypesRenamed(); + } + + class TypeDefDict : RefDict { + Dictionary tokenToTypeDef = new Dictionary(); + Dictionary typeRefToDef = new Dictionary(); + + public IEnumerable getAll() { + return tokenToTypeDef.Values; + } + + public IEnumerable getSorted() { + var list = new List(getAll()); + list.Sort((a, b) => { + if (a.Index < b.Index) return -1; + if (a.Index > b.Index) return 1; + return 0; + }); + return list; + } + + public TypeDef find(TypeReference typeReference) { + TypeDef typeDef; + if (tokenToTypeDef.TryGetValue(new ScopeAndTokenKey(typeReference), out typeDef)) + return typeDef; + + typeRefToDef.TryGetValue(new TypeReferenceKey(typeReference), out typeDef); + return typeDef; + } + + public void add(TypeDef typeDef) { + tokenToTypeDef[new ScopeAndTokenKey(typeDef.TypeDefinition)] = typeDef; + typeRefToDef[new TypeReferenceKey(typeDef.TypeDefinition)] = typeDef; + } + + public void onTypesRenamed() { + var all = new List(typeRefToDef.Values); + typeRefToDef.Clear(); + foreach (var typeDef in all) + typeRefToDef[new TypeReferenceKey(typeDef.TypeDefinition)] = typeDef; + } + } + + class FieldDefDict : RefDict { + Dictionary tokenToFieldDef = new Dictionary(); + Dictionary fieldRefToDef = new Dictionary(); + + public IEnumerable getAll() { + return tokenToFieldDef.Values; + } + + public IEnumerable getSorted() { + var list = new List(getAll()); + list.Sort((a, b) => { + if (a.Index < b.Index) return -1; + if (a.Index > b.Index) return 1; + return 0; + }); + return list; + } + + public FieldDef find(FieldReference fieldReference) { + FieldDef fieldDef; + if (tokenToFieldDef.TryGetValue(new ScopeAndTokenKey(fieldReference), out fieldDef)) + return fieldDef; + + fieldRefToDef.TryGetValue(new FieldReferenceKey(fieldReference), out fieldDef); + return fieldDef; + } + + public void add(FieldDef fieldDef) { + tokenToFieldDef[new ScopeAndTokenKey(fieldDef.FieldDefinition)] = fieldDef; + fieldRefToDef[new FieldReferenceKey(fieldDef.FieldDefinition)] = fieldDef; + } + + public void onTypesRenamed() { + var all = new List(fieldRefToDef.Values); + fieldRefToDef.Clear(); + foreach (var fieldDef in all) + fieldRefToDef[new FieldReferenceKey(fieldDef.FieldDefinition)] = fieldDef; + } + } + + class MethodDefDict : RefDict { + Dictionary tokenToMethodDef = new Dictionary(); + Dictionary methodRefToDef = new Dictionary(); + + public IEnumerable getAll() { + return tokenToMethodDef.Values; + } + + public IEnumerable getSorted() { + var list = new List(getAll()); + list.Sort((a, b) => { + if (a.Index < b.Index) return -1; + if (a.Index > b.Index) return 1; + return 0; + }); + return list; + } + + public MethodDef find(MethodReference methodReference) { + MethodDef methodDef; + if (tokenToMethodDef.TryGetValue(new ScopeAndTokenKey(methodReference), out methodDef)) + return methodDef; + + methodRefToDef.TryGetValue(new MethodReferenceKey(methodReference), out methodDef); + return methodDef; + } + + public void add(MethodDef methodDef) { + tokenToMethodDef[new ScopeAndTokenKey(methodDef.MethodDefinition)] = methodDef; + methodRefToDef[new MethodReferenceKey(methodDef.MethodDefinition)] = methodDef; + } + + public void onTypesRenamed() { + var all = new List(methodRefToDef.Values); + methodRefToDef.Clear(); + foreach (var methodDef in all) + methodRefToDef[new MethodReferenceKey(methodDef.MethodDefinition)] = methodDef; + } + } + + class PropertyDefDict : RefDict { + Dictionary tokenToPropDef = new Dictionary(); + + public IEnumerable getAll() { + return tokenToPropDef.Values; + } + + public IEnumerable getSorted() { + var list = new List(getAll()); + list.Sort((a, b) => { + if (a.Index < b.Index) return -1; + if (a.Index > b.Index) return 1; + return 0; + }); + return list; + } + + public PropertyDef find(PropertyReference propertyReference) { + PropertyDef propDef; + tokenToPropDef.TryGetValue(new ScopeAndTokenKey(propertyReference), out propDef); + return propDef; + } + + public void add(PropertyDef propDef) { + tokenToPropDef[new ScopeAndTokenKey(propDef.PropertyDefinition)] = propDef; + } + + public void onTypesRenamed() { + } + } + + class EventDefDict : RefDict { + Dictionary tokenToEventDef = new Dictionary(); + + public IEnumerable getAll() { + return tokenToEventDef.Values; + } + + public IEnumerable getSorted() { + var list = new List(getAll()); + list.Sort((a, b) => { + if (a.Index < b.Index) return -1; + if (a.Index > b.Index) return 1; + return 0; + }); + return list; + } + + public EventDef find(EventReference eventReference) { + EventDef eventDef; + tokenToEventDef.TryGetValue(new ScopeAndTokenKey(eventReference), out eventDef); + return eventDef; + } + + public void add(EventDef eventDef) { + tokenToEventDef[new ScopeAndTokenKey(eventDef.EventDefinition)] = eventDef; + } + + public void onTypesRenamed() { + } + } +} diff --git a/de4dot.code/renamer/asmmodules/TypeDef.cs b/de4dot.code/renamer/asmmodules/TypeDef.cs new file mode 100644 index 00000000..b6380c55 --- /dev/null +++ b/de4dot.code/renamer/asmmodules/TypeDef.cs @@ -0,0 +1,117 @@ +/* + 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; + +namespace de4dot.renamer.asmmodules { + class TypeInfo { + public TypeReference typeReference; + public TypeDef typeDef; + public TypeInfo(TypeReference typeReference, TypeDef typeDef) { + this.typeReference = typeReference; + this.typeDef = typeDef; + } + } + + class TypeDef : Ref { + EventDefDict events = new EventDefDict(); + FieldDefDict fields = new FieldDefDict(); + MethodDefDict methods = new MethodDefDict(); + PropertyDefDict properties = new PropertyDefDict(); + TypeDefDict types = new TypeDefDict(); + internal TypeInfo baseType = null; + internal IList interfaces = new List(); // directly implemented interfaces + internal IList derivedTypes = new List(); + Module module; + + public bool HasModule { + get { return module != null; } + } + + public IEnumerable NestedTypes { + get { return types.getSorted(); } + } + + public TypeDef NestingType { get; set; } + + public TypeDefinition TypeDefinition { + get { return (TypeDefinition)memberReference; } + } + + public TypeDef(TypeDefinition typeDefinition, Module module, int index) + : base(typeDefinition, null, index) { + this.module = module; + } + + public void addInterface(TypeDef ifaceDef, TypeReference iface) { + if (ifaceDef == null || iface == null) + return; + interfaces.Add(new TypeInfo(iface, ifaceDef)); + } + + public void addBaseType(TypeDef baseDef, TypeReference baseRef) { + if (baseDef == null || baseRef == null) + return; + baseType = new TypeInfo(baseRef, baseDef); + } + + public void add(EventDef e) { + events.add(e); + } + + public void add(FieldDef f) { + fields.add(f); + } + + public void add(MethodDef m) { + methods.add(m); + } + + public void add(PropertyDef p) { + properties.add(p); + } + + public void add(TypeDef t) { + types.add(t); + } + + public MethodDef find(MethodReference mr) { + return methods.find(mr); + } + + public FieldDef find(FieldReference fr) { + return fields.find(fr); + } + + public void addMembers() { + var type = TypeDefinition; + + for (int i = 0; i < type.Events.Count; i++) + add(new EventDef(type.Events[i], this, i)); + for (int i = 0; i < type.Fields.Count; i++) + add(new FieldDef(type.Fields[i], this, i)); + for (int i = 0; i < type.Methods.Count; i++) + add(new MethodDef(type.Methods[i], this, i)); + for (int i = 0; i < type.Properties.Count; i++) + add(new PropertyDef(type.Properties[i], this, i)); + } + } +}