/* Copyright (C) 2011 de4dot@gmail.com This file is part of de4dot. de4dot is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. de4dot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with de4dot. If not, see . */ using System; using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; using de4dot.blocks; using de4dot.renamer.asmmodules; namespace de4dot.renamer { class MemberInfo { Ref memberRef; public string oldFullName; public string oldName; public string newName; public bool renamed; public MemberInfo(Ref memberRef) { this.memberRef = memberRef; oldFullName = memberRef.memberReference.FullName; oldName = memberRef.memberReference.Name; newName = memberRef.memberReference.Name; } public void rename(string newTypeName) { renamed = true; newName = newTypeName; } public bool gotNewName() { return oldName != newName; } } class TypeInfo : MemberInfo { public string oldNamespace; public string newNamespace; public TypeInfo(TypeDef type) : base(type) { oldNamespace = type.TypeDefinition.Namespace; } } class GenericParamInfo : MemberInfo { public GenericParamInfo(GenericParamDef genericParamDef) : base(genericParamDef) { } } class Renamer { public bool RenameNamespaces { get; set; } public bool RenameTypes { get; set; } public bool RenameProperties { get; set; } public bool RenameEvents { get; set; } public bool RenameFields { get; set; } public bool RenameGenericParams { get; set; } public bool RenameMethodArgs { get; set; } Modules modules = new Modules(); DerivedFrom isWinFormsClass; Dictionary allTypeInfos = new Dictionary(); Dictionary allGenericParamInfos = new Dictionary(); Dictionary suggestedMethodNames = new Dictionary(); static string[] WINFORMS_CLASSES = new string[] { #region Win Forms class names "System.Windows.Forms.Control", "System.Windows.Forms.AxHost", "System.Windows.Forms.ButtonBase", "System.Windows.Forms.Button", "System.Windows.Forms.CheckBox", "System.Windows.Forms.RadioButton", "System.Windows.Forms.DataGrid", "System.Windows.Forms.DataGridView", "System.Windows.Forms.DataVisualization.Charting.Chart", "System.Windows.Forms.DateTimePicker", "System.Windows.Forms.GroupBox", "System.Windows.Forms.Integration.ElementHost", "System.Windows.Forms.Label", "System.Windows.Forms.LinkLabel", "System.Windows.Forms.ListControl", "System.Windows.Forms.ComboBox", "Microsoft.VisualBasic.Compatibility.VB6.DriveListBox", "System.Windows.Forms.DataGridViewComboBoxEditingControl", "System.Windows.Forms.ListBox", "Microsoft.VisualBasic.Compatibility.VB6.DirListBox", "Microsoft.VisualBasic.Compatibility.VB6.FileListBox", "System.Windows.Forms.CheckedListBox", "System.Windows.Forms.ListView", "System.Windows.Forms.MdiClient", "System.Windows.Forms.MonthCalendar", "System.Windows.Forms.PictureBox", "System.Windows.Forms.PrintPreviewControl", "System.Windows.Forms.ProgressBar", "System.Windows.Forms.ScrollableControl", "System.Windows.Forms.ContainerControl", "System.Windows.Forms.Form", "System.ComponentModel.Design.CollectionEditor.CollectionForm", "System.Messaging.Design.QueuePathDialog", "System.ServiceProcess.Design.ServiceInstallerDialog", "System.Web.UI.Design.WebControls.CalendarAutoFormatDialog", "System.Web.UI.Design.WebControls.RegexEditorDialog", "System.Windows.Forms.Design.ComponentEditorForm", "System.Windows.Forms.PrintPreviewDialog", "System.Windows.Forms.ThreadExceptionDialog", "System.Workflow.Activities.Rules.Design.RuleConditionDialog", "System.Workflow.Activities.Rules.Design.RuleSetDialog", "System.Workflow.ComponentModel.Design.ThemeConfigurationDialog", "System.Workflow.ComponentModel.Design.TypeBrowserDialog", "System.Workflow.ComponentModel.Design.WorkflowPageSetupDialog", "System.Windows.Forms.PropertyGrid", "System.Windows.Forms.SplitContainer", "System.Windows.Forms.ToolStripContainer", "System.Windows.Forms.ToolStripPanel", "System.Windows.Forms.UpDownBase", "System.Windows.Forms.DomainUpDown", "System.Windows.Forms.NumericUpDown", "System.Windows.Forms.UserControl", "Microsoft.VisualBasic.Compatibility.VB6.ADODC", "System.Web.UI.Design.WebControls.ParameterEditorUserControl", "System.Workflow.ComponentModel.Design.WorkflowOutline", "System.Workflow.ComponentModel.Design.WorkflowView", "System.Windows.Forms.Design.ComponentTray", "System.Windows.Forms.Panel", "System.Windows.Forms.Design.ComponentEditorPage", "System.Windows.Forms.FlowLayoutPanel", "System.Windows.Forms.SplitterPanel", "System.Windows.Forms.TableLayoutPanel", "System.ComponentModel.Design.ByteViewer", "System.Windows.Forms.TabPage", "System.Windows.Forms.ToolStripContentPanel", "System.Windows.Forms.ToolStrip", "System.Windows.Forms.BindingNavigator", "System.Windows.Forms.MenuStrip", "System.Windows.Forms.StatusStrip", "System.Windows.Forms.ToolStripDropDown", "System.Windows.Forms.ToolStripDropDownMenu", "System.Windows.Forms.ContextMenuStrip", "System.Windows.Forms.ToolStripOverflow", "System.Windows.Forms.ScrollBar", "System.Windows.Forms.HScrollBar", "System.Windows.Forms.VScrollBar", "System.Windows.Forms.Splitter", "System.Windows.Forms.StatusBar", "System.Windows.Forms.TabControl", "System.Windows.Forms.TextBoxBase", "System.Windows.Forms.MaskedTextBox", "System.Windows.Forms.RichTextBox", "System.Windows.Forms.TextBox", "System.Windows.Forms.DataGridTextBox", "System.Windows.Forms.DataGridViewTextBoxEditingControl", "System.Windows.Forms.ToolBar", "System.Windows.Forms.TrackBar", "System.Windows.Forms.TreeView", "System.ComponentModel.Design.ObjectSelectorEditor.Selector", "System.Windows.Forms.WebBrowserBase", "System.Windows.Forms.WebBrowser", #endregion }; public Renamer(IEnumerable files) { RenameNamespaces = true; RenameTypes = true; RenameProperties = true; RenameEvents = true; RenameFields = true; RenameGenericParams = true; RenameMethodArgs = true; foreach (var file in files) modules.add(new Module(file)); isWinFormsClass = new DerivedFrom(WINFORMS_CLASSES); } public void rename() { if (modules.Empty) return; Log.n("Renaming all obfuscated symbols"); modules.initialize(); modules.initializeVirtualMembers(); renameTypeDefinitions(); modules.cleanUp(); } void renameTypeDefinitions() { Log.v("Renaming obfuscated type definitions"); prepareRenameTypes(); } void prepareRenameTypes() { foreach (var type in modules.AllTypes) allTypeInfos[type] = new TypeInfo(type); var state = new TypeRenamerState(); prepareRenameTypes(modules.BaseTypes, state); fixClsTypeNames(); renameTypeDefinitions(modules.NonNestedTypes); } void renameTypeDefinitions(IEnumerable typeDefs) { Log.indent(); foreach (var typeDef in typeDefs) { rename(typeDef); renameTypeDefinitions(typeDef.NestedTypes); } Log.deIndent(); } void rename(TypeDef type) { var typeDefinition = type.TypeDefinition; var info = allTypeInfos[type]; Log.v("Type: {0} ({1:X8})", typeDefinition.FullName, typeDefinition.MetadataToken.ToUInt32()); Log.indent(); renameGenericParams(type.GenericParams); if (RenameTypes && info.gotNewName()) { var old = typeDefinition.Name; typeDefinition.Name = info.newName; Log.v("Name: {0} => {1}", old, typeDefinition.Name); } if (RenameNamespaces && info.newNamespace != null) { var old = typeDefinition.Namespace; typeDefinition.Namespace = info.newNamespace; Log.v("Namespace: {0} => {1}", old, typeDefinition.Namespace); } Log.deIndent(); } void renameGenericParams(IEnumerable genericParams) { if (!RenameGenericParams) return; foreach (var param in genericParams) { var info = allGenericParamInfos[param]; if (!info.gotNewName()) continue; param.GenericParameter.Name = info.newName; Log.v("GenParam: {0} => {1}", info.oldFullName, param.GenericParameter.FullName); } } // 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. void fixClsTypeNames() { foreach (var type in modules.NonNestedTypes) fixClsTypeNames(null, type); } void fixClsTypeNames(TypeDef nesting, TypeDef nested) { int nestingCount = nesting == null ? 0 : nesting.GenericParams.Count; int arity = nested.GenericParams.Count - nestingCount; var nestedInfo = allTypeInfos[nested]; if (nestedInfo.renamed && arity > 0) nestedInfo.newName += "`" + arity; foreach (var nestedType in nested.NestedTypes) fixClsTypeNames(nested, nestedType); } void prepareRenameTypes(IEnumerable types, TypeRenamerState state) { foreach (var typeDef in types) { prepareRenameTypes(typeDef, state); prepareRenameTypes(typeDef.derivedTypes, state); } } void prepareRenameTypes(TypeDef type, TypeRenamerState state) { var info = allTypeInfos[type]; var checker = type.Module.ObfuscatedFile.NameChecker; if (RenameNamespaces) { if (info.newNamespace == null && info.oldNamespace != "") { if (!checker.isValidNamespaceName(info.oldNamespace)) { info.newNamespace = state.createNamespace(info.oldNamespace); } } } if (RenameTypes) { if (info.oldFullName != "" && !checker.isValidTypeName(info.oldName)) { string origClassName = null; if (isWinFormsClass.check(type)) origClassName = findWindowsFormsClassName(type); if (origClassName != null && checker.isValidTypeName(origClassName)) info.rename(state.getTypeName(info.oldName, origClassName)); else { ITypeNameCreator nameCreator = type.isGlobalType() ? state.globalTypeNameCreator : state.internalTypeNameCreator; string newBaseType = null; TypeInfo baseInfo; if (type.baseType != null && allTypeInfos.TryGetValue(type.baseType.typeDef, out baseInfo)) { if (baseInfo.renamed) newBaseType = baseInfo.newName; } info.rename(nameCreator.create(type.TypeDefinition, newBaseType)); } } } if (RenameGenericParams) prepareRenameGenericParams(type.GenericParams, checker); } void prepareRenameGenericParams(IEnumerable genericParams, INameChecker checker, IEnumerable otherGenericParams = null) { var usedNames = new Dictionary(StringComparer.Ordinal); var nameCreator = new GenericParamNameCreator(); foreach (var gp in genericParams) allGenericParamInfos[gp] = new GenericParamInfo(gp); if (otherGenericParams != null) { foreach (var param in otherGenericParams) { var gpInfo = allGenericParamInfos[param]; usedNames[gpInfo.newName] = true; } } foreach (var param in genericParams) { var gpInfo = allGenericParamInfos[param]; if (!checker.isValidGenericParamName(gpInfo.oldName) || usedNames.ContainsKey(gpInfo.oldName)) { string newName; do { newName = nameCreator.create(); } while (usedNames.ContainsKey(newName)); usedNames[newName] = true; gpInfo.rename(newName); } } } string findWindowsFormsClassName(TypeDef type) { foreach (var methodDef in type.getAllMethods()) { 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(type, methodDef); return className; } } return null; } void findInitializeComponentMethod(TypeDef type, MethodDef possibleInitMethod) { foreach (var methodDef in type.getAllMethods()) { if (methodDef.MethodDefinition.Name != ".ctor") continue; if (methodDef.MethodDefinition.Body == null) continue; foreach (var instr in methodDef.MethodDefinition.Body.Instructions) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) continue; if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(possibleInitMethod.MethodDefinition, instr.Operand as MethodReference)) continue; suggestedMethodNames[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 (!Utils.StartsWith(method.DeclaringType.FullName, "System.Windows.Forms.", StringComparison.Ordinal)) return false; return true; } } }