From e6a8d50d0387df47ef452997985c2ae926d5a5bc Mon Sep 17 00:00:00 2001 From: de4dot Date: Fri, 4 Nov 2011 13:58:17 +0100 Subject: [PATCH 01/19] Add updated cecil submodule --- cecil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cecil b/cecil index 926f46f2..5bb4d7d3 160000 --- a/cecil +++ b/cecil @@ -1 +1 @@ -Subproject commit 926f46f282a7f8de0b36f3e175568665afb5bad6 +Subproject commit 5bb4d7d39d83cb5f051767d3cd03d785b1e5c7ff From df507526baaa72955c712f1ee9730f84b15f314c Mon Sep 17 00:00:00 2001 From: de4dot Date: Fri, 4 Nov 2011 13:59:43 +0100 Subject: [PATCH 02/19] Update renamer code so it's less likely to use an existing name --- de4dot.code/de4dot.code.csproj | 1 + de4dot.code/renamer/CurrentNames.cs | 62 +++++++++++++++++++++++ de4dot.code/renamer/DefinitionsRenamer.cs | 2 + de4dot.code/renamer/MemberRefs.cs | 36 ++++++++----- de4dot.code/renamer/NameCreators.cs | 21 +++----- de4dot.code/renamer/TypeNameState.cs | 17 +++++-- de4dot.code/renamer/VariableNameState.cs | 25 ++++++--- 7 files changed, 127 insertions(+), 37 deletions(-) create mode 100644 de4dot.code/renamer/CurrentNames.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 8baee5b9..9b5dc4f6 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -103,6 +103,7 @@ + diff --git a/de4dot.code/renamer/CurrentNames.cs b/de4dot.code/renamer/CurrentNames.cs new file mode 100644 index 00000000..894fb3d1 --- /dev/null +++ b/de4dot.code/renamer/CurrentNames.cs @@ -0,0 +1,62 @@ +/* + 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; + +namespace de4dot.renamer { + class CurrentNames { + Dictionary allNames = new Dictionary(StringComparer.Ordinal); + + public void add(string name) { + allNames[name] = true; + } + + bool exists(string name) { + return allNames.ContainsKey(name); + } + + public string newName(string oldName, INameCreator nameCreator) { + return newName(oldName, () => nameCreator.newName()); + } + + public string newName(string oldName, Func createNewName) { + string prevName = null; + while (true) { + var name = createNewName(); + if (name == prevName) + throw new ApplicationException(string.Format("Could not rename symbol to {0}", Utils.toCsharpString(name))); + + if (!exists(name) || name == oldName) { + allNames[name] = true; + return name; + } + + prevName = name; + } + } + + public CurrentNames clone() { + var cn = new CurrentNames(); + foreach (var key in allNames.Keys) + cn.allNames[key] = true; + return cn; + } + } +} diff --git a/de4dot.code/renamer/DefinitionsRenamer.cs b/de4dot.code/renamer/DefinitionsRenamer.cs index 7f307ca5..d3b58621 100644 --- a/de4dot.code/renamer/DefinitionsRenamer.cs +++ b/de4dot.code/renamer/DefinitionsRenamer.cs @@ -209,6 +209,8 @@ namespace de4dot.renamer { void renameTypeDefinitions() { Log.v("Renaming obfuscated type definitions"); typeNameState = new TypeNameState(); + foreach (var typeDef in allTypes) + typeNameState.currentNames.add(typeDef.OldName); prepareRenameTypeDefinitions(baseTypes); typeNameState = null; diff --git a/de4dot.code/renamer/MemberRefs.cs b/de4dot.code/renamer/MemberRefs.cs index 34f674d6..c8ad0426 100644 --- a/de4dot.code/renamer/MemberRefs.cs +++ b/de4dot.code/renamer/MemberRefs.cs @@ -635,6 +635,13 @@ namespace de4dot.renamer { 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). @@ -947,15 +954,20 @@ namespace de4dot.renamer { if (canRenameName) { var nameCreator = getMethodNameCreator(methodDef, suggestedName); - if (!methodDef.MethodDefinition.IsRuntimeSpecialName && !variableNameState.IsValidName(methodDef.OldName)) - methodDef.NewName = nameCreator.newName(); + 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) { var newVariableNameState = variableNameState.clone(); foreach (var paramDef in methodDef.ParamDefs) { if (!newVariableNameState.IsValidName(paramDef.OldName)) { - paramDef.NewName = newVariableNameState.getNewParamName(paramDef.ParameterDefinition); + paramDef.NewName = newVariableNameState.getNewParamName(paramDef.OldName, paramDef.ParameterDefinition); paramDef.Renamed = true; } } @@ -968,18 +980,10 @@ namespace de4dot.renamer { } string getPinvokeName(MethodDef methodDef) { - var methodNames = new Dictionary(StringComparer.Ordinal); - foreach (var method in methods.getAll()) - methodNames[method.NewName] = true; - var entryPoint = methodDef.MethodDefinition.PInvokeInfo.EntryPoint; if (Regex.IsMatch(entryPoint, @"^#\d+$")) entryPoint = DotNetUtils.getDllName(methodDef.MethodDefinition.PInvokeInfo.Module.Name) + "_" + entryPoint.Substring(1); - while (true) { - var newName = MemberRenameState.variableNameState.pinvokeNameCreator.newName(entryPoint); - if (!methodNames.ContainsKey(newName)) - return newName; - } + return entryPoint; } INameCreator getMethodNameCreator(MethodDef methodDef, string suggestedName) { @@ -1011,8 +1015,12 @@ namespace de4dot.renamer { if (newName == null) newName = suggestedName; - if (newName != null) - nameCreator = new OneNameCreator(newName); + if (newName != null) { + if (methodDef.isVirtual()) + nameCreator = new OneNameCreator(newName); // It must have this name + else + nameCreator = new NameCreator2(newName); + } return nameCreator; } diff --git a/de4dot.code/renamer/NameCreators.cs b/de4dot.code/renamer/NameCreators.cs index 438c6498..e4a08c2e 100644 --- a/de4dot.code/renamer/NameCreators.cs +++ b/de4dot.code/renamer/NameCreators.cs @@ -125,17 +125,6 @@ namespace de4dot.renamer { string newName(TypeDefinition typeDefinition, string newBaseTypeName = null); } - class PinvokeNameCreator { - Dictionary nameCreators = new Dictionary(StringComparer.Ordinal); - - public string newName(string name) { - NameCreator2 nameCreator; - if (!nameCreators.TryGetValue(name, out nameCreator)) - nameCreators[name] = nameCreator = new NameCreator2(name); - return nameCreator.newName(); - } - } - class NameInfos { IList nameInfos = new List(); @@ -163,6 +152,7 @@ namespace de4dot.renamer { } class TypeNameCreator : ITypeNameCreator { + CurrentNames currentNames; INameCreator createUnknownTypeName; INameCreator createEnumName; INameCreator createStructName; @@ -171,7 +161,8 @@ namespace de4dot.renamer { INameCreator createInterfaceName; NameInfos nameInfos = new NameInfos(); - public TypeNameCreator() { + public TypeNameCreator(CurrentNames currentNames) { + this.currentNames = currentNames; createUnknownTypeName = createNameCreator("Type"); createEnumName = createNameCreator("Enum"); createStructName = createNameCreator("Struct"); @@ -197,7 +188,7 @@ namespace de4dot.renamer { public string newName(TypeDefinition typeDefinition, string newBaseTypeName = null) { var nameCreator = getNameCreator(typeDefinition, newBaseTypeName); - return nameCreator.newName(); + return currentNames.newName(typeDefinition.Name, nameCreator); } INameCreator getNameCreator(TypeDefinition typeDefinition, string newBaseTypeName) { @@ -228,6 +219,10 @@ namespace de4dot.renamer { } class GlobalTypeNameCreator : TypeNameCreator { + public GlobalTypeNameCreator(CurrentNames currentNames) + : base(currentNames) { + } + protected override INameCreator createNameCreator(string prefix) { return new GlobalNameCreator(base.createNameCreator("G" + prefix)); } diff --git a/de4dot.code/renamer/TypeNameState.cs b/de4dot.code/renamer/TypeNameState.cs index a20240b5..12999ae7 100644 --- a/de4dot.code/renamer/TypeNameState.cs +++ b/de4dot.code/renamer/TypeNameState.cs @@ -23,10 +23,11 @@ using de4dot.deobfuscators; namespace de4dot.renamer { class TypeNameState { - IDictionary namespaceToNewName = new Dictionary(StringComparer.Ordinal); - INameCreator createNamespaceName = new GlobalNameCreator(new NameCreator("ns")); - public ITypeNameCreator globalTypeNameCreator = new GlobalTypeNameCreator(); - public ITypeNameCreator internalTypeNameCreator = new TypeNameCreator(); + public CurrentNames currentNames; + IDictionary namespaceToNewName; + INameCreator createNamespaceName; + public ITypeNameCreator globalTypeNameCreator; + public ITypeNameCreator internalTypeNameCreator; Func isValidName; public Func IsValidName { @@ -34,6 +35,14 @@ namespace de4dot.renamer { set { isValidName = value; } } + public TypeNameState() { + currentNames = new CurrentNames(); + namespaceToNewName = new Dictionary(StringComparer.Ordinal); + createNamespaceName = new GlobalNameCreator(new NameCreator("ns")); + globalTypeNameCreator = new GlobalTypeNameCreator(currentNames); + internalTypeNameCreator = new TypeNameCreator(currentNames); + } + public bool isValidNamespace(string ns) { foreach (var part in ns.Split(new char[] { '.' })) { if (!isValidName(part)) diff --git a/de4dot.code/renamer/VariableNameState.cs b/de4dot.code/renamer/VariableNameState.cs index 47ba167a..d9c44da3 100644 --- a/de4dot.code/renamer/VariableNameState.cs +++ b/de4dot.code/renamer/VariableNameState.cs @@ -18,11 +18,12 @@ */ using Mono.Cecil; -using de4dot.deobfuscators; namespace de4dot.renamer { // State when renaming type members class VariableNameState { + CurrentNames currentVariableNames = new CurrentNames(); + CurrentNames currentMethodNames = new CurrentNames(); protected TypeNames variableNameCreator = new VariableNameCreator(); // For fields and method args protected TypeNames propertyNameCreator = new PropertyNameCreator(); protected INameCreator eventNameCreator = new NameCreator("Event_"); @@ -30,7 +31,6 @@ namespace de4dot.renamer { public INameCreator virtualMethodNameCreator = new NameCreator("vmethod_"); public INameCreator instanceMethodNameCreator = new NameCreator("method_"); protected INameCreator genericPropertyNameCreator = new NameCreator("Prop_"); - public PinvokeNameCreator pinvokeNameCreator = new PinvokeNameCreator(); Func isValidName; public Func IsValidName { @@ -44,7 +44,17 @@ namespace de4dot.renamer { return rv; } + public void addFieldName(string fieldName) { + currentVariableNames.add(fieldName); + } + + public void addMethodName(string methodName) { + currentMethodNames.add(methodName); + } + protected void cloneInit(VariableNameState variableNameState) { + variableNameState.currentVariableNames = new CurrentNames(); + variableNameState.currentMethodNames = new CurrentNames(); variableNameState.variableNameCreator = variableNameCreator.clone(); variableNameState.propertyNameCreator = propertyNameCreator.clone(); variableNameState.eventNameCreator = eventNameCreator.clone(); @@ -52,7 +62,6 @@ namespace de4dot.renamer { variableNameState.virtualMethodNameCreator = virtualMethodNameCreator.clone(); variableNameState.instanceMethodNameCreator = instanceMethodNameCreator.clone(); variableNameState.genericPropertyNameCreator = genericPropertyNameCreator.clone(); - variableNameState.pinvokeNameCreator = new PinvokeNameCreator(); variableNameState.isValidName = isValidName; } @@ -68,11 +77,15 @@ namespace de4dot.renamer { } public string getNewFieldName(FieldDefinition field) { - return variableNameCreator.newName(field.FieldType); + return currentVariableNames.newName(field.Name, () => variableNameCreator.newName(field.FieldType)); } - public string getNewParamName(ParameterDefinition param) { - return variableNameCreator.newName(param.ParameterType); + public string getNewParamName(string oldName, ParameterDefinition param) { + return currentVariableNames.newName(oldName, () => variableNameCreator.newName(param.ParameterType)); + } + + public string getNewMethodName(string oldName, INameCreator nameCreator) { + return currentMethodNames.newName(oldName, nameCreator); } } From 7486b73da3024d3b6ffb7dd71d8375f6ddbc8f8c Mon Sep 17 00:00:00 2001 From: de4dot Date: Fri, 4 Nov 2011 15:39:16 +0100 Subject: [PATCH 03/19] Restore original WinForms class and field names --- de4dot.code/renamer/MemberRefs.cs | 211 ++++++++++++++++++++++- de4dot.code/renamer/VariableNameState.cs | 4 + 2 files changed, 214 insertions(+), 1 deletion(-) diff --git a/de4dot.code/renamer/MemberRefs.cs b/de4dot.code/renamer/MemberRefs.cs index c8ad0426..0165b53d 100644 --- a/de4dot.code/renamer/MemberRefs.cs +++ b/de4dot.code/renamer/MemberRefs.cs @@ -21,6 +21,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Mono.Cecil; +using Mono.Cecil.Cil; using de4dot.blocks; using de4dot.deobfuscators; @@ -286,6 +287,101 @@ namespace de4dot.renamer { } 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; + } + public IDefFinder defFinder; public TypeInfo baseType = null; public IList interfaces = new List(); // directly implemented interfaces @@ -344,6 +440,23 @@ namespace de4dot.renamer { 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; @@ -482,7 +595,13 @@ namespace de4dot.renamer { if (OldFullName != "" && !typeNameState.IsValidName(OldName)) { var newBaseType = baseType != null && baseType.typeDef.Renamed ? baseType.typeDef.NewName : null; - rename(nameCreator.newName(typeDefinition, newBaseType)); + 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)) @@ -491,6 +610,49 @@ namespace de4dot.renamer { 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; + var calledMethod = call.Operand as MethodReference; + if (!isWindowsFormsSetNameMethod(calledMethod)) + continue; + var ldstr = instructions[i - 1]; + if (ldstr.OpCode.Code != Code.Ldstr) + continue; + var ldarg = instructions[i - 2]; + if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, ldarg) != 0) + continue; + + return ldstr.Operand as string; + } + } + return null; + } + + 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; @@ -733,6 +895,9 @@ namespace de4dot.renamer { void prepareRenameFields() { var variableNameState = MemberRenameState.variableNameState; + if (isWindowsFormsControlDerivedClass()) + initializeWindowsFormsFields(); + if (TypeDefinition.IsEnum) { var instanceFields = new List(getInstanceFields()); if (instanceFields.Count == 1) { @@ -746,6 +911,8 @@ namespace de4dot.renamer { 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)) @@ -761,6 +928,48 @@ namespace de4dot.renamer { } } + 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; + var calledMethod = call.Operand as MethodReference; + if (!isWindowsFormsSetNameMethod(calledMethod)) + continue; + var ldstr = instructions[i - 1]; + if (ldstr.OpCode.Code != Code.Ldstr) + 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; + + var fieldName = ldstr.Operand as string; + if (fieldName == null || !variableNameState.IsValidName(fieldName)) + continue; + + if (fieldDef.Renamed) + continue; + + fieldDef.rename(variableNameState.getNewFieldName(fieldDef.OldName, new NameCreator2(fieldName))); + } + } + } + static MethodReference getOverrideMethod(MethodDefinition meth) { if (meth == null || !meth.HasOverrides) return null; diff --git a/de4dot.code/renamer/VariableNameState.cs b/de4dot.code/renamer/VariableNameState.cs index d9c44da3..04a2e7fc 100644 --- a/de4dot.code/renamer/VariableNameState.cs +++ b/de4dot.code/renamer/VariableNameState.cs @@ -80,6 +80,10 @@ namespace de4dot.renamer { return currentVariableNames.newName(field.Name, () => variableNameCreator.newName(field.FieldType)); } + public string getNewFieldName(string oldName, INameCreator nameCreator) { + return currentVariableNames.newName(oldName, () => nameCreator.newName()); + } + public string getNewParamName(string oldName, ParameterDefinition param) { return currentVariableNames.newName(oldName, () => variableNameCreator.newName(param.ParameterType)); } From 2236300943508df6e816254dbea7153fe4e8271c Mon Sep 17 00:00:00 2001 From: de4dot Date: Fri, 4 Nov 2011 19:08:23 +0100 Subject: [PATCH 04/19] Update renamer to better rename methods and args Finds InitializeComponent() method and renames it if necessary. Finds all event handlers and names the args sender and e respectively. Finds all field event handlers and names them _, eg. button_Click. --- de4dot.code/renamer/MemberRefs.cs | 149 ++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 6 deletions(-) diff --git a/de4dot.code/renamer/MemberRefs.cs b/de4dot.code/renamer/MemberRefs.cs index 0165b53d..d947a54d 100644 --- a/de4dot.code/renamer/MemberRefs.cs +++ b/de4dot.code/renamer/MemberRefs.cs @@ -382,6 +382,8 @@ namespace de4dot.renamer { 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 @@ -631,12 +633,35 @@ namespace de4dot.renamer { if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, ldarg) != 0) continue; - return ldstr.Operand as string; + var className = ldstr.Operand as string; + if (className == null) + 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; @@ -826,6 +851,9 @@ namespace de4dot.renamer { prepareRenameFields(); // must be first prepareRenameProperties(); prepareRenameEvents(); + + initializeEventHandlerNames(); + prepareRenameMethods(); // must be last } } @@ -970,6 +998,92 @@ namespace de4dot.renamer { } } + 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; @@ -1142,6 +1256,9 @@ namespace de4dot.renamer { return; methodDef.Renamed = true; + if (suggestedName == null) + newMethodsNames.TryGetValue(methodDef, out suggestedName); + bool canRenameName = true; if (IsDelegate && methodDef.isVirtual()) { switch (methodDef.MethodDefinition.Name) { @@ -1173,11 +1290,19 @@ namespace de4dot.renamer { } if (methodDef.ParamDefs.Count > 0) { - 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; + 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; + } } } } @@ -1188,6 +1313,18 @@ namespace de4dot.renamer { 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+$")) From 51092fa09a8a50859263a3ae2a90bec0db5bb0c8 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 07:38:12 +0100 Subject: [PATCH 05/19] Add updated cecil submodule --- cecil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cecil b/cecil index 5bb4d7d3..e4776e4b 160000 --- a/cecil +++ b/cecil @@ -1 +1 @@ -Subproject commit 5bb4d7d39d83cb5f051767d3cd03d785b1e5c7ff +Subproject commit e4776e4b1676c3ca08b36e91be4c519e36e9dbfe From f524989a1e1039149ec1322eaf51b5598b9285f4 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 07:42:58 +0100 Subject: [PATCH 06/19] Re-arrange some code --- de4dot.code/renamer/MemberRefs.cs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/de4dot.code/renamer/MemberRefs.cs b/de4dot.code/renamer/MemberRefs.cs index d947a54d..65d09abd 100644 --- a/de4dot.code/renamer/MemberRefs.cs +++ b/de4dot.code/renamer/MemberRefs.cs @@ -623,20 +623,19 @@ namespace de4dot.renamer { var call = instructions[i]; if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; - var calledMethod = call.Operand as MethodReference; - if (!isWindowsFormsSetNameMethod(calledMethod)) + if (!isWindowsFormsSetNameMethod(call.Operand as MethodReference)) continue; + var ldstr = instructions[i - 1]; if (ldstr.OpCode.Code != Code.Ldstr) continue; - var ldarg = instructions[i - 2]; - if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, ldarg) != 0) - 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; } @@ -972,12 +971,16 @@ namespace de4dot.renamer { var call = instructions[i]; if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt) continue; - var calledMethod = call.Operand as MethodReference; - if (!isWindowsFormsSetNameMethod(calledMethod)) + 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) @@ -986,10 +989,6 @@ namespace de4dot.renamer { if (!ourFields.TryGetValue(new FieldReferenceAndDeclaringTypeKey(fieldRef), out fieldDef)) continue; - var fieldName = ldstr.Operand as string; - if (fieldName == null || !variableNameState.IsValidName(fieldName)) - continue; - if (fieldDef.Renamed) continue; From c66c062753f10155608d85f6d181851f3cde6f8d Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 07:46:24 +0100 Subject: [PATCH 07/19] Fix problem when HasPInvokeInfo == true but PInvokeInfo == null --- blocks/DotNetUtils.cs | 2 +- de4dot.code/renamer/MemberRefs.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blocks/DotNetUtils.cs b/blocks/DotNetUtils.cs index 785be832..ad658261 100644 --- a/blocks/DotNetUtils.cs +++ b/blocks/DotNetUtils.cs @@ -225,7 +225,7 @@ namespace de4dot.blocks { public static bool isPinvokeMethod(MethodDefinition method, string dll, string funcName) { if (method == null) return false; - if (!method.HasPInvokeInfo || method.PInvokeInfo.EntryPoint != funcName) + if (method.PInvokeInfo == null || method.PInvokeInfo.EntryPoint != funcName) return false; return getDllName(dll).Equals(getDllName(method.PInvokeInfo.Module.Name), StringComparison.OrdinalIgnoreCase); } diff --git a/de4dot.code/renamer/MemberRefs.cs b/de4dot.code/renamer/MemberRefs.cs index 65d09abd..871955f5 100644 --- a/de4dot.code/renamer/MemberRefs.cs +++ b/de4dot.code/renamer/MemberRefs.cs @@ -1336,7 +1336,7 @@ namespace de4dot.renamer { INameCreator nameCreator = null; string newName = null; - if (methodDef.MethodDefinition.HasPInvokeInfo) + if (methodDef.MethodDefinition.PInvokeInfo != null) newName = getPinvokeName(methodDef); else if (methodDef.MethodDefinition.IsStatic) nameCreator = variableNameState.staticMethodNameCreator; From 13d5f8e37d7460ee053278d6eeefd01aa33fcc41 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 08:04:14 +0100 Subject: [PATCH 08/19] Ignore assemblies that contain native code --- de4dot.code/FilesDeobfuscator.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/de4dot.code/FilesDeobfuscator.cs b/de4dot.code/FilesDeobfuscator.cs index 56ec0af1..7f67135d 100644 --- a/de4dot.code/FilesDeobfuscator.cs +++ b/de4dot.code/FilesDeobfuscator.cs @@ -20,6 +20,7 @@ using System; using System.IO; using System.Collections.Generic; +using Mono.Cecil; using de4dot.renamer; using de4dot.deobfuscators; using de4dot.AssemblyClient; @@ -189,6 +190,12 @@ namespace de4dot { return false; } + if ((file.ModuleDefinition.Attributes & ModuleAttributes.ILOnly) == 0) { + Log.w("Ignoring assembly with native code {0}", file.Filename); + return false; + } + + var deob = file.Deobfuscator; if (skipUnknownObfuscator && deob is deobfuscators.Unknown.Deobfuscator) { Log.v("Skipping unknown obfuscator: {0}", file.Filename); From a23a889776e6722d50fe083ccaf01903727a6163 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 08:08:16 +0100 Subject: [PATCH 09/19] Ignore resolve errors. It's likely an obfuscator bug. --- de4dot.code/renamer/DefinitionsRenamer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/de4dot.code/renamer/DefinitionsRenamer.cs b/de4dot.code/renamer/DefinitionsRenamer.cs index d3b58621..97a2d1e5 100644 --- a/de4dot.code/renamer/DefinitionsRenamer.cs +++ b/de4dot.code/renamer/DefinitionsRenamer.cs @@ -504,7 +504,8 @@ namespace de4dot.renamer { } if (isAutoCreatedType(typeReference)) return null; - throw new ApplicationException(string.Format("Could not resolve TypeReference {0} ({1:X8})", typeReference, typeReference.MetadataToken.ToInt32())); + Log.e("Could not resolve TypeReference {0} ({1:X8})", typeReference, typeReference.MetadataToken.ToInt32()); + return null; } public MethodDef resolve(MethodReference methodReference) { @@ -520,7 +521,8 @@ namespace de4dot.renamer { } if (isAutoCreatedType(methodReference.DeclaringType)) return null; - throw new ApplicationException(string.Format("Could not resolve MethodReference {0} ({1:X8})", methodReference, methodReference.MetadataToken.ToInt32())); + Log.e("Could not resolve MethodReference {0} ({1:X8})", methodReference, methodReference.MetadataToken.ToInt32()); + return null; } public FieldDef resolve(FieldReference fieldReference) { @@ -536,7 +538,8 @@ namespace de4dot.renamer { } if (isAutoCreatedType(fieldReference.DeclaringType)) return null; - throw new ApplicationException(string.Format("Could not resolve FieldReference {0} ({1:X8})", fieldReference, fieldReference.MetadataToken.ToInt32())); + Log.e("Could not resolve FieldReference {0} ({1:X8})", fieldReference, fieldReference.MetadataToken.ToInt32()); + return null; } public MethodDef findMethod(MethodReference methodReference) { From 5e274dc4ad2afc625d7dc2e1ff8d1d06ad0f516e Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 08:35:33 +0100 Subject: [PATCH 10/19] Add updated cecil submodule --- cecil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cecil b/cecil index e4776e4b..3bcc7cb1 160000 --- a/cecil +++ b/cecil @@ -1 +1 @@ -Subproject commit e4776e4b1676c3ca08b36e91be4c519e36e9dbfe +Subproject commit 3bcc7cb109f9f44e1acd16c9bfd4f40d020917ba From 81d890d94e3c415c6d440ae51868d5ae53e0be4a Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 08:36:36 +0100 Subject: [PATCH 11/19] Don't update method header max stack field if no cflow deob --- de4dot.code/AssemblyModule.cs | 7 +++++-- de4dot.code/ObfuscatedFile.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/de4dot.code/AssemblyModule.cs b/de4dot.code/AssemblyModule.cs index ee030fab..e0f0b455 100644 --- a/de4dot.code/AssemblyModule.cs +++ b/de4dot.code/AssemblyModule.cs @@ -44,8 +44,11 @@ namespace de4dot { return module; } - public void save(string newFilename) { - module.Write(newFilename); + public void save(string newFilename, bool updateMaxStack) { + var writerParams = new WriterParameters() { + UpdateMaxStack = updateMaxStack, + }; + module.Write(newFilename, writerParams); } void readMethodsFile() { diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index 031cfb71..605321d2 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -245,7 +245,7 @@ namespace de4dot { public void save() { Log.n("Saving {0}", options.NewFilename); - assemblyModule.save(options.NewFilename); + assemblyModule.save(options.NewFilename, options.ControlFlowDeobfuscation); } IList getAllMethods() { From 93ad40d2182b12376003a9cdf8fc56065ace498e Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 08:43:40 +0100 Subject: [PATCH 12/19] Rename --asmpath option to --asm-path --- de4dot.code/CommandLineParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/de4dot.code/CommandLineParser.cs b/de4dot.code/CommandLineParser.cs index 8b62e3c9..882fa418 100644 --- a/de4dot.code/CommandLineParser.cs +++ b/de4dot.code/CommandLineParser.cs @@ -112,7 +112,7 @@ namespace de4dot { miscOptions.Add(new NoArgOption("d", null, "Detect obfuscators and exit", () => { filesOptions.DetectObfuscators = true; })); - miscOptions.Add(new OneArgOption(null, "asmpath", "Add an assembly search path", "path", (val) => { + miscOptions.Add(new OneArgOption(null, "asm-path", "Add an assembly search path", "path", (val) => { AssemblyResolver.Instance.addSearchDirectory(val); })); miscOptions.Add(new NoArgOption(null, "dont-rename", "Don't rename classes, methods, etc.", () => { From 65a9e7dbc156ecbb7b173718b27f4d5bb0375363 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 09:35:36 +0100 Subject: [PATCH 13/19] Add Silverlight assembly search paths --- de4dot.code/AssemblyResolver.cs | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/de4dot.code/AssemblyResolver.cs b/de4dot.code/AssemblyResolver.cs index dc560261..a1074311 100644 --- a/de4dot.code/AssemblyResolver.cs +++ b/de4dot.code/AssemblyResolver.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using Mono.Cecil; namespace de4dot { @@ -31,6 +32,56 @@ namespace de4dot { static AssemblyResolver() { // Make sure there's only ONE assembly resolver GlobalAssemblyResolver.Instance = Instance; + addSilverlightSearchPaths(); + } + + static void addSilverlightSearchPaths() { + addSilverlightSearchPaths(Environment.GetEnvironmentVariable("ProgramFiles")); + addSilverlightSearchPaths(Environment.GetEnvironmentVariable("ProgramFiles(x86)")); + } + + static void addSilverlightSearchPaths(string path) { + if (string.IsNullOrEmpty(path)) + return; + addSilverlightDirs(Path.Combine(path, @"Microsoft Silverlight")); + addIfExists(path, @"Microsoft SDKs\Silverlight\v3.0\Libraries\Client"); + addIfExists(path, @"Microsoft SDKs\Silverlight\v3.0\Libraries\Server"); + addIfExists(path, @"Microsoft SDKs\Silverlight\v4.0\Libraries\Client"); + addIfExists(path, @"Microsoft SDKs\Silverlight\v4.0\Libraries\Server"); + addIfExists(path, @"Reference Assemblies\Microsoft\Framework\Silverlight\v3.0"); + addIfExists(path, @"Reference Assemblies\Microsoft\Framework\Silverlight\v4.0"); + } + + // basePath is eg. "C:\Program Files (x86)\Microsoft Silverlight" + static void addSilverlightDirs(string basePath) { + try { + var di = new DirectoryInfo(basePath); + foreach (var dir in di.GetDirectories()) { + if (Regex.IsMatch(dir.Name, @"^\d+(?:\.\d+){3}$")) + addIfExists(basePath, dir.Name); + } + } + catch (Exception) { + } + } + + static void addIfExists(string basePath, string extraPath) { + try { + var path = Path.Combine(basePath, extraPath); + if (pathExists(path)) + Instance.addSearchDirectory(path); + } + catch (Exception) { + } + } + + static bool pathExists(string path) { + try { + return new DirectoryInfo(path).Exists; + } + catch (Exception) { + return false; + } } public void addSearchDirectory(string dir) { From fe2fe0befee65e462b86f4e0a2b723f447a936f9 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 09:45:34 +0100 Subject: [PATCH 14/19] Add Visual Studio public assemblies search paths --- de4dot.code/AssemblyResolver.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/de4dot.code/AssemblyResolver.cs b/de4dot.code/AssemblyResolver.cs index a1074311..64b763fd 100644 --- a/de4dot.code/AssemblyResolver.cs +++ b/de4dot.code/AssemblyResolver.cs @@ -32,15 +32,15 @@ namespace de4dot { static AssemblyResolver() { // Make sure there's only ONE assembly resolver GlobalAssemblyResolver.Instance = Instance; - addSilverlightSearchPaths(); + addOtherAssemblySearchPaths(); } - static void addSilverlightSearchPaths() { - addSilverlightSearchPaths(Environment.GetEnvironmentVariable("ProgramFiles")); - addSilverlightSearchPaths(Environment.GetEnvironmentVariable("ProgramFiles(x86)")); + static void addOtherAssemblySearchPaths() { + addOtherAssemblySearchPaths(Environment.GetEnvironmentVariable("ProgramFiles")); + addOtherAssemblySearchPaths(Environment.GetEnvironmentVariable("ProgramFiles(x86)")); } - static void addSilverlightSearchPaths(string path) { + static void addOtherAssemblySearchPaths(string path) { if (string.IsNullOrEmpty(path)) return; addSilverlightDirs(Path.Combine(path, @"Microsoft Silverlight")); @@ -50,6 +50,10 @@ namespace de4dot { addIfExists(path, @"Microsoft SDKs\Silverlight\v4.0\Libraries\Server"); addIfExists(path, @"Reference Assemblies\Microsoft\Framework\Silverlight\v3.0"); addIfExists(path, @"Reference Assemblies\Microsoft\Framework\Silverlight\v4.0"); + addIfExists(path, @"Microsoft Visual Studio .NET\Common7\IDE\PublicAssemblies"); + addIfExists(path, @"Microsoft Visual Studio 8.0\Common7\IDE\PublicAssemblies"); + addIfExists(path, @"Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies"); + addIfExists(path, @"Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies"); } // basePath is eg. "C:\Program Files (x86)\Microsoft Silverlight" From 34a11ee5552f49a4d2311e6b2a06ff56caf6ed36 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 09:56:51 +0100 Subject: [PATCH 15/19] Create methods to check whether a file/dir exists --- de4dot.code/AssemblyModule.cs | 2 +- de4dot.code/AssemblyResolver.cs | 11 +---------- de4dot.code/CommandLineParser.cs | 6 +++--- de4dot.code/FilesDeobfuscator.cs | 12 +++++++++--- de4dot.code/Utils.cs | 18 ++++++++++++++++++ 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/de4dot.code/AssemblyModule.cs b/de4dot.code/AssemblyModule.cs index e0f0b455..3baafd55 100644 --- a/de4dot.code/AssemblyModule.cs +++ b/de4dot.code/AssemblyModule.cs @@ -52,7 +52,7 @@ namespace de4dot { } void readMethodsFile() { - if (new FileInfo(methodsFilename).Exists) { + if (Utils.fileExists(methodsFilename)) { using (var reader = new BinaryReader(File.Open(methodsFilename, FileMode.Open, FileAccess.Read, FileShare.Read))) { dumpedMethods = new DumpedMethodsReader(reader).read(); } diff --git a/de4dot.code/AssemblyResolver.cs b/de4dot.code/AssemblyResolver.cs index 64b763fd..25926172 100644 --- a/de4dot.code/AssemblyResolver.cs +++ b/de4dot.code/AssemblyResolver.cs @@ -72,22 +72,13 @@ namespace de4dot { static void addIfExists(string basePath, string extraPath) { try { var path = Path.Combine(basePath, extraPath); - if (pathExists(path)) + if (Utils.pathExists(path)) Instance.addSearchDirectory(path); } catch (Exception) { } } - static bool pathExists(string path) { - try { - return new DirectoryInfo(path).Exists; - } - catch (Exception) { - return false; - } - } - public void addSearchDirectory(string dir) { if (!addedDirectories.ContainsKey(dir)) { addedDirectories[dir] = true; diff --git a/de4dot.code/CommandLineParser.cs b/de4dot.code/CommandLineParser.cs index 882fa418..1ab149b3 100644 --- a/de4dot.code/CommandLineParser.cs +++ b/de4dot.code/CommandLineParser.cs @@ -95,7 +95,7 @@ namespace de4dot { miscOptions.Add(new OneArgOption("r", null, "Scan for .NET files in all subdirs", "dir", (val) => { addSearchDir(); searchDir = new FilesDeobfuscator.SearchDir(); - if (!new DirectoryInfo(val).Exists) + if (!Utils.pathExists(val)) exitError(string.Format("Directory {0} does not exist", val)); searchDir.InputDirectory = val; })); @@ -152,7 +152,7 @@ namespace de4dot { defaultOption = new OneArgOption("f", null, "Name of .NET file", "file", (val) => { addFile(); - if (!new FileInfo(val).Exists) + if (!Utils.fileExists(val)) exitError(string.Format("File \"{0}\" does not exist.", val)); newFileOptions = new ObfuscatedFile.Options { Filename = val, @@ -168,7 +168,7 @@ namespace de4dot { fileOptions.Add(new OneArgOption("m", null, "Name of .methods file", "file", (val) => { if (newFileOptions == null) exitError("Missing input file"); - if (!new FileInfo(val).Exists) + if (!Utils.fileExists(val)) exitError(string.Format("File \"{0}\" does not exist.", val)); newFileOptions.MethodsFilename = val; })); diff --git a/de4dot.code/FilesDeobfuscator.cs b/de4dot.code/FilesDeobfuscator.cs index 7f67135d..e97419a4 100644 --- a/de4dot.code/FilesDeobfuscator.cs +++ b/de4dot.code/FilesDeobfuscator.cs @@ -300,9 +300,15 @@ namespace de4dot { void createDirectories(string path) { if (string.IsNullOrEmpty(path)) return; - var di = new DirectoryInfo(path); - if (!di.Exists) - di.Create(); + try { + var di = new DirectoryInfo(path); + if (!di.Exists) + di.Create(); + } + catch (System.Security.SecurityException) { + } + catch (ArgumentException) { + } } } diff --git a/de4dot.code/Utils.cs b/de4dot.code/Utils.cs index ed1f492e..0c974db6 100644 --- a/de4dot.code/Utils.cs +++ b/de4dot.code/Utils.cs @@ -198,5 +198,23 @@ namespace de4dot { return name; return name.Substring(0, i); } + + public static bool pathExists(string path) { + try { + return new DirectoryInfo(path).Exists; + } + catch (Exception) { + return false; + } + } + + public static bool fileExists(string path) { + try { + return new FileInfo(path).Exists; + } + catch (Exception) { + return false; + } + } } } From 198d5c3f746992023f0e088dcaf1eb002273ce7e Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 10:10:36 +0100 Subject: [PATCH 16/19] Remove memory manager from Main() --- .../deobfuscators/SmartAssembly/Deobfuscator.cs | 4 +++- .../SmartAssembly/MemoryManagerInfo.cs | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs index cbeb1b98..323673c6 100644 --- a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs @@ -291,8 +291,10 @@ namespace de4dot.deobfuscators.SmartAssembly { public override void deobfuscateBegin() { base.deobfuscateBegin(); - if (options.RemoveMemoryManager) + if (options.RemoveMemoryManager) { addModuleCctorInitCallToBeRemoved(memoryManagerInfo.CctorInitMethod); + addCallToBeRemoved(module.EntryPoint, memoryManagerInfo.CctorInitMethod); + } initDecrypters(); proxyDelegateFinder.find(); } diff --git a/de4dot.code/deobfuscators/SmartAssembly/MemoryManagerInfo.cs b/de4dot.code/deobfuscators/SmartAssembly/MemoryManagerInfo.cs index 8a523011..cbdc7399 100644 --- a/de4dot.code/deobfuscators/SmartAssembly/MemoryManagerInfo.cs +++ b/de4dot.code/deobfuscators/SmartAssembly/MemoryManagerInfo.cs @@ -44,11 +44,17 @@ namespace de4dot.deobfuscators.SmartAssembly { } bool find() { - var cctor = DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor"); - if (cctor == null) - return false; + if (checkCalledMethods(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor"))) + return true; + if (checkCalledMethods(module.EntryPoint)) + return true; + return false; + } - foreach (var tuple in DotNetUtils.getCalledMethods(module, cctor)) { + bool checkCalledMethods(MethodDefinition checkMethod) { + if (checkMethod == null) + return false; + foreach (var tuple in DotNetUtils.getCalledMethods(module, checkMethod)) { var method = tuple.Item2; if (method.Name == ".cctor" || method.Name == ".ctor") continue; From 432c321bab0183953ec25fd96b1b1ae0cd0c0e38 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 10:30:38 +0100 Subject: [PATCH 17/19] Catch SecurityDeclaration resolve exception --- de4dot.code/renamer/MemberRefFinder.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/de4dot.code/renamer/MemberRefFinder.cs b/de4dot.code/renamer/MemberRefFinder.cs index a6c875c0..bfc32574 100644 --- a/de4dot.code/renamer/MemberRefFinder.cs +++ b/de4dot.code/renamer/MemberRefFinder.cs @@ -91,13 +91,20 @@ namespace de4dot { Dictionary exceptionMessages = new Dictionary(StringComparer.Ordinal); void access(Action action) { + string exMessage = null; try { action(); } + catch (ResolutionException ex) { + exMessage = ex.Message; + } catch (AssemblyResolutionException ex) { - if (!exceptionMessages.ContainsKey(ex.Message)) { - exceptionMessages[ex.Message] = true; - Log.w("Could not resolve a reference. ERROR: {0}", ex.Message); + exMessage = ex.Message; + } + if (exMessage != null) { + if (!exceptionMessages.ContainsKey(exMessage)) { + exceptionMessages[exMessage] = true; + Log.w("Could not resolve a reference. ERROR: {0}", exMessage); } } } @@ -421,7 +428,7 @@ namespace de4dot { void addSecurityDeclaration(SecurityDeclaration decl) { if (decl == null) return; - addSecurityAttributes(decl.SecurityAttributes); + access(() => addSecurityAttributes(decl.SecurityAttributes)); } void addSecurityAttribute(SecurityAttribute attr) { if (attr == null) From 52c3c160cdab010a52f31e2bca79993fe2b126de Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 13:55:57 +0100 Subject: [PATCH 18/19] Add updated cecil submodule --- cecil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cecil b/cecil index 3bcc7cb1..070361f7 160000 --- a/cecil +++ b/cecil @@ -1 +1 @@ -Subproject commit 3bcc7cb109f9f44e1acd16c9bfd4f40d020917ba +Subproject commit 070361f78b3417369ee6385e570f6c9e93460071 From 51fc70169def4992a1be4b9aaf490f64c6b22522 Mon Sep 17 00:00:00 2001 From: de4dot Date: Sat, 5 Nov 2011 13:58:03 +0100 Subject: [PATCH 19/19] Handle case where asm resolver returns a later version --- de4dot.code/renamer/ExternalAssemblies.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/de4dot.code/renamer/ExternalAssemblies.cs b/de4dot.code/renamer/ExternalAssemblies.cs index e6dbffbb..65bd0a87 100644 --- a/de4dot.code/renamer/ExternalAssemblies.cs +++ b/de4dot.code/renamer/ExternalAssemblies.cs @@ -64,9 +64,20 @@ namespace de4dot.renamer { Log.w("Could not load assembly {0}", asmFullName); return null; } - Log.v("Loaded assembly {0}", asmFullName); + if (assemblies.ContainsKey(asmDef.Name.FullName)) { + assemblies[asmFullName] = assemblies[asmDef.Name.FullName]; + return assemblies[asmDef.Name.FullName]; + } - return assemblies[asmFullName] = asm = new ExternalAssembly(asmDef); + if (asmFullName == asmDef.Name.FullName) + Log.v("Loaded assembly {0}", asmFullName); + else + Log.v("Loaded assembly {0} (but wanted {1})", asmDef.Name.FullName, asmFullName); + + asm = new ExternalAssembly(asmDef); + assemblies[asmFullName] = asm; + assemblies[asmDef.Name.FullName] = asm; + return asm; } public TypeDefinition resolve(TypeReference type) {