diff --git a/blocks/DotNetUtils.cs b/blocks/DotNetUtils.cs index 84c6fc93..a495f6fb 100644 --- a/blocks/DotNetUtils.cs +++ b/blocks/DotNetUtils.cs @@ -305,7 +305,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/AssemblyModule.cs b/de4dot.code/AssemblyModule.cs index b869a341..8753d87a 100644 --- a/de4dot.code/AssemblyModule.cs +++ b/de4dot.code/AssemblyModule.cs @@ -45,8 +45,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); } public ModuleDefinition reload(byte[] newModuleData, Dictionary dumpedMethods) { @@ -63,7 +66,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 95729e93..fc0d1901 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,51 @@ namespace de4dot { static AssemblyResolver() { // Make sure there's only ONE assembly resolver GlobalAssemblyResolver.Instance = Instance; + addOtherAssemblySearchPaths(); + } + + static void addOtherAssemblySearchPaths() { + addOtherAssemblySearchPaths(Environment.GetEnvironmentVariable("ProgramFiles")); + addOtherAssemblySearchPaths(Environment.GetEnvironmentVariable("ProgramFiles(x86)")); + } + + static void addOtherAssemblySearchPaths(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"); + 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" + 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 (Utils.pathExists(path)) + Instance.addSearchDirectory(path); + } + catch (Exception) { + } } public void addSearchDirectory(string dir) { diff --git a/de4dot.code/CommandLineParser.cs b/de4dot.code/CommandLineParser.cs index dcfa24a2..7af6a59d 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; })); @@ -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.", () => { @@ -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 7e525a1a..18c12d58 100644 --- a/de4dot.code/FilesDeobfuscator.cs +++ b/de4dot.code/FilesDeobfuscator.cs @@ -198,6 +198,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); @@ -303,9 +309,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/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index f52488df..54032926 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -258,7 +258,7 @@ namespace de4dot { public void save() { Log.n("Saving {0}", options.NewFilename); - assemblyModule.save(options.NewFilename); + assemblyModule.save(options.NewFilename, options.ControlFlowDeobfuscation); } IList getAllMethods() { 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; + } + } } } diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index b7a87ef9..5ab97570 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -126,6 +126,7 @@ + diff --git a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs index 7ceb0e78..fb996e04 100644 --- a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs @@ -290,8 +290,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 c9ebb4cf..e07998be 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; 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 b3d182a3..c52d3b13 100644 --- a/de4dot.code/renamer/DefinitionsRenamer.cs +++ b/de4dot.code/renamer/DefinitionsRenamer.cs @@ -211,6 +211,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; @@ -504,7 +506,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 +523,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 +540,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) { diff --git a/de4dot.code/renamer/ExternalAssemblies.cs b/de4dot.code/renamer/ExternalAssemblies.cs index b0dc3b8a..69977563 100644 --- a/de4dot.code/renamer/ExternalAssemblies.cs +++ b/de4dot.code/renamer/ExternalAssemblies.cs @@ -69,9 +69,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] = 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) { 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) diff --git a/de4dot.code/renamer/MemberRefs.cs b/de4dot.code/renamer/MemberRefs.cs index aa2240f9..ea7905e4 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,103 @@ 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; + } + + Dictionary newMethodsNames = new Dictionary(); + public IDefFinder defFinder; public TypeInfo baseType = null; public IList interfaces = new List(); // directly implemented interfaces @@ -344,6 +442,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 +597,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 +612,71 @@ 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; + 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; @@ -635,6 +821,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). @@ -657,6 +850,9 @@ namespace de4dot.renamer { prepareRenameFields(); // must be first prepareRenameProperties(); prepareRenameEvents(); + + initializeEventHandlerNames(); + prepareRenameMethods(); // must be last } } @@ -726,6 +922,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) { @@ -739,6 +938,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)) @@ -754,6 +955,134 @@ 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; + 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; @@ -927,6 +1256,9 @@ namespace de4dot.renamer { methodDef.Renamed = true; bool canRenameMethodName = true; + if (suggestedName == null) + newMethodsNames.TryGetValue(methodDef, out suggestedName); + if (IsDelegate && methodDef.isVirtual()) { switch (methodDef.MethodDefinition.Name) { case "BeginInvoke": @@ -941,16 +1273,29 @@ namespace de4dot.renamer { if (canRenameMethodName) { 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.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; + } } } } @@ -961,21 +1306,23 @@ namespace de4dot.renamer { MemberRenameState.add(methodDef); } - string getPinvokeName(MethodDef methodDef) { - var methodNames = new Dictionary(StringComparer.Ordinal); - foreach (var method in methods.getAll()) - methodNames[method.NewName] = true; + 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; + } - if (methodDef.MethodDefinition.PInvokeInfo == null) - throw new ApplicationException(string.Format("PInvokeInfo is null: A type was probably removed but still referenced by the code.")); + 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); - while (true) { - var newName = MemberRenameState.variableNameState.pinvokeNameCreator.newName(entryPoint); - if (!methodNames.ContainsKey(newName)) - return newName; - } + return entryPoint; } INameCreator getMethodNameCreator(MethodDef methodDef, string suggestedName) { @@ -983,7 +1330,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; @@ -1007,8 +1354,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..04a2e7fc 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,19 @@ 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 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)); + } + + public string getNewMethodName(string oldName, INameCreator nameCreator) { + return currentMethodNames.newName(oldName, nameCreator); } }