From b2b563ef226f3d473dd0cbbb10f4722d417bd370 Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 21 Nov 2011 10:36:23 +0100 Subject: [PATCH] Add more renamer code --- de4dot.code/renamer/ExistingNames.cs | 2 +- de4dot.code/renamer/MemberInfos.cs | 12 +- de4dot.code/renamer/Renamer.cs | 905 +++++++++++++++++- de4dot.code/renamer/TypeInfo.cs | 227 ++++- de4dot.code/renamer/TypeRenamerState.cs | 4 + de4dot.code/renamer/VariableNameState.cs | 71 +- de4dot.code/renamer/asmmodules/EventDef.cs | 4 + .../renamer/asmmodules/MethodNameScopes.cs | 50 +- de4dot.code/renamer/asmmodules/Module.cs | 6 + de4dot.code/renamer/asmmodules/Modules.cs | 3 +- de4dot.code/renamer/asmmodules/PropertyDef.cs | 3 + de4dot.code/renamer/asmmodules/RefDict.cs | 73 +- de4dot.code/renamer/asmmodules/TypeDef.cs | 26 + 13 files changed, 1325 insertions(+), 61 deletions(-) diff --git a/de4dot.code/renamer/ExistingNames.cs b/de4dot.code/renamer/ExistingNames.cs index af809c2f..9bd1a933 100644 --- a/de4dot.code/renamer/ExistingNames.cs +++ b/de4dot.code/renamer/ExistingNames.cs @@ -28,7 +28,7 @@ namespace de4dot.renamer { allNames[name] = true; } - bool exists(string name) { + public bool exists(string name) { return allNames.ContainsKey(name); } diff --git a/de4dot.code/renamer/MemberInfos.cs b/de4dot.code/renamer/MemberInfos.cs index 2c3d3b61..17b90750 100644 --- a/de4dot.code/renamer/MemberInfos.cs +++ b/de4dot.code/renamer/MemberInfos.cs @@ -22,7 +22,7 @@ using de4dot.renamer.asmmodules; namespace de4dot.renamer { class MemberInfo { - Ref memberRef; + protected Ref memberRef; public string oldFullName; public string oldName; public string newName; @@ -71,6 +71,10 @@ namespace de4dot.renamer { } class MethodInfo : MemberInfo { + public MethodDef MethodDef { + get { return (MethodDef)memberRef; } + } + public MethodInfo(MethodDef methodDef) : base(methodDef) { } @@ -238,6 +242,10 @@ namespace de4dot.renamer { return allParamInfos[param]; } + public void add(PropertyDef prop) { + allPropertyInfos[prop] = new PropertyInfo(prop); + } + public void initialize(Modules modules) { foreach (var type in modules.AllTypes) { allTypeInfos[type] = new TypeInfo(type, this); @@ -252,7 +260,7 @@ namespace de4dot.renamer { allEventInfos[evt] = new EventInfo(evt); foreach (var prop in type.AllProperties) - allPropertyInfos[prop] = new PropertyInfo(prop); + add(prop); foreach (var method in type.AllMethods) { allMethodInfos[method] = new MethodInfo(method); diff --git a/de4dot.code/renamer/Renamer.cs b/de4dot.code/renamer/Renamer.cs index d729402f..465b7192 100644 --- a/de4dot.code/renamer/Renamer.cs +++ b/de4dot.code/renamer/Renamer.cs @@ -17,21 +17,35 @@ along with de4dot. If not, see . */ +using System; using System.Collections.Generic; +using System.Text.RegularExpressions; +using Mono.Cecil; +using Mono.Cecil.Cil; using de4dot.renamer.asmmodules; +using de4dot.blocks; namespace de4dot.renamer { class Renamer { public bool RenameNamespaces { get; set; } public bool RenameTypes { get; set; } - public bool RenameGenericParams { get; set; } public bool RenameProperties { get; set; } public bool RenameEvents { get; set; } public bool RenameFields { get; set; } public bool RenameMethods { get; set; } public bool RenameMethodArgs { get; set; } + public bool RenameGenericParams { get; set; } + public bool RestoreProperties { get; set; } + public bool RestorePropertiesFromNames { get; set; } + Modules modules = new Modules(); MemberInfos memberInfos = new MemberInfos(); + DerivedFrom isDelegateClass; + + static string[] delegateClasses = new string[] { + "System.Delegate", + "System.MulticastDelegate", + }; public Renamer(IEnumerable files) { RenameNamespaces = true; @@ -39,8 +53,12 @@ namespace de4dot.renamer { RenameProperties = true; RenameEvents = true; RenameFields = true; - RenameGenericParams = true; + RenameMethods = true; RenameMethodArgs = true; + RenameGenericParams = true; + RestoreProperties = true; + RestorePropertiesFromNames = true; + isDelegateClass = new DerivedFrom(delegateClasses); foreach (var file in files) modules.add(new Module(file)); @@ -52,23 +70,65 @@ namespace de4dot.renamer { Log.n("Renaming all obfuscated symbols"); modules.initialize(); - modules.initializeVirtualMembers(); + var scopes = modules.initializeVirtualMembers(); memberInfos.initialize(modules); renameTypeDefinitions(); renameTypeReferences(); modules.onTypesRenamed(); - prepareRenameMemberDefinitions(); + restoreProperties(scopes); + prepareRenameMemberDefinitions(scopes); + renameMemberDefinitions(); + renameMemberReferences(); + renameResources(); modules.cleanUp(); } void renameTypeDefinitions() { Log.v("Renaming obfuscated type definitions"); - prepareRenameTypes(modules.BaseTypes, new TypeRenamerState()); + foreach (var module in modules.TheModules) { + if (module.ObfuscatedFile.RemoveNamespaceWithOneType) + removeOneClassNamespaces(module); + } + + var state = new TypeRenamerState(); + foreach (var type in modules.AllTypes) + state.addTypeName(memberInfos.type(type).oldName); + prepareRenameTypes(modules.BaseTypes, state); fixClsTypeNames(); renameTypeDefinitions(modules.NonNestedTypes); } + void removeOneClassNamespaces(Module module) { + var nsToTypes = new Dictionary>(StringComparer.Ordinal); + + foreach (var typeDef in module.getAllTypes()) { + List list; + var ns = typeDef.TypeDefinition.Namespace; + if (string.IsNullOrEmpty(ns)) + continue; + if (module.ObfuscatedFile.NameChecker.isValidNamespaceName(ns)) + continue; + if (!nsToTypes.TryGetValue(ns, out list)) + nsToTypes[ns] = list = new List(); + list.Add(typeDef); + } + + var sortedNamespaces = new List>(nsToTypes.Values); + sortedNamespaces.Sort((a, b) => { + return string.CompareOrdinal(a[0].TypeDefinition.Namespace, b[0].TypeDefinition.Namespace); + }); + foreach (var list in sortedNamespaces) { + const int maxClasses = 1; + if (list.Count != maxClasses) + continue; + var ns = list[0].TypeDefinition.Namespace; + Log.v("Removing namespace: {0}", ns); + foreach (var type in list) + memberInfos.type(type).newNamespace = ""; + } + } + void renameTypeDefinitions(IEnumerable typeDefs) { Log.indent(); foreach (var typeDef in typeDefs) { @@ -114,6 +174,235 @@ namespace de4dot.renamer { } } + void renameMemberDefinitions() { + Log.v("Renaming member definitions #2"); + + var allTypes = new List(modules.AllTypes); + allTypes.Sort((a, b) => Utils.compareInt32(a.Index, b.Index)); + + Log.indent(); + foreach (var typeDef in allTypes) + renameMembers(typeDef); + Log.deIndent(); + } + + void renameMembers(TypeDef type) { + var info = memberInfos.type(type); + + Log.v("Type: {0}", info.type.TypeDefinition.FullName); + Log.indent(); + + renameFields(info); + renameProperties(info); + renameEvents(info); + renameMethods(info); + + Log.deIndent(); + } + + void renameFields(TypeInfo info) { + if (!RenameFields) + return; + foreach (var fieldDef in info.type.AllFieldsSorted) { + var fieldInfo = memberInfos.field(fieldDef); + if (!fieldInfo.gotNewName()) + continue; + fieldDef.FieldDefinition.Name = fieldInfo.newName; + Log.v("Field: {0} ({1:X8}) => {2}", fieldInfo.oldFullName, fieldDef.FieldDefinition.MetadataToken.ToUInt32(), fieldDef.FieldDefinition.FullName); + } + } + + void renameProperties(TypeInfo info) { + if (!RenameProperties) + return; + foreach (var propDef in info.type.AllPropertiesSorted) { + var propInfo = memberInfos.prop(propDef); + if (!propInfo.gotNewName()) + continue; + propDef.PropertyDefinition.Name = propInfo.newName; + Log.v("Property: {0} ({1:X8}) => {2}", propInfo.oldFullName, propDef.PropertyDefinition.MetadataToken.ToUInt32(), propDef.PropertyDefinition.FullName); + } + } + + void renameEvents(TypeInfo info) { + if (!RenameEvents) + return; + foreach (var eventDef in info.type.AllEventsSorted) { + var eventInfo = memberInfos.evt(eventDef); + if (!eventInfo.gotNewName()) + continue; + eventDef.EventDefinition.Name = eventInfo.newName; + Log.v("Event: {0} ({1:X8}) => {2}", eventInfo.oldFullName, eventDef.EventDefinition.MetadataToken.ToUInt32(), eventDef.EventDefinition.FullName); + } + } + + void renameMethods(TypeInfo info) { + if (!RenameMethods && !RenameMethodArgs && !RenameGenericParams) + return; + foreach (var methodDef in info.type.AllMethodsSorted) { + var methodInfo = memberInfos.method(methodDef); + Log.v("Method {0} ({1:X8})", methodInfo.oldFullName, methodDef.MethodDefinition.MetadataToken.ToUInt32()); + Log.indent(); + + renameGenericParams(methodDef.GenericParams); + + if (RenameMethods && methodInfo.gotNewName()) { + methodDef.MethodDefinition.Name = methodInfo.newName; + Log.v("Name: {0} => {1}", methodInfo.oldFullName, methodDef.MethodDefinition.FullName); + } + + if (RenameMethodArgs) { + foreach (var param in methodDef.ParamDefs) { + var paramInfo = memberInfos.param(param); + if (!paramInfo.gotNewName()) + continue; + param.ParameterDefinition.Name = paramInfo.newName; + Log.v("Param ({0}/{1}): {2} => {3}", param.Index + 1, methodDef.ParamDefs.Count, paramInfo.oldName, paramInfo.newName); + } + } + + Log.deIndent(); + } + } + + void renameMemberReferences() { + Log.v("Renaming references to other definitions"); + foreach (var module in modules.TheModules) { + if (modules.TheModules.Count > 1) + Log.v("Renaming references to other definitions ({0})", module.Filename); + Log.indent(); + foreach (var refToDef in module.MethodRefsToRename) + refToDef.reference.Name = refToDef.definition.Name; + foreach (var refToDef in module.FieldRefsToRename) + refToDef.reference.Name = refToDef.definition.Name; + Log.deIndent(); + } + } + + void renameResources() { + Log.v("Renaming resources"); + foreach (var module in modules.TheModules) { + if (modules.TheModules.Count > 1) + Log.v("Renaming resources ({0})", module.Filename); + Log.indent(); + renameResources(module); + Log.deIndent(); + } + } + + void renameResources(Module module) { + var renamedTypes = new List(); + foreach (var type in module.getAllTypes()) { + var info = memberInfos.type(type); + if (info.oldFullName != info.type.TypeDefinition.FullName) + renamedTypes.Add(info); + } + if (renamedTypes.Count == 0) + return; + + // Rename the longest names first. Otherwise eg. b.g.resources could be renamed + // Class0.g.resources instead of Class1.resources when b.g was renamed Class1. + renamedTypes.Sort((a, b) => Utils.compareInt32(b.oldFullName.Length, a.oldFullName.Length)); + + renameResourceNamesInCode(module, renamedTypes); + renameResources(module, renamedTypes); + } + + void renameResourceNamesInCode(Module module, IEnumerable renamedTypes) { + // This is needed to speed up this method + var oldToNewTypeName = new Dictionary(StringComparer.Ordinal); + foreach (var info in renamedTypes) + oldToNewTypeName[info.oldFullName] = info.type.TypeDefinition.FullName; + + List validResourceNames = new List(); + if (module.ModuleDefinition.Resources != null) { + foreach (var resource in module.ModuleDefinition.Resources) { + var name = resource.Name; + if (name.EndsWith(".resources", StringComparison.Ordinal)) + validResourceNames.Add(name); + } + } + + foreach (var method in module.getAllMethods()) { + if (!method.HasBody) + continue; + foreach (var instr in method.Body.Instructions) { + if (instr.OpCode != OpCodes.Ldstr) + continue; + var s = (string)instr.Operand; + if (string.IsNullOrEmpty(s)) + continue; // Ignore emtpy strings since we'll get lots of false warnings + + string newName = null; + string oldName = null; + if (oldToNewTypeName.ContainsKey(s)) { + oldName = s; + newName = oldToNewTypeName[s]; + } + else if (s.EndsWith(".resources", StringComparison.Ordinal)) { + // This should rarely, if ever, execute... + foreach (var info in renamedTypes) { // Slow loop + var newName2 = renameResourceString(s, info.oldFullName, info.type.TypeDefinition.FullName); + if (newName2 != s) { + newName = newName2; + oldName = info.oldFullName; + break; + } + } + } + if (newName == null || string.IsNullOrEmpty(oldName)) + continue; + + bool isValid = false; + foreach (var validName in validResourceNames) { + if (Utils.StartsWith(validName, oldName, StringComparison.Ordinal)) { + isValid = true; + break; + } + } + if (!isValid) + continue; + + if (s == "" || !module.ObfuscatedFile.RenameResourcesInCode) + Log.v("Possible resource name in code: '{0}' => '{1}' in method {2}", s, newName, method); + else { + instr.Operand = newName; + Log.v("Renamed resource string in code: '{0}' => '{1}' ({2})", s, newName, method); + break; + } + } + } + } + + void renameResources(Module module, IEnumerable renamedTypes) { + if (module.ModuleDefinition.Resources == null) + return; + foreach (var resource in module.ModuleDefinition.Resources) { + var s = resource.Name; + foreach (var info in renamedTypes) { + var newName = renameResourceString(s, info.oldFullName, info.type.TypeDefinition.FullName); + if (newName != s) { + resource.Name = newName; + Log.v("Renamed resource in resources: {0} => {1}", s, newName); + break; + } + } + } + } + + static string renameResourceString(string s, string oldTypeName, string newTypeName) { + if (!Utils.StartsWith(s, oldTypeName, StringComparison.Ordinal)) + return s; + if (s.Length == oldTypeName.Length) + return newTypeName; + // s.Length > oldTypeName.Length + if (s[oldTypeName.Length] != '.') + return s; + if (!s.EndsWith(".resources", StringComparison.Ordinal)) + return s; + return newTypeName + s.Substring(oldTypeName.Length); + } + // Make sure the renamed types are using valid CLS names. That means renaming all // generic types from eg. Class1 to Class1`2. If we don't do this, some decompilers // (eg. ILSpy v1.0) won't produce correct output. @@ -154,7 +443,163 @@ namespace de4dot.renamer { } } - void prepareRenameMemberDefinitions() { + void restoreProperties(MethodNameScopes scopes) { + var allScopes = scopes.getAllScopes(); + restoreVirtualProperties(allScopes); + restorePropertiesFromNames(allScopes); + } + + void restoreVirtualProperties(IEnumerable allScopes) { + if (!RestoreProperties) + return; + foreach (var scope in allScopes) + restoreVirtualProperties(scope); + } + + void restoreVirtualProperties(MethodNameScope scope) { + if (scope.Methods.Count <= 1 || !scope.hasProperty()) + return; + + PropertyDef prop = null; + List missingProps = null; + foreach (var method in scope.Methods) { + if (method.Property == null) { + if (missingProps == null) + missingProps = new List(); + missingProps.Add(method); + } + else if (prop == null) + prop = method.Property; + } + if (prop == null) + return; // Should never happen + if (missingProps == null) + return; + + foreach (var method in missingProps) { + if (!method.Owner.HasModule) + continue; + + if (method.MethodDefinition.MethodReturnType.ReturnType.FullName == "System.Void") + createPropertySetter(prop.PropertyDefinition.Name, method); + else + createPropertyGetter(prop.PropertyDefinition.Name, method); + } + } + + void restorePropertiesFromNames(IEnumerable allScopes) { + if (!RestorePropertiesFromNames) + return; + + foreach (var scope in allScopes) { + var scopeMethod = scope.Methods[0]; + var methodName = scopeMethod.MethodDefinition.Name; + bool onlyRenamableMethods = !scope.hasNonRenamableMethod(); + + if (Utils.StartsWith(methodName, "get_", StringComparison.Ordinal)) { + var propName = methodName.Substring(4); + foreach (var method in scope.Methods) { + if (onlyRenamableMethods && !memberInfos.type(method.Owner).NameChecker.isValidPropertyName(propName)) + continue; + createPropertyGetter(propName, method); + } + } + else if (Utils.StartsWith(methodName, "set_", StringComparison.Ordinal)) { + var propName = methodName.Substring(4); + foreach (var method in scope.Methods) { + if (onlyRenamableMethods && !memberInfos.type(method.Owner).NameChecker.isValidPropertyName(propName)) + continue; + createPropertySetter(propName, method); + } + } + } + + foreach (var type in modules.AllTypes) { + foreach (var method in type.AllMethodsSorted) { + if (method.isVirtual()) + continue; // Virtual methods are in allScopes, so already fixed above + if (method.Property != null) + continue; + var methodName = method.MethodDefinition.Name; + if (Utils.StartsWith(methodName, "get_", StringComparison.Ordinal)) + createPropertyGetter(methodName.Substring(4), method); + else if (Utils.StartsWith(methodName, "set_", StringComparison.Ordinal)) + createPropertySetter(methodName.Substring(4), method); + } + } + } + + PropertyDef createPropertyGetter(string name, MethodDef propMethod) { + if (string.IsNullOrEmpty(name)) + return null; + var ownerType = propMethod.Owner; + if (!ownerType.HasModule) + return null; + if (propMethod.Property != null) + return null; + + var method = propMethod.MethodDefinition; + var propType = method.MethodReturnType.ReturnType; + var propDef = createProperty(ownerType, name, propType); + if (propDef == null) + return null; + if (propDef.GetMethod != null) + return null; + Log.v("Restoring property getter {0} ({1:X8}), Property: {2} ({3:X8})", + propMethod, + propMethod.MethodDefinition.MetadataToken.ToInt32(), + propDef.PropertyDefinition, + propDef.PropertyDefinition.MetadataToken.ToInt32()); + propDef.PropertyDefinition.GetMethod = propMethod.MethodDefinition; + propDef.GetMethod = propMethod; + propMethod.Property = propDef; + return propDef; + } + + PropertyDef createPropertySetter(string name, MethodDef propMethod) { + if (string.IsNullOrEmpty(name)) + return null; + var ownerType = propMethod.Owner; + if (!ownerType.HasModule) + return null; + if (propMethod.Property != null) + return null; + + var method = propMethod.MethodDefinition; + if (method.Parameters.Count == 0) + return null; + var propType = method.Parameters[method.Parameters.Count - 1].ParameterType; + var propDef = createProperty(ownerType, name, propType); + if (propDef == null) + return null; + if (propDef.SetMethod != null) + return null; + Log.v("Restoring property setter {0} ({1:X8}), Property: {2} ({3:X8})", + propMethod, + propMethod.MethodDefinition.MetadataToken.ToInt32(), + propDef.PropertyDefinition, + propDef.PropertyDefinition.MetadataToken.ToInt32()); + propDef.PropertyDefinition.SetMethod = propMethod.MethodDefinition; + propDef.SetMethod = propMethod; + propMethod.Property = propDef; + return propDef; + } + + PropertyDef createProperty(TypeDef ownerType, string name, TypeReference propType) { + if (string.IsNullOrEmpty(name) || propType.FullName == "System.Void") + return null; + var newProp = DotNetUtils.createPropertyDefinition(name, propType); + var propDef = ownerType.find(newProp); + if (propDef != null) + return propDef; + + propDef = ownerType.create(newProp); + memberInfos.add(propDef); + Log.v("Restoring property: {0}", newProp); + return propDef; + } + + void prepareRenameMemberDefinitions(MethodNameScopes scopes) { Log.v("Renaming member definitions #1"); prepareRenameEntryPoints(); @@ -164,6 +609,11 @@ namespace de4dot.renamer { foreach (var typeDef in modules.AllTypes) prepareRenameMembers(typeDef); + + prepareRenameVirtualMethods(scopes); + + foreach (var typeDef in modules.AllTypes) + memberInfos.type(typeDef).prepareRenameMethods2(); } Dictionary prepareRenameMembersCalled = new Dictionary(); @@ -182,6 +632,449 @@ namespace de4dot.renamer { info.prepareRenameMembers(); } + static List getSorted(MethodNameScopes scopes) { + var allScopes = new List(scopes.getAllScopes()); + allScopes.Sort((a, b) => Utils.compareInt32(b.Count, a.Count)); + return allScopes; + } + + void prepareRenameVirtualMethods(MethodNameScopes scopes) { + var allScopes = getSorted(scopes); + + var virtualMethods = new List(); + var ifaceMethods = new List(); + var propMethods = new List(); + var eventMethods = new List(); + foreach (var scope in allScopes) { + if (scope.hasNonRenamableMethod()) + continue; + else if (scope.hasPropertyMethod() && getPropertyMethodType(scope.Methods[0]) != PropertyMethodType.Other) + propMethods.Add(scope); + else if (scope.hasEventMethod()) + eventMethods.Add(scope); + else if (scope.hasInterfaceMethod()) + ifaceMethods.Add(scope); + else + virtualMethods.Add(scope); + } + + prepareRenameVirtualProperties(propMethods); + prepareRenameVirtualEvents(eventMethods); + prepareRenameVirtualMethods(virtualMethods, "vmethod_", false); + prepareRenameVirtualMethods(ifaceMethods, "imethod_", false); + prepareRenameVirtualMethods(virtualMethods, "vmethod_", true); + prepareRenameVirtualMethods(ifaceMethods, "imethod_", true); + } + + Dictionary numBaseClassesDict = new Dictionary(); + int getNumberOfBaseClasses(TypeDef type) { + int numBaseClasses; + if (numBaseClassesDict.TryGetValue(type, out numBaseClasses)) + return numBaseClasses; + return numBaseClassesDict[type] = getNumberOfBaseClassesInternal(type); + } + + int getNumberOfBaseClassesInternal(TypeDef type) { + if (type.baseType == null) + return 0; + return getNumberOfBaseClasses(type.baseType.typeDef) + 1; + } + + int compareTypes(TypeDef a, TypeDef b) { + int ac = getNumberOfBaseClasses(a); + int bc = getNumberOfBaseClasses(b); + if (ac < bc) return -1; + if (ac > bc) return 1; + return Utils.compareInt32(a.Index, b.Index); + } + + void sortScopes(List scopes) { + var scopeToType = new Dictionary(scopes.Count); + foreach (var scope in scopes) { + TypeDef type = null; + foreach (var method in scope.Methods) { + var owner = method.Owner; + if (type == null || compareTypes(owner, type) < 0) + type = owner; + } + scopeToType[scope] = type; + } + scopes.Sort((a, b) => compareTypes(scopeToType[a], scopeToType[b])); + } + + static readonly Regex removeGenericsArityRegex = new Regex(@"`[0-9]+"); + static string getOverridePrefix(MethodDef method) { + if (method.MethodDefinition.Overrides.Count == 0) + return ""; + var overrideMethod = method.MethodDefinition.Overrides[0]; + var name = overrideMethod.DeclaringType.FullName.Replace('/', '.'); + name = removeGenericsArityRegex.Replace(name, ""); + return name + "."; + } + + static string getRealName(string name) { + int index = name.LastIndexOf('.'); + if (index < 0) + return name; + return name.Substring(index + 1); + } + + void prepareRenameVirtualEvents(List scopes) { + sortScopes(scopes); + + foreach (var scope in scopes) + prepareRenameEvent(scope, false); + foreach (var scope in scopes) + prepareRenameEvent(scope, true); + } + + void prepareRenameEvent(MethodNameScope scope, bool renameOverrides) { + string methodPrefix, overridePrefix; + var eventName = prepareRenameEvent(scope, renameOverrides, out overridePrefix, out methodPrefix); + if (eventName == null) + return; + + var methodName = overridePrefix + methodPrefix + eventName; + foreach (var method in scope.Methods) + memberInfos.method(method).rename(methodName); + } + + string prepareRenameEvent(MethodNameScope scope, bool renameOverrides, out string overridePrefix, out string methodPrefix) { + var eventMethod = getEventMethod(scope); + if (eventMethod == null) + throw new ApplicationException("No events found"); + + var eventDef = eventMethod.Event; + if (eventMethod == eventDef.AddMethod) + methodPrefix = "add_"; + else if (eventMethod == eventDef.RemoveMethod) + methodPrefix = "remove_"; + else if (eventMethod == eventDef.RaiseMethod) + methodPrefix = "raise_"; + else + methodPrefix = null; + + overridePrefix = getOverridePrefix(eventMethod); + if (renameOverrides && overridePrefix == "") + return null; + if (!renameOverrides && overridePrefix != "") + return null; + + string newEventName, oldEventName; + var eventInfo = memberInfos.evt(eventDef); + + if (overridePrefix == "") + oldEventName = eventInfo.oldName; + else { + var overriddenEventDef = getOverriddenEvent(eventMethod); + if (overriddenEventDef == null) + oldEventName = getRealName(eventInfo.oldName); + else + oldEventName = getRealName(memberInfos.evt(overriddenEventDef).newName); + } + + if (eventInfo.renamed) + newEventName = getRealName(eventInfo.newName); + else if (eventDef.Owner.Module.ObfuscatedFile.NameChecker.isValidEventName(oldEventName)) + newEventName = oldEventName; + else + newEventName = getAvailableName("Event_", scope, (scope2, newName) => isEventAvailable(scope2, newName)); + + var newEventNameWithPrefix = overridePrefix + newEventName; + foreach (var method in scope.Methods) { + if (method.Event != null) { + memberInfos.evt(method.Event).rename(newEventNameWithPrefix); + var ownerInfo = memberInfos.type(method.Owner); + ownerInfo.variableNameState.addEventName(newEventName); + ownerInfo.variableNameState.addEventName(newEventNameWithPrefix); + } + } + + return newEventName; + } + + EventDef getOverriddenEvent(MethodDef overrideMethod) { + var overriddenMethod = modules.resolve(overrideMethod.MethodDefinition.Overrides[0]); + if (overriddenMethod == null) + return null; + return overriddenMethod.Event; + } + + MethodDef getEventMethod(MethodNameScope scope) { + foreach (var method in scope.Methods) { + if (method.Event != null) + return method; + } + return null; + } + + void prepareRenameVirtualProperties(List scopes) { + sortScopes(scopes); + + foreach (var scope in scopes) + prepareRenameProperty(scope, false); + foreach (var scope in scopes) + prepareRenameProperty(scope, true); + } + + void prepareRenameProperty(MethodNameScope scope, bool renameOverrides) { + string overridePrefix; + var propName = prepareRenameProperty(scope, renameOverrides, out overridePrefix); + if (propName == null) + return; + + string methodPrefix; + switch (getPropertyMethodType(scope.Methods[0])) { + case PropertyMethodType.Getter: + methodPrefix = "get_"; + break; + case PropertyMethodType.Setter: + methodPrefix = "set_"; + break; + default: + throw new ApplicationException("Invalid property type"); + } + + var methodName = overridePrefix + methodPrefix + propName; + foreach (var method in scope.Methods) + memberInfos.method(method).rename(methodName); + } + + string prepareRenameProperty(MethodNameScope scope, bool renameOverrides, out string overridePrefix) { + var propMethod = getPropertyMethod(scope); + if (propMethod == null) + throw new ApplicationException("No properties found"); + + overridePrefix = getOverridePrefix(propMethod); + + if (renameOverrides && overridePrefix == "") + return null; + if (!renameOverrides && overridePrefix != "") + return null; + + string newPropName, oldPropName; + var propDef = propMethod.Property; + var propInfo = memberInfos.prop(propDef); + + if (overridePrefix == "") + oldPropName = propInfo.oldName; + else { + var overriddenPropDef = getOverriddenProperty(propMethod); + if (overriddenPropDef == null) + oldPropName = getRealName(propInfo.oldName); + else + oldPropName = getRealName(memberInfos.prop(overriddenPropDef).newName); + } + + if (propInfo.renamed) + newPropName = getRealName(propInfo.newName); + else if (propDef.Owner.Module.ObfuscatedFile.NameChecker.isValidPropertyName(oldPropName)) + newPropName = oldPropName; + else { + var propPrefix = getSuggestedPropertyName(scope) ?? getNewPropertyNamePrefix(scope); + newPropName = getAvailableName(propPrefix, scope, (scope2, newName) => isPropertyAvailable(scope2, newName)); + } + + var newPropNameWithPrefix = overridePrefix + newPropName; + foreach (var method in scope.Methods) { + if (method.Property != null) { + memberInfos.prop(method.Property).rename(newPropNameWithPrefix); + var ownerInfo = memberInfos.type(method.Owner); + ownerInfo.variableNameState.addPropertyName(newPropName); + ownerInfo.variableNameState.addPropertyName(newPropNameWithPrefix); + } + } + + return newPropName; + } + + PropertyDef getOverriddenProperty(MethodDef overrideMethod) { + var overriddenMethod = modules.resolve(overrideMethod.MethodDefinition.Overrides[0]); + if (overriddenMethod == null) + return null; + return overriddenMethod.Property; + } + + MethodDef getPropertyMethod(MethodNameScope scope) { + foreach (var method in scope.Methods) { + if (method.Property != null) + return method; + } + return null; + } + + string getSuggestedPropertyName(MethodNameScope scope) { + foreach (var method in scope.Methods) { + if (method.Property == null) + continue; + var info = memberInfos.prop(method.Property); + if (info.suggestedName != null) + return info.suggestedName; + } + return null; + } + + string getNewPropertyNamePrefix(MethodNameScope scope) { + const string defaultVal = "Prop_"; + + var propType = getPropertyType(scope); + if (propType == null) + return defaultVal; + + string name = propType.Name; + int i = name.IndexOf('`'); + if (i >= 0) + name = name.Substring(0, i); + i = name.IndexOf('.'); + if (i >= 0) + name = name.Substring(0, i); + if (name == "") + return defaultVal; + return name + "_"; + } + + enum PropertyMethodType { + Other, + Getter, + Setter, + } + + static PropertyMethodType getPropertyMethodType(MethodDef method) { + if (method.MethodDefinition.MethodReturnType.ReturnType.FullName != "System.Void") + return PropertyMethodType.Getter; + if (method.ParamDefs.Count > 0) + return PropertyMethodType.Setter; + return PropertyMethodType.Other; + } + + // Returns property type, or null if not all methods have the same type + TypeReference getPropertyType(MethodNameScope scope) { + var methodType = getPropertyMethodType(scope.Methods[0]); + if (methodType == PropertyMethodType.Other) + return null; + + TypeReference type = null; + foreach (var propMethod in scope.Methods) { + TypeReference propType; + if (methodType == PropertyMethodType.Setter) + propType = propMethod.ParamDefs[propMethod.ParamDefs.Count - 1].ParameterDefinition.ParameterType; + else + propType = propMethod.MethodDefinition.MethodReturnType.ReturnType; + if (type == null) + type = propType; + else if (!MemberReferenceHelper.compareTypes(type, propType)) + return null; + } + return type; + } + + void prepareRenameVirtualMethods(List scopes, string namePrefix, bool renameOverrides) { + sortScopes(scopes); + + foreach (var scope in scopes) + prepareRenameVirtualMethods(scope, namePrefix, renameOverrides); + } + + void prepareRenameVirtualMethods(MethodNameScope scope, string namePrefix, bool renameOverrides) { + if (!hasInvalidMethodName(scope)) + return; + + if (hasDelegateOwner(scope)) { + switch (scope.Methods[0].MethodDefinition.Name) { + case "Invoke": + case "BeginInvoke": + case "EndInvoke": + return; + } + } + + var overrideMethod = scope.Methods[0]; + var overridePrefix = getOverridePrefix(overrideMethod); + if (renameOverrides && overridePrefix == "") + return; + if (!renameOverrides && overridePrefix != "") + return; + + string newMethodName; + if (overridePrefix != "") { + var overrideInfo = memberInfos.method(overrideMethod); + var overriddenMethod = getOverriddenMethod(overrideMethod); + if (overriddenMethod == null) + newMethodName = getRealName(overrideMethod.MethodDefinition.Overrides[0].Name); + else + newMethodName = getRealName(memberInfos.method(overriddenMethod).newName); + } + else + newMethodName = getSuggestedMethodName(scope) ?? getAvailableName(namePrefix, scope, (scope2, newName) => isMethodAvailable(scope2, newName)); + + var newMethodNameWithPrefix = overridePrefix + newMethodName; + foreach (var method in scope.Methods) + memberInfos.type(method.Owner).renameMethod(method, newMethodNameWithPrefix); + } + + MethodDef getOverriddenMethod(MethodDef overrideMethod) { + return modules.resolve(overrideMethod.MethodDefinition.Overrides[0]); + } + + string getSuggestedMethodName(MethodNameScope scope) { + foreach (var method in scope.Methods) { + var info = memberInfos.method(method); + if (info.suggestedName != null) + return info.suggestedName; + } + return null; + } + + bool hasInvalidMethodName(MethodNameScope scope) { + foreach (var method in scope.Methods) { + var typeInfo = memberInfos.type(method.Owner); + var methodInfo = memberInfos.method(method); + if (!typeInfo.NameChecker.isValidMethodName(methodInfo.oldName)) + return true; + } + return false; + } + + static string getAvailableName(string prefix, MethodNameScope scope, Func checkAvailable) { + for (int i = 0; ; i++) { + string newName = prefix + i; + if (checkAvailable(scope, newName)) + return newName; + } + } + + bool isMethodAvailable(MethodNameScope scope, string methodName) { + foreach (var method in scope.Methods) { + if (memberInfos.type(method.Owner).variableNameState.isMethodNameUsed(methodName)) + return false; + } + return true; + } + + bool isPropertyAvailable(MethodNameScope scope, string methodName) { + foreach (var method in scope.Methods) { + if (memberInfos.type(method.Owner).variableNameState.isPropertyNameUsed(methodName)) + return false; + } + return true; + } + + bool isEventAvailable(MethodNameScope scope, string methodName) { + foreach (var method in scope.Methods) { + if (memberInfos.type(method.Owner).variableNameState.isEventNameUsed(methodName)) + return false; + } + return true; + } + + bool hasDelegateOwner(MethodNameScope scope) { + foreach (var method in scope.Methods) { + if (isDelegateClass.check(method.Owner)) + return true; + } + return false; + } + void prepareRenameEntryPoints() { foreach (var module in modules.TheModules) { var entryPoint = module.ModuleDefinition.EntryPoint; diff --git a/de4dot.code/renamer/TypeInfo.cs b/de4dot.code/renamer/TypeInfo.cs index 39fccfab..cac23105 100644 --- a/de4dot.code/renamer/TypeInfo.cs +++ b/de4dot.code/renamer/TypeInfo.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; using de4dot.renamer.asmmodules; @@ -29,9 +30,13 @@ namespace de4dot.renamer { public string oldNamespace; public string newNamespace; public VariableNameState variableNameState; - TypeDef type; + public TypeDef type; MemberInfos memberInfos; + public INameChecker NameChecker { + get { return type.Module.ObfuscatedFile.NameChecker; } + } + public TypeInfo(TypeDef typeDef, MemberInfos memberInfos) : base(typeDef) { this.type = typeDef; @@ -77,7 +82,7 @@ namespace de4dot.renamer { } public void prepareRenameTypes(TypeRenamerState state) { - var checker = type.Module.ObfuscatedFile.NameChecker; + var checker = NameChecker; if (newNamespace == null && oldNamespace != "") { if (!checker.isValidNamespaceName(oldNamespace)) { @@ -110,6 +115,15 @@ namespace de4dot.renamer { if (variableNameState == null) variableNameState = memberInfos.type(type.baseType.typeDef).variableNameState.clone(); + foreach (var fieldDef in type.AllFields) + variableNameState.addFieldName(field(fieldDef).oldName); + foreach (var eventDef in type.AllEvents) + variableNameState.addEventName(evt(eventDef).oldName); + foreach (var propDef in type.AllProperties) + variableNameState.addPropertyName(prop(propDef).oldName); + foreach (var methodDef in type.AllMethods) + variableNameState.addMethodName(method(methodDef).oldName); + if (isWinFormsClass()) initializeWindowsFormsFieldsAndProps(); @@ -123,34 +137,32 @@ namespace de4dot.renamer { } void prepareRenameFields() { - var checker = type.Module.ObfuscatedFile.NameChecker; + var checker = NameChecker; if (type.TypeDefinition.IsEnum) { var instanceFields = getInstanceFields(); - if (instanceFields.Count == 1) { - var fieldDef = instanceFields[0]; - rename("value__"); - fieldDef.FieldDefinition.IsRuntimeSpecialName = true; - fieldDef.FieldDefinition.IsSpecialName = true; - } + if (instanceFields.Count == 1) + field(instanceFields[0]).rename("value__"); int i = 0; string nameFormat = hasFlagsAttribute() ? "flag_{0}" : "const_{0}"; foreach (var fieldDef in type.AllFieldsSorted) { - if (renamed) + var fieldInfo = field(fieldDef); + if (fieldInfo.renamed) continue; if (!fieldDef.FieldDefinition.IsStatic || !fieldDef.FieldDefinition.IsLiteral) continue; - if (!checker.isValidFieldName(oldName)) - rename(string.Format(nameFormat, i)); + if (!checker.isValidFieldName(fieldInfo.oldName)) + fieldInfo.rename(string.Format(nameFormat, i)); i++; } } foreach (var fieldDef in type.AllFieldsSorted) { - if (renamed) + var fieldInfo = field(fieldDef); + if (fieldInfo.renamed) continue; - if (!checker.isValidFieldName(oldName)) - rename(variableNameState.getNewFieldName(fieldDef.FieldDefinition)); + if (!checker.isValidFieldName(fieldInfo.oldName)) + fieldInfo.rename(variableNameState.getNewFieldName(fieldDef.FieldDefinition)); } } @@ -172,15 +184,186 @@ namespace de4dot.renamer { } void prepareRenameProperties() { - //TODO: + foreach (var propDef in type.AllPropertiesSorted) { + if (propDef.isVirtual()) + continue; + prepareRenameProperty(propDef); + } + } + + void prepareRenameProperty(PropertyDef propDef) { + if (propDef.isVirtual()) + throw new ApplicationException("Can't rename virtual props here"); + var propInfo = prop(propDef); + if (propInfo.renamed) + return; + + string propName = propInfo.oldName; + if (!NameChecker.isValidPropertyName(propName)) + propName = propInfo.suggestedName; + if (!NameChecker.isValidPropertyName(propName)) + propName = variableNameState.getNewPropertyName(propDef.PropertyDefinition); + variableNameState.addPropertyName(propName); + propInfo.rename(propName); + + renameSpecialMethod(propDef.GetMethod, "get_" + propName); + renameSpecialMethod(propDef.SetMethod, "set_" + propName); } void prepareRenameEvents() { - //TODO: + foreach (var eventDef in type.AllEventsSorted) { + if (eventDef.isVirtual()) + continue; + prepareRenameEvent(eventDef); + } + } + + void prepareRenameEvent(EventDef eventDef) { + if (eventDef.isVirtual()) + throw new ApplicationException("Can't rename virtual events here"); + var eventInfo = evt(eventDef); + if (eventInfo.renamed) + return; + + string eventName = eventInfo.oldName; + if (!NameChecker.isValidEventName(eventName)) + eventName = eventInfo.suggestedName; + if (!NameChecker.isValidEventName(eventName)) + eventName = variableNameState.getNewEventName(eventDef.EventDefinition); + variableNameState.addEventName(eventName); + eventInfo.rename(eventName); + + renameSpecialMethod(eventDef.AddMethod, "add_" + eventName); + renameSpecialMethod(eventDef.RemoveMethod, "remove_" + eventName); + renameSpecialMethod(eventDef.RaiseMethod, "raise_" + eventName); + } + + void renameSpecialMethod(MethodDef methodDef, string newName) { + if (methodDef == null) + return; + if (methodDef.isVirtual()) + return; + renameMethod(methodDef, newName); } void prepareRenameMethods() { - //TODO: + foreach (var methodDef in type.AllMethodsSorted) { + if (methodDef.isVirtual()) + continue; + renameMethod(methodDef); + } + } + + public void prepareRenameMethods2() { + var checker = NameChecker; + foreach (var methodDef in type.AllMethodsSorted) { + prepareRenameMethodArgs(methodDef); + prepareRenameGenericParams(methodDef.GenericParams, checker, methodDef.Owner == null ? null : methodDef.Owner.GenericParams); + } + } + + void prepareRenameMethodArgs(MethodDef methodDef) { + if (methodDef.ParamDefs.Count > 0) { + if (isEventHandler(methodDef)) { + param(methodDef.ParamDefs[0]).newName = "sender"; + param(methodDef.ParamDefs[1]).newName = "e"; + } + else { + var newVariableNameState = variableNameState.clone(); + var checker = NameChecker; + foreach (var paramDef in methodDef.ParamDefs) { + var info = param(paramDef); + if (info.gotNewName()) + continue; + if (!checker.isValidMethodArgName(info.oldName)) + info.newName = newVariableNameState.getNewParamName(info.oldName, paramDef.ParameterDefinition); + } + } + } + + if (methodDef.Property != null && methodDef == methodDef.Property.SetMethod) { + if (methodDef.ParamDefs.Count > 0) { + var paramDef = methodDef.ParamDefs[methodDef.ParamDefs.Count - 1]; + param(paramDef).newName = "value"; + } + } + } + + bool canRenameMethod(MethodDef methodDef) { + var methodInfo = method(methodDef); + if (methodDef.isStatic()) { + if (methodInfo.oldName == ".cctor") + return false; + } + else if (methodDef.isVirtual()) { + if (DotNetUtils.derivesFromDelegate(type.TypeDefinition)) { + switch (methodInfo.oldName) { + case "BeginInvoke": + case "EndInvoke": + case "Invoke": + return false; + } + } + } + else { + if (methodInfo.oldName == ".ctor") + return false; + } + return true; + } + + public void renameMethod(MethodDef methodDef, string methodName) { + if (!canRenameMethod(methodDef)) + return; + var methodInfo = method(methodDef); + variableNameState.addMethodName(methodName); + methodInfo.rename(methodName); + } + + void renameMethod(MethodDef methodDef) { + if (methodDef.isVirtual()) + throw new ApplicationException("Can't rename virtual methods here"); + if (!canRenameMethod(methodDef)) + return; + + var info = method(methodDef); + if (info.renamed) + return; + info.renamed = true; + var checker = NameChecker; + + if (!NameChecker.isValidMethodName(info.oldName)) { + INameCreator nameCreator = null; + string newName = info.suggestedName; + if (methodDef.MethodDefinition.PInvokeInfo != null) + newName = getPinvokeName(methodDef); + else if (methodDef.isStatic()) + nameCreator = variableNameState.staticMethodNameCreator; + else + nameCreator = variableNameState.instanceMethodNameCreator; + if (newName != null) + nameCreator = new NameCreator2(newName); + renameMethod(methodDef, variableNameState.getNewMethodName(info.oldName, nameCreator)); + } + } + + string getPinvokeName(MethodDef methodDef) { + var entryPoint = methodDef.MethodDefinition.PInvokeInfo.EntryPoint; + if (Regex.IsMatch(entryPoint, @"^#\d+$")) + entryPoint = DotNetUtils.getDllName(methodDef.MethodDefinition.PInvokeInfo.Module.Name) + "_" + entryPoint.Substring(1); + return entryPoint; + } + + static bool isEventHandler(MethodDef methodDef) { + if (methodDef.MethodDefinition.Parameters.Count != 2) + return false; + if (methodDef.MethodDefinition.MethodReturnType.ReturnType.FullName != "System.Void") + return false; + if (methodDef.MethodDefinition.Parameters[0].ParameterType.FullName != "System.Object") + return false; + if (!methodDef.MethodDefinition.Parameters[1].ParameterType.FullName.Contains("EventArgs")) + return false; + return true; } void prepareRenameGenericParams(IEnumerable genericParams, INameChecker checker, IEnumerable otherGenericParams = null) { @@ -208,7 +391,7 @@ namespace de4dot.renamer { } void initializeWindowsFormsFieldsAndProps() { - var checker = type.Module.ObfuscatedFile.NameChecker; + var checker = NameChecker; var ourFields = new Dictionary(); foreach (var fieldDef in type.AllFields) @@ -309,7 +492,7 @@ namespace de4dot.renamer { // VB initializes the handlers in the property setter, where it first removes the handler // from the previous control, and then adds the handler to the new control. void initVbEventHandlers(Dictionary ourFields, Dictionary ourMethods) { - var checker = type.Module.ObfuscatedFile.NameChecker; + var checker = NameChecker; foreach (var propDef in type.AllProperties) { var setter = propDef.PropertyDefinition.SetMethod; @@ -426,7 +609,7 @@ namespace de4dot.renamer { } void initFieldEventHandlers(Dictionary ourFields, Dictionary ourMethods) { - var checker = type.Module.ObfuscatedFile.NameChecker; + var checker = NameChecker; foreach (var methodDef in type.AllMethods) { if (methodDef.MethodDefinition.Body == null) @@ -505,7 +688,7 @@ namespace de4dot.renamer { } void initTypeEventHandlers(Dictionary ourFields, Dictionary ourMethods) { - var checker = type.Module.ObfuscatedFile.NameChecker; + var checker = NameChecker; foreach (var methodDef in type.AllMethods) { if (methodDef.MethodDefinition.Body == null) diff --git a/de4dot.code/renamer/TypeRenamerState.cs b/de4dot.code/renamer/TypeRenamerState.cs index 8da9671b..5d73b43b 100644 --- a/de4dot.code/renamer/TypeRenamerState.cs +++ b/de4dot.code/renamer/TypeRenamerState.cs @@ -36,6 +36,10 @@ namespace de4dot.renamer { internalTypeNameCreator = new TypeNameCreator(existingNames); } + public void addTypeName(string name) { + existingNames.add(name); + } + public string getTypeName(string oldName, string newName) { return existingNames.getName(oldName, new NameCreator2(newName)); } diff --git a/de4dot.code/renamer/VariableNameState.cs b/de4dot.code/renamer/VariableNameState.cs index 6631f107..86578c80 100644 --- a/de4dot.code/renamer/VariableNameState.cs +++ b/de4dot.code/renamer/VariableNameState.cs @@ -22,7 +22,15 @@ using Mono.Cecil; namespace de4dot.renamer { class VariableNameState { ExistingNames existingVariableNames = new ExistingNames(); + ExistingNames existingMethodNames = new ExistingNames(); + ExistingNames existingPropertyNames = new ExistingNames(); + ExistingNames existingEventNames = new ExistingNames(); TypeNames variableNameCreator = new VariableNameCreator(); // For fields and method args + TypeNames propertyNameCreator = new PropertyNameCreator(); + INameCreator eventNameCreator = new NameCreator("Event_"); + INameCreator genericPropertyNameCreator = new NameCreator("Prop_"); + public INameCreator staticMethodNameCreator = new NameCreator("smethod_"); + public INameCreator instanceMethodNameCreator = new NameCreator("method_"); public virtual VariableNameState clone() { var rv = new VariableNameState(); @@ -31,14 +39,67 @@ namespace de4dot.renamer { } void cloneInit(VariableNameState variableNameState) { - variableNameState.existingVariableNames = new ExistingNames(); + variableNameState.existingVariableNames = existingVariableNames.clone(); + variableNameState.existingMethodNames = existingMethodNames.clone(); + variableNameState.existingPropertyNames = existingPropertyNames.clone(); + variableNameState.existingEventNames = existingEventNames.clone(); variableNameState.variableNameCreator = variableNameCreator.clone(); + variableNameState.propertyNameCreator = propertyNameCreator.clone(); + variableNameState.eventNameCreator = eventNameCreator.clone(); + variableNameState.genericPropertyNameCreator = genericPropertyNameCreator.clone(); + variableNameState.staticMethodNameCreator = staticMethodNameCreator.clone(); + variableNameState.instanceMethodNameCreator = instanceMethodNameCreator.clone(); + } + + public string getNewPropertyName(PropertyDefinition propertyDefinition) { + var propType = propertyDefinition.PropertyType; + string newName; + if (propType is GenericParameter) + newName = genericPropertyNameCreator.create(); + else + newName = propertyNameCreator.create(propType); + addPropertyName(newName); + return newName; + } + + public string getNewEventName(EventDefinition eventDefinition) { + string newName = eventNameCreator.create(); + addEventName(newName); + return newName; } public void addFieldName(string fieldName) { existingVariableNames.add(fieldName); } + public void addParamName(string paramName) { + existingVariableNames.add(paramName); + } + + public void addMethodName(string methodName) { + existingMethodNames.add(methodName); + } + + public void addPropertyName(string propName) { + existingPropertyNames.add(propName); + } + + public void addEventName(string eventName) { + existingEventNames.add(eventName); + } + + public bool isMethodNameUsed(string methodName) { + return existingMethodNames.exists(methodName); + } + + public bool isPropertyNameUsed(string propName) { + return existingPropertyNames.exists(propName); + } + + public bool isEventNameUsed(string eventName) { + return existingEventNames.exists(eventName); + } + public string getNewFieldName(FieldDefinition field) { return existingVariableNames.getName(field.Name, () => variableNameCreator.create(field.FieldType)); } @@ -46,5 +107,13 @@ namespace de4dot.renamer { public string getNewFieldName(string oldName, INameCreator nameCreator) { return existingVariableNames.getName(oldName, () => nameCreator.create()); } + + public string getNewParamName(string oldName, ParameterDefinition param) { + return existingVariableNames.getName(oldName, () => variableNameCreator.create(param.ParameterType)); + } + + public string getNewMethodName(string oldName, INameCreator nameCreator) { + return existingMethodNames.getName(oldName, nameCreator); + } } } diff --git a/de4dot.code/renamer/asmmodules/EventDef.cs b/de4dot.code/renamer/asmmodules/EventDef.cs index fcae2f11..17e5fe71 100644 --- a/de4dot.code/renamer/asmmodules/EventDef.cs +++ b/de4dot.code/renamer/asmmodules/EventDef.cs @@ -22,6 +22,10 @@ using Mono.Cecil; namespace de4dot.renamer.asmmodules { class EventDef : Ref { + public MethodDef AddMethod { get; set; } + public MethodDef RemoveMethod { get; set; } + public MethodDef RaiseMethod { get; set; } + public EventDefinition EventDefinition { get { return (EventDefinition)memberReference; } } diff --git a/de4dot.code/renamer/asmmodules/MethodNameScopes.cs b/de4dot.code/renamer/asmmodules/MethodNameScopes.cs index b4b9496c..96b37d32 100644 --- a/de4dot.code/renamer/asmmodules/MethodNameScopes.cs +++ b/de4dot.code/renamer/asmmodules/MethodNameScopes.cs @@ -42,6 +42,54 @@ namespace de4dot.renamer.asmmodules { methods.AddRange(other.methods); } + public bool hasNonRenamableMethod() { + foreach (var method in methods) { + if (!method.Owner.HasModule) + return true; + } + return false; + } + + public bool hasInterfaceMethod() { + foreach (var method in methods) { + if (method.Owner.TypeDefinition.IsInterface) + return true; + } + return false; + } + + public bool hasPropertyMethod() { + foreach (var method in methods) { + if (method.Property != null) + return true; + } + return false; + } + + public bool hasEventMethod() { + foreach (var method in methods) { + if (method.Event != null) + return true; + } + return false; + } + + public bool hasProperty() { + foreach (var method in methods) { + if (method.Property != null) + return true; + } + return false; + } + + public bool hasEvent() { + foreach (var method in methods) { + if (method.Event != null) + return true; + } + return false; + } + public override string ToString() { return string.Format("{0} -- {1}", methods.Count, methods.Count > 0 ? methods[0].ToString() : ""); } @@ -58,7 +106,7 @@ namespace de4dot.renamer.asmmodules { get(methodDef); } - MethodNameScope get(MethodDef method) { + public MethodNameScope get(MethodDef method) { if (!method.isVirtual()) throw new ApplicationException("Not a virtual method"); MethodNameScope scope; diff --git a/de4dot.code/renamer/asmmodules/Module.cs b/de4dot.code/renamer/asmmodules/Module.cs index 0488944a..07338d79 100644 --- a/de4dot.code/renamer/asmmodules/Module.cs +++ b/de4dot.code/renamer/asmmodules/Module.cs @@ -30,6 +30,7 @@ namespace de4dot.renamer.asmmodules { IList> typeRefsToRename = new List>(); IList> methodRefsToRename = new List>(); IList> fieldRefsToRename = new List>(); + List allMethods; public class RefToDef where R : MemberReference where D : R { public R reference; @@ -72,9 +73,14 @@ namespace de4dot.renamer.asmmodules { return types.getAll(); } + public IEnumerable getAllMethods() { + return allMethods; + } + public void findAllMemberReferences(ref int typeIndex) { memberRefFinder = new MemberRefFinder(); memberRefFinder.findAll(ModuleDefinition, ModuleDefinition.Types); + allMethods = new List(memberRefFinder.methodDefinitions.Keys); var allTypesList = new List(); foreach (var type in memberRefFinder.typeDefinitions.Keys) { diff --git a/de4dot.code/renamer/asmmodules/Modules.cs b/de4dot.code/renamer/asmmodules/Modules.cs index 09d20106..6b9efd0a 100644 --- a/de4dot.code/renamer/asmmodules/Modules.cs +++ b/de4dot.code/renamer/asmmodules/Modules.cs @@ -256,10 +256,11 @@ namespace de4dot.renamer.asmmodules { return otherTypesDict[key] = typeDef; } - public void initializeVirtualMembers() { + public MethodNameScopes initializeVirtualMembers() { var scopes = new MethodNameScopes(); foreach (var typeDef in allTypes) typeDef.initializeVirtualMembers(scopes, this); + return scopes; } public void onTypesRenamed() { diff --git a/de4dot.code/renamer/asmmodules/PropertyDef.cs b/de4dot.code/renamer/asmmodules/PropertyDef.cs index 446203e0..8edb2800 100644 --- a/de4dot.code/renamer/asmmodules/PropertyDef.cs +++ b/de4dot.code/renamer/asmmodules/PropertyDef.cs @@ -22,6 +22,9 @@ using Mono.Cecil; namespace de4dot.renamer.asmmodules { class PropertyDef : Ref { + public MethodDef GetMethod { get; set; } + public MethodDef SetMethod { get; set; } + public PropertyDefinition PropertyDefinition { get { return (PropertyDefinition)memberReference; } } diff --git a/de4dot.code/renamer/asmmodules/RefDict.cs b/de4dot.code/renamer/asmmodules/RefDict.cs index f9a126dc..9c4cb741 100644 --- a/de4dot.code/renamer/asmmodules/RefDict.cs +++ b/de4dot.code/renamer/asmmodules/RefDict.cs @@ -23,6 +23,7 @@ using de4dot.blocks; namespace de4dot.renamer.asmmodules { interface RefDict where TRef : Ref where TMRef : MemberReference { + int Count { get; } IEnumerable getAll(); IEnumerable getSorted(); TRef find(TMRef tmref); @@ -34,17 +35,17 @@ namespace de4dot.renamer.asmmodules { Dictionary tokenToTypeDef = new Dictionary(); Dictionary typeRefToDef = new Dictionary(); + public int Count { + get { return tokenToTypeDef.Count; } + } + 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; - }); + list.Sort((a, b) => Utils.compareInt32(a.Index, b.Index)); return list; } @@ -74,17 +75,17 @@ namespace de4dot.renamer.asmmodules { Dictionary tokenToFieldDef = new Dictionary(); Dictionary fieldRefToDef = new Dictionary(); + public int Count { + get { return tokenToFieldDef.Count; } + } + 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; - }); + list.Sort((a, b) => Utils.compareInt32(a.Index, b.Index)); return list; } @@ -114,17 +115,17 @@ namespace de4dot.renamer.asmmodules { Dictionary tokenToMethodDef = new Dictionary(); Dictionary methodRefToDef = new Dictionary(); + public int Count { + get { return tokenToMethodDef.Count; } + } + 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; - }); + list.Sort((a, b) => Utils.compareInt32(a.Index, b.Index)); return list; } @@ -152,6 +153,11 @@ namespace de4dot.renamer.asmmodules { class PropertyDefDict : RefDict { Dictionary tokenToPropDef = new Dictionary(); + Dictionary propRefToDef = new Dictionary(); + + public int Count { + get { return tokenToPropDef.Count; } + } public IEnumerable getAll() { return tokenToPropDef.Values; @@ -159,30 +165,39 @@ namespace de4dot.renamer.asmmodules { 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; - }); + list.Sort((a, b) => Utils.compareInt32(a.Index, b.Index)); return list; } public PropertyDef find(PropertyReference propertyReference) { PropertyDef propDef; - tokenToPropDef.TryGetValue(new ScopeAndTokenKey(propertyReference), out propDef); + if (tokenToPropDef.TryGetValue(new ScopeAndTokenKey(propertyReference), out propDef)) + return propDef; + + propRefToDef.TryGetValue(new PropertyReferenceKey(propertyReference), out propDef); return propDef; } public void add(PropertyDef propDef) { tokenToPropDef[new ScopeAndTokenKey(propDef.PropertyDefinition)] = propDef; + propRefToDef[new PropertyReferenceKey(propDef.PropertyDefinition)] = propDef; } public void onTypesRenamed() { + var all = new List(propRefToDef.Values); + propRefToDef.Clear(); + foreach (var propDef in all) + propRefToDef[new PropertyReferenceKey(propDef.PropertyDefinition)] = propDef; } } class EventDefDict : RefDict { Dictionary tokenToEventDef = new Dictionary(); + Dictionary eventRefToDef = new Dictionary(); + + public int Count { + get { return tokenToEventDef.Count; } + } public IEnumerable getAll() { return tokenToEventDef.Values; @@ -190,25 +205,29 @@ namespace de4dot.renamer.asmmodules { 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; - }); + list.Sort((a, b) => Utils.compareInt32(a.Index, b.Index)); return list; } public EventDef find(EventReference eventReference) { EventDef eventDef; - tokenToEventDef.TryGetValue(new ScopeAndTokenKey(eventReference), out eventDef); + if (tokenToEventDef.TryGetValue(new ScopeAndTokenKey(eventReference), out eventDef)) + return eventDef; + + eventRefToDef.TryGetValue(new EventReferenceKey(eventReference), out eventDef); return eventDef; } public void add(EventDef eventDef) { tokenToEventDef[new ScopeAndTokenKey(eventDef.EventDefinition)] = eventDef; + eventRefToDef[new EventReferenceKey(eventDef.EventDefinition)] = eventDef; } public void onTypesRenamed() { + var all = new List(eventRefToDef.Values); + eventRefToDef.Clear(); + foreach (var eventDef in all) + eventRefToDef[new EventReferenceKey(eventDef.EventDefinition)] = eventDef; } } } diff --git a/de4dot.code/renamer/asmmodules/TypeDef.cs b/de4dot.code/renamer/asmmodules/TypeDef.cs index aa79ba24..7bf333f5 100644 --- a/de4dot.code/renamer/asmmodules/TypeDef.cs +++ b/de4dot.code/renamer/asmmodules/TypeDef.cs @@ -219,6 +219,7 @@ namespace de4dot.renamer.asmmodules { get { return module; } } + // Returns false if this is a type from a dependency (non-renamble) assembly (eg. mscorlib) public bool HasModule { get { return module != null; } } @@ -315,6 +316,20 @@ namespace de4dot.renamer.asmmodules { return fields.find(fr); } + public PropertyDef find(PropertyReference pr) { + return properties.find(pr); + } + + public PropertyDef create(PropertyDefinition newProp) { + if (find(newProp) != null) + throw new ApplicationException("Can't add a property when it's already been added"); + + var propDef = new PropertyDef(newProp, this, properties.Count); + add(propDef); + TypeDefinition.Properties.Add(newProp); + return propDef; + } + public void addMembers() { var type = TypeDefinition; @@ -333,6 +348,10 @@ namespace de4dot.renamer.asmmodules { if (methodDef == null) throw new ApplicationException("Could not find property method"); methodDef.Property = propDef; + if (method == propDef.PropertyDefinition.GetMethod) + propDef.GetMethod = methodDef; + if (method == propDef.PropertyDefinition.SetMethod) + propDef.SetMethod = methodDef; } } @@ -342,12 +361,19 @@ namespace de4dot.renamer.asmmodules { if (methodDef == null) throw new ApplicationException("Could not find event method"); methodDef.Event = eventDef; + if (method == eventDef.EventDefinition.AddMethod) + eventDef.AddMethod = methodDef; + if (method == eventDef.EventDefinition.RemoveMethod) + eventDef.RemoveMethod = methodDef; + if (method == eventDef.EventDefinition.InvokeMethod) + eventDef.RaiseMethod = methodDef; } } } public void onTypesRenamed() { events.onTypesRenamed(); + properties.onTypesRenamed(); fields.onTypesRenamed(); methods.onTypesRenamed(); types.onTypesRenamed();