/* 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 System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; using de4dot.blocks; using de4dot.deobfuscators; namespace de4dot.renamer { abstract class Ref { public string NewName { get; set; } public string OldName { get; private set; } public string OldFullName { get; private set; } public int Index { get; private set; } public MemberReference MemberReference { get; private set; } public TypeDef Owner { get; set; } public bool Renamed { get; set; } public Ref(MemberReference mr, TypeDef owner, int index) { MemberReference = mr; NewName = OldName = mr.Name; OldFullName = mr.FullName; Owner = owner; Index = index; } public bool gotNewName() { return NewName != OldName; } public abstract bool isSame(MemberReference mr); public bool rename(string newName) { if (Renamed) return false; Renamed = true; NewName = newName; return true; } static protected bool isVirtual(MethodDefinition m) { return m != null && m.IsVirtual; } protected static IList createGenericParamDefList(IEnumerable parameters) { var list = new List(); if (parameters == null) return list; int i = 0; foreach (var param in parameters) list.Add(new GenericParamDef(param, i++)); return list; } public override string ToString() { return MemberReference != null ? MemberReference.ToString() : null; } } class FieldDef : Ref { public FieldDef(FieldDefinition fieldDefinition, TypeDef owner, int index) : base(fieldDefinition, owner, index) { } public FieldDefinition FieldDefinition { get { return (FieldDefinition)MemberReference; } } public override bool isSame(MemberReference mr) { return MemberReferenceHelper.compareFieldReference(FieldDefinition, mr as FieldReference); } } class EventRef : Ref { public EventRef(EventReference eventReference, TypeDef owner, int index) : base(eventReference, owner, index) { } public EventReference EventReference { get { return (EventReference)MemberReference; } } public override bool isSame(MemberReference mr) { return MemberReferenceHelper.compareEventReference(EventReference, mr as EventReference); } } class EventDef : EventRef { public EventDef(EventDefinition eventDefinition, TypeDef owner, int index) : base(eventDefinition, owner, index) { } public EventDefinition EventDefinition { get { return (EventDefinition)MemberReference; } } 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; } } // Returns one of the overridden methods or null if none found public MethodReference getOverrideMethod() { foreach (var method in methodDefinitions()) { if (method.HasOverrides) return method.Overrides[0]; } return null; } public bool isVirtual() { foreach (var method in methodDefinitions()) { if (isVirtual(method)) return true; } return false; } } class PropertyRef : Ref { public PropertyRef(PropertyReference propertyReference, TypeDef owner, int index) : base(propertyReference, owner, index) { } public PropertyReference PropertyReference { get { return (PropertyReference)MemberReference; } } public override bool isSame(MemberReference mr) { return MemberReferenceHelper.comparePropertyReference(PropertyReference, mr as PropertyReference); } } class PropertyDef : PropertyRef { public PropertyDef(PropertyDefinition propertyDefinition, TypeDef owner, int index) : base(propertyDefinition, owner, index) { } public PropertyDefinition PropertyDefinition { get { return (PropertyDefinition)MemberReference; } } 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; } } // Returns one of the overridden methods or null if none found public MethodReference getOverrideMethod() { foreach (var method in methodDefinitions()) { if (method.HasOverrides) return method.Overrides[0]; } return null; } public bool isVirtual() { foreach (var method in methodDefinitions()) { if (isVirtual(method)) return true; } return false; } } class MethodRef : Ref { public IList paramDefs = new List(); public IList ParamDefs { get { return paramDefs; } } public MethodRef(MethodReference methodReference, TypeDef owner, int index) : base(methodReference, owner, index) { if (methodReference.HasParameters) { for (int i = 0; i < methodReference.Parameters.Count; i++) { var param = methodReference.Parameters[i]; paramDefs.Add(new ParamDef(param, i)); } } } public MethodReference MethodReference { get { return (MethodReference)MemberReference; } } public override bool isSame(MemberReference mr) { return MemberReferenceHelper.compareMethodReference(MethodReference, mr as MethodReference); } } class MethodDef : MethodRef { IList genericParams; public IList GenericParams { get { return genericParams; } } public PropertyDef Property { get; set; } public EventDef Event { get; set; } public MethodDef(MethodDefinition methodDefinition, TypeDef owner, int index) : base(methodDefinition, owner, index) { genericParams = createGenericParamDefList(MethodDefinition.GenericParameters); } public MethodDefinition MethodDefinition { get { return (MethodDefinition)MemberReference; } } public bool isVirtual() { return isVirtual(MethodDefinition); } } class ParamDef { public ParameterDefinition ParameterDefinition { get; set; } public string OldName { get; private set; } public string NewName { get; set; } public int Index { get; private set; } public bool Renamed { get; set; } public ParamDef(ParameterDefinition parameterDefinition, int index) { this.ParameterDefinition = parameterDefinition; NewName = OldName = parameterDefinition.Name; Index = index; } public bool gotNewName() { return NewName != OldName; } } class GenericParamDef : Ref { public GenericParamDef(GenericParameter genericParameter, int index) : base(genericParameter, null, index) { } public GenericParameter GenericParameter { get { return (GenericParameter)MemberReference; } } public override bool isSame(MemberReference mr) { throw new NotImplementedException(); } } class TypeInfo { public TypeReference typeReference; public TypeDef typeDef; public TypeInfo(TypeReference typeReference, TypeDef typeDef) { this.typeReference = typeReference; this.typeDef = typeDef; } } class TypeDef : Ref { static Dictionary windowsFormsControlClasses = new Dictionary(StringComparer.Ordinal); static TypeDef() { windowsFormsControlClasses["System.Windows.Forms.Control"] = true; windowsFormsControlClasses["System.Windows.Forms.AxHost"] = true; windowsFormsControlClasses["System.Windows.Forms.ButtonBase"] = true; windowsFormsControlClasses["System.Windows.Forms.Button"] = true; windowsFormsControlClasses["System.Windows.Forms.CheckBox"] = true; windowsFormsControlClasses["System.Windows.Forms.RadioButton"] = true; windowsFormsControlClasses["System.Windows.Forms.DataGrid"] = true; windowsFormsControlClasses["System.Windows.Forms.DataGridView"] = true; windowsFormsControlClasses["System.Windows.Forms.DataVisualization.Charting.Chart"] = true; windowsFormsControlClasses["System.Windows.Forms.DateTimePicker"] = true; windowsFormsControlClasses["System.Windows.Forms.GroupBox"] = true; windowsFormsControlClasses["System.Windows.Forms.Integration.ElementHost"] = true; windowsFormsControlClasses["System.Windows.Forms.Label"] = true; windowsFormsControlClasses["System.Windows.Forms.LinkLabel"] = true; windowsFormsControlClasses["System.Windows.Forms.ListControl"] = true; windowsFormsControlClasses["System.Windows.Forms.ComboBox"] = true; windowsFormsControlClasses["Microsoft.VisualBasic.Compatibility.VB6.DriveListBox"] = true; windowsFormsControlClasses["System.Windows.Forms.DataGridViewComboBoxEditingControl"] = true; windowsFormsControlClasses["System.Windows.Forms.ListBox"] = true; windowsFormsControlClasses["Microsoft.VisualBasic.Compatibility.VB6.DirListBox"] = true; windowsFormsControlClasses["Microsoft.VisualBasic.Compatibility.VB6.FileListBox"] = true; windowsFormsControlClasses["System.Windows.Forms.CheckedListBox"] = true; windowsFormsControlClasses["System.Windows.Forms.ListView"] = true; windowsFormsControlClasses["System.Windows.Forms.MdiClient"] = true; windowsFormsControlClasses["System.Windows.Forms.MonthCalendar"] = true; windowsFormsControlClasses["System.Windows.Forms.PictureBox"] = true; windowsFormsControlClasses["System.Windows.Forms.PrintPreviewControl"] = true; windowsFormsControlClasses["System.Windows.Forms.ProgressBar"] = true; windowsFormsControlClasses["System.Windows.Forms.ScrollableControl"] = true; windowsFormsControlClasses["System.Windows.Forms.ContainerControl"] = true; windowsFormsControlClasses["System.Windows.Forms.Form"] = true; windowsFormsControlClasses["System.ComponentModel.Design.CollectionEditor.CollectionForm"] = true; windowsFormsControlClasses["System.Messaging.Design.QueuePathDialog"] = true; windowsFormsControlClasses["System.ServiceProcess.Design.ServiceInstallerDialog"] = true; windowsFormsControlClasses["System.Web.UI.Design.WebControls.CalendarAutoFormatDialog"] = true; windowsFormsControlClasses["System.Web.UI.Design.WebControls.RegexEditorDialog"] = true; windowsFormsControlClasses["System.Windows.Forms.Design.ComponentEditorForm"] = true; windowsFormsControlClasses["System.Windows.Forms.PrintPreviewDialog"] = true; windowsFormsControlClasses["System.Windows.Forms.ThreadExceptionDialog"] = true; windowsFormsControlClasses["System.Workflow.Activities.Rules.Design.RuleConditionDialog"] = true; windowsFormsControlClasses["System.Workflow.Activities.Rules.Design.RuleSetDialog"] = true; windowsFormsControlClasses["System.Workflow.ComponentModel.Design.ThemeConfigurationDialog"] = true; windowsFormsControlClasses["System.Workflow.ComponentModel.Design.TypeBrowserDialog"] = true; windowsFormsControlClasses["System.Workflow.ComponentModel.Design.WorkflowPageSetupDialog"] = true; windowsFormsControlClasses["System.Windows.Forms.PropertyGrid"] = true; windowsFormsControlClasses["System.Windows.Forms.SplitContainer"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStripContainer"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStripPanel"] = true; windowsFormsControlClasses["System.Windows.Forms.UpDownBase"] = true; windowsFormsControlClasses["System.Windows.Forms.DomainUpDown"] = true; windowsFormsControlClasses["System.Windows.Forms.NumericUpDown"] = true; windowsFormsControlClasses["System.Windows.Forms.UserControl"] = true; windowsFormsControlClasses["Microsoft.VisualBasic.Compatibility.VB6.ADODC"] = true; windowsFormsControlClasses["System.Web.UI.Design.WebControls.ParameterEditorUserControl"] = true; windowsFormsControlClasses["System.Workflow.ComponentModel.Design.WorkflowOutline"] = true; windowsFormsControlClasses["System.Workflow.ComponentModel.Design.WorkflowView"] = true; windowsFormsControlClasses["System.Windows.Forms.Design.ComponentTray"] = true; windowsFormsControlClasses["System.Windows.Forms.Panel"] = true; windowsFormsControlClasses["System.Windows.Forms.Design.ComponentEditorPage"] = true; windowsFormsControlClasses["System.Windows.Forms.FlowLayoutPanel"] = true; windowsFormsControlClasses["System.Windows.Forms.SplitterPanel"] = true; windowsFormsControlClasses["System.Windows.Forms.TableLayoutPanel"] = true; windowsFormsControlClasses["System.ComponentModel.Design.ByteViewer"] = true; windowsFormsControlClasses["System.Windows.Forms.TabPage"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStripContentPanel"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStrip"] = true; windowsFormsControlClasses["System.Windows.Forms.BindingNavigator"] = true; windowsFormsControlClasses["System.Windows.Forms.MenuStrip"] = true; windowsFormsControlClasses["System.Windows.Forms.StatusStrip"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStripDropDown"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStripDropDownMenu"] = true; windowsFormsControlClasses["System.Windows.Forms.ContextMenuStrip"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolStripOverflow"] = true; windowsFormsControlClasses["System.Windows.Forms.ScrollBar"] = true; windowsFormsControlClasses["System.Windows.Forms.HScrollBar"] = true; windowsFormsControlClasses["System.Windows.Forms.VScrollBar"] = true; windowsFormsControlClasses["System.Windows.Forms.Splitter"] = true; windowsFormsControlClasses["System.Windows.Forms.StatusBar"] = true; windowsFormsControlClasses["System.Windows.Forms.TabControl"] = true; windowsFormsControlClasses["System.Windows.Forms.TextBoxBase"] = true; windowsFormsControlClasses["System.Windows.Forms.MaskedTextBox"] = true; windowsFormsControlClasses["System.Windows.Forms.RichTextBox"] = true; windowsFormsControlClasses["System.Windows.Forms.TextBox"] = true; windowsFormsControlClasses["System.Windows.Forms.DataGridTextBox"] = true; windowsFormsControlClasses["System.Windows.Forms.DataGridViewTextBoxEditingControl"] = true; windowsFormsControlClasses["System.Windows.Forms.ToolBar"] = true; windowsFormsControlClasses["System.Windows.Forms.TrackBar"] = true; windowsFormsControlClasses["System.Windows.Forms.TreeView"] = true; windowsFormsControlClasses["System.ComponentModel.Design.ObjectSelectorEditor.Selector"] = true; windowsFormsControlClasses["System.Windows.Forms.WebBrowserBase"] = true; windowsFormsControlClasses["System.Windows.Forms.WebBrowser"] = true; } Dictionary newMethodsNames = new Dictionary(); public IDefFinder defFinder; public TypeInfo baseType = null; public IList interfaces = new List(); // directly implemented interfaces public IList derivedTypes = new List(); public Module module; string newNamespace = null; EventDefDict events = new EventDefDict(); FieldDefDict fields = new FieldDefDict(); MethodDefDict methods = new MethodDefDict(); PropertyDefDict properties = new PropertyDefDict(); TypeDefDict types = new TypeDefDict(); IList genericParams; public TypeDefinition TypeDefinition { get { return (TypeDefinition)MemberReference; } } public MemberRenameState MemberRenameState { get; set; } public MemberRenameState InterfaceScopeState { get; set; } bool prepareRenameMembersCalled = false; public IEnumerable NestedTypes { get { return types.getSorted(); } } public TypeDef NestingType { get; set; } public IList GenericParams { get { return genericParams; } } public bool IsRenamable { get { return module != null; } } bool IsDelegate { get; set; } public TypeDef(TypeDefinition typeDefinition) : this(typeDefinition, null) { } public TypeDef(TypeDefinition typeDefinition, Module module, int index = 0) : base(typeDefinition, null, index) { this.module = module; genericParams = createGenericParamDefList(TypeDefinition.GenericParameters); } public override bool isSame(MemberReference mr) { return MemberReferenceHelper.compareTypes(TypeDefinition, mr as TypeReference); } public bool isInterface() { return TypeDefinition.IsInterface; } public IEnumerable Methods { get { return methods.getAll(); } } bool? isWindowsFormsControlDerivedClass_cached; bool isWindowsFormsControlDerivedClass() { if (!isWindowsFormsControlDerivedClass_cached.HasValue) isWindowsFormsControlDerivedClass_cached = isWindowsFormsControlDerivedClassInternal(); return isWindowsFormsControlDerivedClass_cached.Value; } bool isWindowsFormsControlDerivedClassInternal() { if (windowsFormsControlClasses.ContainsKey(OldFullName)) return true; if (baseType != null) return baseType.typeDef.isWindowsFormsControlDerivedClass(); if (TypeDefinition.BaseType != null) return windowsFormsControlClasses.ContainsKey(TypeDefinition.BaseType.FullName); return false; } 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)); foreach (var propDef in properties.getAll()) { foreach (var method in propDef.methodDefinitions()) { var methodDef = find(method); if (methodDef == null) throw new ApplicationException("Could not find property method"); methodDef.Property = propDef; } } foreach (var eventDef in events.getAll()) { foreach (var method in eventDef.methodDefinitions()) { var methodDef = find(method); if (methodDef == null) throw new ApplicationException("Could not find event method"); methodDef.Event = eventDef; } } } 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); IsDelegate = baseRef.FullName == "System.Delegate" || baseRef.FullName == "System.MulticastDelegate"; } // Called when all types have been renamed public void onTypesRenamed() { events.onTypesRenamed(); fields.onTypesRenamed(); methods.onTypesRenamed(); types.onTypesRenamed(); } public IEnumerable getAllInterfaces() { if (isInterface()) yield return this; foreach (var ifaceInfo in interfaces) { foreach (var iface in ifaceInfo.typeDef.getAllInterfaces()) yield return iface; } foreach (var typeDef in derivedTypes) { foreach (var iface in typeDef.getAllInterfaces()) yield return iface; } } public IEnumerable getAllRenamableInterfaces() { foreach (var iface in getAllInterfaces()) { if (iface.IsRenamable) yield return iface; } } 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); } IEnumerable getInstanceFields() { foreach (var fieldDef in fields.getSorted()) { if (!fieldDef.FieldDefinition.IsStatic) yield return fieldDef; } } bool isNested() { return NestingType != null; } bool isGlobalType() { if (!isNested()) return TypeDefinition.IsPublic; var mask = TypeDefinition.Attributes & TypeAttributes.VisibilityMask; switch (mask) { case TypeAttributes.NestedPrivate: case TypeAttributes.NestedAssembly: case TypeAttributes.NestedFamANDAssem: return false; case TypeAttributes.NestedPublic: case TypeAttributes.NestedFamily: case TypeAttributes.NestedFamORAssem: return NestingType.isGlobalType(); default: return false; } } // Renames name, namespace, and generic parameters if needed. Does not rename members. public void prepareRename(TypeNameState typeNameState) { var typeDefinition = TypeDefinition; ITypeNameCreator nameCreator = isGlobalType() ? typeNameState.globalTypeNameCreator : typeNameState.internalTypeNameCreator; if (OldFullName != "" && !typeNameState.IsValidName(OldName)) { var newBaseType = baseType != null && baseType.typeDef.Renamed ? baseType.typeDef.NewName : null; string origClassName = null; if (isWindowsFormsControlDerivedClass()) origClassName = findWindowsFormsClassName(); if (origClassName != null && typeNameState.IsValidName(origClassName)) rename(typeNameState.currentNames.newName(OldName, new NameCreator2(origClassName))); else rename(nameCreator.newName(typeDefinition, newBaseType)); } if (typeDefinition.Namespace != "" && !typeNameState.isValidNamespace(typeDefinition.Namespace)) newNamespace = typeNameState.newNamespace(typeDefinition.Namespace); prepareRenameGenericParams(genericParams, typeNameState.IsValidName); } string findWindowsFormsClassName() { foreach (var methodDef in methods.getAll()) { if (methodDef.MethodDefinition.Body == null) continue; if (methodDef.MethodDefinition.IsStatic || methodDef.MethodDefinition.IsVirtual) continue; var instructions = methodDef.MethodDefinition.Body.Instructions; for (int i = 2; i < instructions.Count; i++) { var call = instructions[i]; if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; if (!isWindowsFormsSetNameMethod(call.Operand as MethodReference)) continue; var ldstr = instructions[i - 1]; if (ldstr.OpCode.Code != Code.Ldstr) continue; var className = ldstr.Operand as string; if (className == null) continue; if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, instructions[i - 2]) != 0) continue; findInitializeComponentMethod(methodDef); return className; } } return null; } void findInitializeComponentMethod(MethodDef possibleInitMethod) { foreach (var methodDef in methods.getAll()) { if (methodDef.OldName != ".ctor") continue; if (methodDef.MethodDefinition.Body == null) continue; foreach (var instr in methodDef.MethodDefinition.Body.Instructions) { if (instr.OpCode.Code != Code.Call) continue; if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(possibleInitMethod.MethodDefinition, instr.Operand as MethodReference)) continue; newMethodsNames[possibleInitMethod] = "InitializeComponent"; return; } } } static bool isWindowsFormsSetNameMethod(MethodReference method) { if (method == null) return false; if (method.Name != "set_Name") return false; if (method.MethodReturnType.ReturnType.FullName != "System.Void") return false; if (method.Parameters.Count != 1) return false; if (method.Parameters[0].ParameterType.FullName != "System.String") return false; if (!method.DeclaringType.FullName.StartsWith("System.Windows.Forms.", StringComparison.Ordinal)) return false; return true; } public void rename() { var typeDefinition = TypeDefinition; Log.v("Type: {0} ({1:X8})", TypeDefinition.FullName, TypeDefinition.MetadataToken.ToUInt32()); Log.indent(); renameGenericParams(genericParams); if (gotNewName()) { var old = typeDefinition.Name; typeDefinition.Name = NewName; Log.v("Name: {0} => {1}", old, typeDefinition.Name); } if (newNamespace != null) { var old = typeDefinition.Namespace; typeDefinition.Namespace = newNamespace; Log.v("Namespace: {0} => {1}", old, typeDefinition.Namespace); } Log.deIndent(); } static void prepareRenameGenericParams(IList genericParams, Func isValidName, IList otherGenericParams = null) { Dictionary usedNames = new Dictionary(StringComparer.Ordinal); INameCreator nameCreator = new GenericParamNameCreator(); if (otherGenericParams != null) { foreach (var param in otherGenericParams) usedNames[param.NewName] = true; } foreach (var param in genericParams) { if (!isValidName(param.OldName) || usedNames.ContainsKey(param.OldName)) { string newName; do { newName = nameCreator.newName(); } while (usedNames.ContainsKey(newName)); usedNames[newName] = true; param.rename(newName); } } } static void renameGenericParams(IList genericParams) { foreach (var param in genericParams) { if (!param.gotNewName()) continue; param.GenericParameter.Name = param.NewName; Log.v("GenParam: {0} => {1}", param.OldFullName, param.GenericParameter.FullName); } } public void renameMembers() { Log.v("Type: {0}", TypeDefinition.FullName); Log.indent(); renameFields(); renameProperties(); renameEvents(); renameMethods(); Log.deIndent(); } void renameFields() { foreach (var fieldDef in fields.getSorted()) { if (!fieldDef.gotNewName()) continue; fieldDef.FieldDefinition.Name = fieldDef.NewName; Log.v("Field: {0} ({1:X8}) => {2}", fieldDef.OldFullName, fieldDef.FieldDefinition.MetadataToken.ToUInt32(), fieldDef.FieldDefinition.FullName); } } void renameProperties() { foreach (var propDef in properties.getSorted()) { if (!propDef.gotNewName()) continue; propDef.PropertyDefinition.Name = propDef.NewName; Log.v("Property: {0} ({1:X8}) => {2}", propDef.OldFullName, propDef.PropertyDefinition.MetadataToken.ToUInt32(), propDef.PropertyDefinition.FullName); } } void renameEvents() { foreach (var eventDef in events.getSorted()) { if (!eventDef.gotNewName()) continue; eventDef.EventDefinition.Name = eventDef.NewName; Log.v("Event: {0} ({1:X8}) => {2}", eventDef.OldFullName, eventDef.EventDefinition.MetadataToken.ToUInt32(), eventDef.EventDefinition.FullName); } } void renameMethods() { foreach (var methodDef in methods.getSorted()) { Log.v("Method {0} ({1:X8})", methodDef.OldFullName, methodDef.MethodDefinition.MetadataToken.ToUInt32()); Log.indent(); renameGenericParams(methodDef.GenericParams); if (methodDef.gotNewName()) { methodDef.MethodReference.Name = methodDef.NewName; Log.v("Name: {0} => {1}", methodDef.OldFullName, methodDef.MethodReference.FullName); } foreach (var param in methodDef.ParamDefs) { if (!param.gotNewName()) continue; param.ParameterDefinition.Name = param.NewName; Log.v("Param ({0}/{1}): {2} => {3}", param.Index + 1, methodDef.ParamDefs.Count, param.OldName, param.NewName); } Log.deIndent(); } } public void initializeVirtualMembers() { expandGenerics(); foreach (var propDef in properties.getSorted()) { if (propDef.isVirtual()) MemberRenameState.add(propDef); } foreach (var eventDef in events.getSorted()) { if (eventDef.isVirtual()) MemberRenameState.add(eventDef); } foreach (var methodDef in methods.getSorted()) { if (methodDef.isVirtual()) MemberRenameState.add(methodDef); } } public void prepareRenameMembers() { if (prepareRenameMembersCalled) return; prepareRenameMembersCalled = true; foreach (var ifaceInfo in interfaces) ifaceInfo.typeDef.prepareRenameMembers(); if (baseType != null) baseType.typeDef.prepareRenameMembers(); if (MemberRenameState == null) MemberRenameState = baseType.typeDef.MemberRenameState.clone(); if (IsRenamable) { foreach (var fieldDef in fields.getAll()) MemberRenameState.variableNameState.addFieldName(fieldDef.OldName); foreach (var methodDef in methods.getAll()) MemberRenameState.variableNameState.addMethodName(methodDef.OldName); } // For each base type and interface it implements, add all its virtual methods, props, // and events if the type is a non-renamable type (eg. it's from mscorlib or some other // non-deobfuscated assembly). if (IsRenamable) { foreach (var ifaceInfo in interfaces) { if (!ifaceInfo.typeDef.IsRenamable) MemberRenameState.mergeRenamed(ifaceInfo.typeDef.MemberRenameState); } if (baseType != null && !baseType.typeDef.IsRenamable) MemberRenameState.mergeRenamed(baseType.typeDef.MemberRenameState); } if (InterfaceScopeState != null) MemberRenameState.mergeRenamed(InterfaceScopeState); expandGenerics(); if (IsRenamable) { MemberRenameState.variableNameState.IsValidName = module.IsValidName; prepareRenameFields(); // must be first prepareRenameProperties(); prepareRenameEvents(); initializeEventHandlerNames(); prepareRenameMethods(); // must be last } } // Replaces the generic params with the generic args, if any void expandGenerics() { foreach (var typeInfo in getTypeInfos()) { var git = typeInfo.typeReference as GenericInstanceType; if (git == null) continue; if (git.GenericArguments.Count != typeInfo.typeDef.TypeDefinition.GenericParameters.Count) { throw new ApplicationException(string.Format("# args ({0}) != # params ({1})", git.GenericArguments.Count, typeInfo.typeDef.TypeDefinition.GenericParameters.Count)); } expandProperties(git); expandEvents(git); expandMethods(git); } } IEnumerable getTypeInfos() { if (baseType != null) yield return baseType; foreach (var typeInfo in interfaces) yield return typeInfo; } void expandProperties(GenericInstanceType git) { foreach (var propRef in new List(MemberRenameState.properties.Values)) { var newPropRef = new GenericPropertyRefExpander(propRef, git).expand(); if (ReferenceEquals(newPropRef, propRef)) continue; MemberRenameState.add(newPropRef); } } void expandEvents(GenericInstanceType git) { foreach (var eventRef in new List(MemberRenameState.events.Values)) { var newEventRef = new GenericEventRefExpander(eventRef, git).expand(); if (ReferenceEquals(eventRef, newEventRef)) continue; MemberRenameState.add(newEventRef); } } void expandMethods(GenericInstanceType git) { foreach (var methodRef in new List(MemberRenameState.methods.Values)) { var newMethodRef = new GenericMethodRefExpander(methodRef, git).expand(); if (ReferenceEquals(methodRef, newMethodRef)) continue; MemberRenameState.add(newMethodRef); } } bool hasFlagsAttribute() { if (TypeDefinition.CustomAttributes != null) { foreach (var attr in TypeDefinition.CustomAttributes) { if (MemberReferenceHelper.verifyType(attr.AttributeType, "mscorlib", "System.FlagsAttribute")) return true; } } return false; } void prepareRenameFields() { var variableNameState = MemberRenameState.variableNameState; if (isWindowsFormsControlDerivedClass()) initializeWindowsFormsFields(); if (TypeDefinition.IsEnum) { var instanceFields = new List(getInstanceFields()); if (instanceFields.Count == 1) { var fieldDef = instanceFields[0]; if (fieldDef.rename("value__")) { fieldDef.FieldDefinition.IsRuntimeSpecialName = true; fieldDef.FieldDefinition.IsSpecialName = true; } } int i = 0; string nameFormat = hasFlagsAttribute() ? "flag_{0}" : "const_{0}"; foreach (var fieldDef in fields.getSorted()) { if (fieldDef.Renamed) continue; if (!fieldDef.FieldDefinition.IsStatic || !fieldDef.FieldDefinition.IsLiteral) continue; if (!variableNameState.IsValidName(fieldDef.OldName)) fieldDef.rename(string.Format(nameFormat, i)); i++; } } foreach (var fieldDef in fields.getSorted()) { if (fieldDef.Renamed) continue; if (!variableNameState.IsValidName(fieldDef.OldName)) fieldDef.rename(variableNameState.getNewFieldName(fieldDef.FieldDefinition)); } } void initializeWindowsFormsFields() { var ourFields = new Dictionary(); foreach (var fieldDef in fields.getAll()) ourFields[new FieldReferenceAndDeclaringTypeKey(fieldDef.FieldDefinition)] = fieldDef; var variableNameState = MemberRenameState.variableNameState; foreach (var methodDef in methods.getAll()) { if (methodDef.MethodDefinition.Body == null) continue; if (methodDef.MethodDefinition.IsStatic || methodDef.MethodDefinition.IsVirtual) continue; var instructions = methodDef.MethodDefinition.Body.Instructions; for (int i = 2; i < instructions.Count; i++) { var call = instructions[i]; if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; if (!isWindowsFormsSetNameMethod(call.Operand as MethodReference)) continue; var ldstr = instructions[i - 1]; if (ldstr.OpCode.Code != Code.Ldstr) continue; var fieldName = ldstr.Operand as string; if (fieldName == null || !variableNameState.IsValidName(fieldName)) continue; var ldfld = instructions[i - 2]; var fieldRef = ldfld.Operand as FieldReference; if (fieldRef == null) continue; FieldDef fieldDef; if (!ourFields.TryGetValue(new FieldReferenceAndDeclaringTypeKey(fieldRef), out fieldDef)) continue; if (fieldDef.Renamed) continue; fieldDef.rename(variableNameState.getNewFieldName(fieldDef.OldName, new NameCreator2(fieldName))); } } } void initializeEventHandlerNames() { var ourFields = new Dictionary(); foreach (var fieldDef in fields.getAll()) ourFields[new FieldReferenceAndDeclaringTypeKey(fieldDef.FieldDefinition)] = fieldDef; var ourMethods = new Dictionary(); foreach (var methodDef in methods.getAll()) ourMethods[new MethodReferenceAndDeclaringTypeKey(methodDef.MethodDefinition)] = methodDef; var variableNameState = MemberRenameState.variableNameState; foreach (var methodDef in methods.getAll()) { if (methodDef.MethodDefinition.Body == null) continue; if (methodDef.MethodDefinition.IsStatic) continue; var instructions = methodDef.MethodDefinition.Body.Instructions; for (int i = 0; i < instructions.Count - 5; i++) { // We're looking for this code pattern: // ldarg.0 // ldfld field // ldarg.0 // ldftn method // newobj event_handler_ctor // callvirt add_SomeEvent if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, instructions[i]) != 0) continue; var ldfld = instructions[i + 1]; if (ldfld.OpCode.Code != Code.Ldfld) continue; var fieldRef = ldfld.Operand as FieldReference; if (fieldRef == null) continue; FieldDef fieldDef; if (!ourFields.TryGetValue(new FieldReferenceAndDeclaringTypeKey(fieldRef), out fieldDef)) continue; if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, instructions[i + 2]) != 0) continue; var ldftn = instructions[i + 3]; if (ldftn.OpCode.Code != Code.Ldftn) continue; var methodRef = ldftn.Operand as MethodReference; if (methodRef == null) continue; MethodDef handlerMethod; if (!ourMethods.TryGetValue(new MethodReferenceAndDeclaringTypeKey(methodRef), out handlerMethod)) continue; var newobj = instructions[i + 4]; if (newobj.OpCode.Code != Code.Newobj) continue; if (!isEventHandlerCtor(newobj.Operand as MethodReference)) continue; var call = instructions[i + 5]; if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; var addHandler = call.Operand as MethodReference; if (addHandler == null) continue; if (!addHandler.Name.StartsWith("add_", StringComparison.Ordinal)) continue; var eventName = addHandler.Name.Substring(4); if (!MemberRenameState.variableNameState.IsValidName(eventName)) continue; newMethodsNames[handlerMethod] = string.Format("{0}_{1}", fieldDef.NewName, eventName); } } } static bool isEventHandlerCtor(MethodReference method) { if (method == null) return false; if (method.Name != ".ctor") return false; if (!DotNetUtils.isMethod(method, "System.Void", "(System.Object,System.IntPtr)")) return false; if (!method.DeclaringType.FullName.EndsWith("EventHandler", StringComparison.Ordinal)) return false; return true; } static MethodReference getOverrideMethod(MethodDefinition meth) { if (meth == null || !meth.HasOverrides) return null; return meth.Overrides[0]; } static string getRealName(string name) { int index = name.LastIndexOf('.'); if (index < 0) return name; return name.Substring(index + 1); } static readonly Regex removeGenericsArityRegex = new Regex(@"`[0-9]+"); static string getOverrideMethodNamePrefix(TypeReference owner) { var name = owner.FullName.Replace('/', '.'); name = removeGenericsArityRegex.Replace(name, ""); return name + "."; } static string getOverrideMethodName(TypeReference owner, string name) { return getOverrideMethodNamePrefix(owner) + name; } void prepareRenameProperties() { var variableNameState = MemberRenameState.variableNameState; foreach (var propDef in properties.getSorted()) { if (propDef.Renamed) continue; propDef.Renamed = true; bool isVirtual = propDef.isVirtual(); string prefix = ""; string baseName = propDef.OldName; string propName = null; if (isVirtual) getVirtualPropName(propDef, ref prefix, ref propName); if (propName == null && !variableNameState.IsValidName(propDef.OldName)) propName = variableNameState.getNewPropertyName(propDef.PropertyDefinition); if (propName != null) { baseName = propName; propDef.NewName = prefix + baseName; } renameSpecialMethod(propDef.PropertyDefinition.GetMethod, prefix + "get_" + baseName); renameSpecialMethod(propDef.PropertyDefinition.SetMethod, prefix + "set_" + baseName, "value"); if (isVirtual) MemberRenameState.add(propDef); } } void getVirtualPropName(PropertyDef propDef, ref string prefix, ref string propName) { PropertyRef sameDef; var overrideMethod = propDef.getOverrideMethod(); if (overrideMethod != null && (sameDef = defFinder.findProp(overrideMethod)) != null) { prefix = getOverrideMethodNamePrefix(sameDef.Owner.TypeDefinition); propName = sameDef.NewName; return; } var method = getOverrideMethod(propDef.PropertyDefinition.GetMethod ?? propDef.PropertyDefinition.SetMethod); if (method != null) { var realName = getRealName(method.Name); // Only use the name if the method is not in one of the loaded files, since the // name shouldn't be obfuscated. if (Regex.IsMatch(realName, @"^[sg]et_.") && defFinder.findProp(method) == null) { prefix = getOverrideMethodNamePrefix(method.DeclaringType); propName = realName.Substring(4); return; } } sameDef = MemberRenameState.get(propDef); if (sameDef != null) { prefix = ""; propName = sameDef.NewName; return; } } void prepareRenameEvents() { var variableNameState = MemberRenameState.variableNameState; foreach (var eventDef in events.getSorted()) { if (eventDef.Renamed) continue; eventDef.Renamed = true; bool isVirtual = eventDef.isVirtual(); string prefix = ""; string baseName = eventDef.OldName; string propName = null; if (isVirtual) getVirtualEventName(eventDef, ref prefix, ref propName); if (propName == null && !variableNameState.IsValidName(eventDef.OldName)) propName = variableNameState.getNewEventName(eventDef.EventDefinition); if (propName != null) { baseName = propName; eventDef.NewName = prefix + baseName; } renameSpecialMethod(eventDef.EventDefinition.AddMethod, prefix + "add_" + baseName, "value"); renameSpecialMethod(eventDef.EventDefinition.RemoveMethod, prefix + "remove_" + baseName, "value"); renameSpecialMethod(eventDef.EventDefinition.InvokeMethod, prefix + "raise_" + baseName); if (isVirtual) MemberRenameState.add(eventDef); } } void getVirtualEventName(EventDef eventDef, ref string prefix, ref string propName) { EventRef sameDef; var overrideMethod = eventDef.getOverrideMethod(); if (overrideMethod != null && (sameDef = defFinder.findEvent(overrideMethod)) != null) { prefix = getOverrideMethodNamePrefix(sameDef.Owner.TypeDefinition); propName = sameDef.NewName; return; } var method = getOverrideMethod(eventDef.EventDefinition.AddMethod ?? eventDef.EventDefinition.RemoveMethod); if (method != null) { var realName = getRealName(method.Name); // Only use the name if the method is not in one of the loaded files, since the // name shouldn't be obfuscated. if (Regex.IsMatch(realName, @"^(add|remove)_.") && defFinder.findEvent(method) == null) { prefix = getOverrideMethodNamePrefix(method.DeclaringType); propName = realName.Substring(realName.IndexOf('_') + 1); return; } } sameDef = MemberRenameState.get(eventDef); if (sameDef != null) { prefix = ""; propName = sameDef.NewName; return; } } void renameSpecialMethod(MethodDefinition methodDefinition, string newName, string newArgName = null) { if (methodDefinition == null) return; var methodDef = find(methodDefinition); if (methodDef == null) throw new ApplicationException("Could not find the event/prop method"); renameMethod(methodDef, newName); if (newArgName != null && methodDef.ParamDefs.Count > 0) { var arg = methodDef.ParamDefs[methodDef.ParamDefs.Count - 1]; if (!MemberRenameState.variableNameState.IsValidName(arg.OldName)) { arg.NewName = newArgName; arg.Renamed = true; } } } void prepareRenameMethods() { foreach (var methodDef in methods.getSorted()) renameMethod(methodDef); } void renameMethod(MethodDef methodDef, string suggestedName = null) { if (methodDef.Renamed) return; methodDef.Renamed = true; bool canRenameMethodName = true; if (suggestedName == null) newMethodsNames.TryGetValue(methodDef, out suggestedName); if (IsDelegate) { switch (methodDef.MethodDefinition.Name) { case "BeginInvoke": case "EndInvoke": case "Invoke": canRenameMethodName = false; break; } } var variableNameState = MemberRenameState.variableNameState; if (canRenameMethodName) { var nameCreator = getMethodNameCreator(methodDef, suggestedName); if (!methodDef.MethodDefinition.IsRuntimeSpecialName && !variableNameState.IsValidName(methodDef.OldName)) { bool useNameCreator = methodDef.isVirtual() || methodDef.Property != null || methodDef.Event != null; if (useNameCreator) methodDef.NewName = nameCreator.newName(); else methodDef.NewName = variableNameState.getNewMethodName(methodDef.OldName, nameCreator); } } if (methodDef.ParamDefs.Count > 0) { if (isEventHandler(methodDef)) { methodDef.ParamDefs[0].NewName = "sender"; methodDef.ParamDefs[0].Renamed = true; methodDef.ParamDefs[1].NewName = "e"; methodDef.ParamDefs[1].Renamed = true; } else { var newVariableNameState = variableNameState.clone(); foreach (var paramDef in methodDef.ParamDefs) { if (!newVariableNameState.IsValidName(paramDef.OldName)) { paramDef.NewName = newVariableNameState.getNewParamName(paramDef.OldName, paramDef.ParameterDefinition); paramDef.Renamed = true; } } } } prepareRenameGenericParams(methodDef.GenericParams, variableNameState.IsValidName, methodDef.Owner == null ? null : methodDef.Owner.genericParams); if (methodDef.isVirtual()) MemberRenameState.add(methodDef); } 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; } 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; } INameCreator getMethodNameCreator(MethodDef methodDef, string suggestedName) { var variableNameState = MemberRenameState.variableNameState; INameCreator nameCreator = null; string newName = null; if (methodDef.MethodDefinition.PInvokeInfo != null) newName = getPinvokeName(methodDef); else if (methodDef.MethodDefinition.IsStatic) nameCreator = variableNameState.staticMethodNameCreator; else if (methodDef.isVirtual()) { MethodRef otherMethodRef; if ((otherMethodRef = MemberRenameState.get(methodDef)) != null) newName = otherMethodRef.NewName; else if (methodDef.MethodDefinition.HasOverrides) { var overrideMethod = methodDef.MethodDefinition.Overrides[0]; var otherMethodDef = defFinder.findMethod(overrideMethod); if (otherMethodDef != null) newName = getOverrideMethodName(overrideMethod.DeclaringType, otherMethodDef.NewName); else newName = getOverrideMethodName(overrideMethod.DeclaringType, overrideMethod.Name); } else nameCreator = variableNameState.virtualMethodNameCreator; } else nameCreator = variableNameState.instanceMethodNameCreator; if (newName == null) newName = suggestedName; if (newName != null) { if (methodDef.isVirtual()) nameCreator = new OneNameCreator(newName); // It must have this name else nameCreator = new NameCreator2(newName); } return nameCreator; } } }