Rename types

This commit is contained in:
de4dot 2011-11-17 04:17:03 +01:00
parent b58c3843e3
commit 195c7194cb
18 changed files with 956 additions and 18 deletions

View File

@ -20,6 +20,7 @@
using System.Collections.Generic;
using de4dot.deobfuscators;
using Mono.Cecil;
using de4dot.renamer;
namespace de4dot {
interface IObfuscatedFile {
@ -27,7 +28,7 @@ namespace de4dot {
IDeobfuscator Deobfuscator { get; }
string Filename { get; }
string NewFilename { get; }
Func<string, bool> IsValidName { get; }
INameChecker NameChecker { get; }
bool RenameResourcesInCode { get; }
bool RenameSymbols { get; }
bool RemoveNamespaceWithOneType { get; }

View File

@ -29,6 +29,7 @@ using de4dot.deobfuscators;
using de4dot.blocks;
using de4dot.blocks.cflow;
using de4dot.AssemblyClient;
using de4dot.renamer;
namespace de4dot {
class ObfuscatedFile : IObfuscatedFile, IDeobfuscatedFile {
@ -106,8 +107,8 @@ namespace de4dot {
get { return module; }
}
public Func<string, bool> IsValidName {
get { return deob.IsValidName; }
public INameChecker NameChecker {
get { return deob; }
}
public bool RenameResourcesInCode {

View File

@ -156,6 +156,7 @@
<Compile Include="renamer\asmmodules\EventDef.cs" />
<Compile Include="renamer\asmmodules\ExternalAssemblies.cs" />
<Compile Include="renamer\asmmodules\FieldDef.cs" />
<Compile Include="renamer\asmmodules\GenericParamDef.cs" />
<Compile Include="renamer\asmmodules\IResolver.cs" />
<Compile Include="renamer\asmmodules\MemberRefFinder.cs" />
<Compile Include="renamer\asmmodules\MethodDef.cs" />
@ -166,7 +167,12 @@
<Compile Include="renamer\asmmodules\Ref.cs" />
<Compile Include="renamer\asmmodules\RefDict.cs" />
<Compile Include="renamer\asmmodules\TypeDef.cs" />
<Compile Include="renamer\DerivedFrom.cs" />
<Compile Include="renamer\ExistingNames.cs" />
<Compile Include="renamer\INameChecker.cs" />
<Compile Include="renamer\NameCreators.cs" />
<Compile Include="renamer\Renamer.cs" />
<Compile Include="renamer\TypeRenamerState.cs" />
<Compile Include="StringDecrypter.cs" />
<Compile Include="UserException.cs" />
<Compile Include="Utils.cs" />

View File

@ -77,10 +77,6 @@ namespace de4dot.deobfuscators {
get { return false; }
}
public Func<string, bool> IsValidName {
get { return (name) => checkValidName(name); }
}
public DeobfuscatorBase(OptionsBase optionsBase) {
this.optionsBase = optionsBase;
StringFeatures = StringFeatures.AllowAll;
@ -502,5 +498,37 @@ namespace de4dot.deobfuscators {
var list = new List<CustomAttribute>(DotNetUtils.findAttributes(module.Assembly, attr));
return list.Count == 0 ? null : list[0];
}
public bool isValidNamespaceName(string ns) {
return checkValidName(ns);
}
public bool isValidTypeName(string name) {
return checkValidName(name);
}
public bool isValidMethodName(string name) {
return checkValidName(name);
}
public bool isValidPropertyName(string name) {
return checkValidName(name);
}
public bool isValidEventName(string name) {
return checkValidName(name);
}
public bool isValidFieldName(string name) {
return checkValidName(name);
}
public bool isValidGenericParamName(string name) {
return checkValidName(name);
}
public bool isValidMethodArgName(string name) {
return checkValidName(name);
}
}
}

View File

@ -22,6 +22,7 @@ using System.Collections.Generic;
using Mono.Cecil;
using Mono.MyStuff;
using de4dot.blocks;
using de4dot.renamer;
namespace de4dot.deobfuscators {
interface IDeobfuscatorOptions {
@ -49,11 +50,10 @@ namespace de4dot.deobfuscators {
RemoveNamespaceIfOneType = 1,
}
interface IDeobfuscator {
interface IDeobfuscator : INameChecker {
string Type { get; }
string TypeLong { get; }
string Name { get; }
Func<string, bool> IsValidName { get; }
IDeobfuscatorOptions TheOptions { get; }
IOperations Operations { get; set; }
StringFeatures StringFeatures { get; }

View File

@ -34,7 +34,7 @@ namespace de4dot.old_renamer {
List<MethodDefinition> allMethods;
public Func<string, bool> IsValidName {
get { return obfuscatedFile.IsValidName; }
get { return null; }
}
class RefToDef<R, D> where R : MemberReference where D : R {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using de4dot.renamer.asmmodules;
namespace de4dot.renamer {
class DerivedFrom {
Dictionary<string, bool> classNames = new Dictionary<string, bool>(StringComparer.Ordinal);
Dictionary<TypeDef, bool> results = new Dictionary<TypeDef, bool>();
public DerivedFrom(string className) {
addName(className);
}
public DerivedFrom(string[] classNames) {
foreach (var className in classNames)
addName(className);
}
void addName(string className) {
classNames[className] = true;
}
public bool check(TypeDef type) {
if (results.ContainsKey(type))
return results[type];
bool val;
if (classNames.ContainsKey(type.TypeDefinition.FullName))
val = true;
else if (type.baseType == null) {
if (type.TypeDefinition.BaseType != null)
val = classNames.ContainsKey(type.TypeDefinition.BaseType.FullName);
else
val = false;
}
else
val = check(type.baseType.typeDef);
results[type] = val;
return val;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace de4dot.renamer {
class ExistingNames {
Dictionary<string, bool> allNames = new Dictionary<string, bool>(StringComparer.Ordinal);
public void add(string name) {
allNames[name] = true;
}
bool exists(string name) {
return allNames.ContainsKey(name);
}
public string getName(string oldName, INameCreator nameCreator) {
return getName(oldName, () => nameCreator.create());
}
public string getName(string oldName, Func<string> 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 ExistingNames clone() {
var cn = new ExistingNames();
foreach (var key in allNames.Keys)
cn.allNames[key] = true;
return cn;
}
}
}

View File

@ -0,0 +1,31 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
namespace de4dot.renamer {
interface INameChecker {
bool isValidNamespaceName(string ns);
bool isValidTypeName(string name);
bool isValidMethodName(string name);
bool isValidPropertyName(string name);
bool isValidEventName(string name);
bool isValidFieldName(string name);
bool isValidGenericParamName(string name);
bool isValidMethodArgName(string name);
}
}

View File

@ -0,0 +1,229 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using Mono.Cecil;
using de4dot.blocks;
namespace de4dot.renamer {
interface INameCreator {
INameCreator clone();
string create();
}
class OneNameCreator : INameCreator {
string name;
public OneNameCreator(string name) {
this.name = name;
}
public INameCreator clone() {
return this;
}
public string create() {
return name;
}
}
class GlobalNameCreator : INameCreator {
INameCreator other;
public GlobalNameCreator(INameCreator other) {
this.other = other;
}
public INameCreator clone() {
return this;
}
public string create() {
return other.create();
}
}
class GenericParamNameCreator : INameCreator {
static string[] names = new string[] { "T", "U", "V", "W", "X", "Y", "Z" };
int index = 0;
public string create() {
if (index < names.Length)
return names[index++];
return string.Format("T{0}", index++);
}
public INameCreator clone() {
var rv = new GenericParamNameCreator();
rv.index = index;
return rv;
}
}
class NameCreator : INameCreator {
string prefix;
int num;
public NameCreator(string prefix, int num = 0) {
this.prefix = prefix;
this.num = num;
}
public INameCreator clone() {
return new NameCreator(prefix, num);
}
public string create() {
return prefix + num++;
}
}
// Like NameCreator but don't add the counter the first time
class NameCreator2 : INameCreator {
string prefix;
int num;
const string separator = "_";
public NameCreator2(string prefix, int num = 0) {
this.prefix = prefix;
this.num = num;
}
public INameCreator clone() {
return new NameCreator2(prefix, num);
}
public string create() {
string rv;
if (num == 0)
rv = prefix;
else
rv = prefix + separator + num;
num++;
return rv;
}
}
interface ITypeNameCreator {
string create(TypeDefinition typeDefinition, string newBaseTypeName = null);
}
class NameInfos {
IList<NameInfo> nameInfos = new List<NameInfo>();
class NameInfo {
public string name;
public INameCreator nameCreator;
public NameInfo(string name, INameCreator nameCreator) {
this.name = name;
this.nameCreator = nameCreator;
}
}
public void add(string name, INameCreator nameCreator) {
nameInfos.Add(new NameInfo(name, nameCreator));
}
public INameCreator find(string typeName) {
foreach (var nameInfo in nameInfos) {
if (typeName.Contains(nameInfo.name))
return nameInfo.nameCreator;
}
return null;
}
}
class TypeNameCreator : ITypeNameCreator {
ExistingNames existingNames;
INameCreator createUnknownTypeName;
INameCreator createEnumName;
INameCreator createStructName;
INameCreator createDelegateName;
INameCreator createClassName;
INameCreator createInterfaceName;
NameInfos nameInfos = new NameInfos();
public TypeNameCreator(ExistingNames existingNames) {
this.existingNames = existingNames;
createUnknownTypeName = createNameCreator("Type");
createEnumName = createNameCreator("Enum");
createStructName = createNameCreator("Struct");
createDelegateName = createNameCreator("Delegate");
createClassName = createNameCreator("Class");
createInterfaceName = createNameCreator("Interface");
var names = new string[] {
"Exception",
"EventArgs",
"Attribute",
"Form",
"Dialog",
"Control",
};
foreach (var name in names)
nameInfos.add(name, createNameCreator(name));
}
protected virtual INameCreator createNameCreator(string prefix) {
return new NameCreator(prefix);
}
public string create(TypeDefinition typeDefinition, string newBaseTypeName = null) {
var nameCreator = getNameCreator(typeDefinition, newBaseTypeName);
return existingNames.getName(typeDefinition.Name, nameCreator);
}
INameCreator getNameCreator(TypeDefinition typeDefinition, string newBaseTypeName) {
var nameCreator = createUnknownTypeName;
if (typeDefinition.IsEnum)
nameCreator = createEnumName;
else if (typeDefinition.IsValueType)
nameCreator = createStructName;
else if (typeDefinition.IsClass) {
if (typeDefinition.BaseType != null) {
if (MemberReferenceHelper.verifyType(typeDefinition.BaseType, "mscorlib", "System.Delegate"))
nameCreator = createDelegateName;
else if (MemberReferenceHelper.verifyType(typeDefinition.BaseType, "mscorlib", "System.MulticastDelegate"))
nameCreator = createDelegateName;
else {
nameCreator = nameInfos.find(newBaseTypeName ?? typeDefinition.BaseType.Name);
if (nameCreator == null)
nameCreator = createClassName;
}
}
else
nameCreator = createClassName;
}
else if (typeDefinition.IsInterface)
nameCreator = createInterfaceName;
return nameCreator;
}
}
class GlobalTypeNameCreator : TypeNameCreator {
public GlobalTypeNameCreator(ExistingNames existingNames)
: base(existingNames) {
}
protected override INameCreator createNameCreator(string prefix) {
return new GlobalNameCreator(base.createNameCreator("G" + prefix));
}
}
}

View File

@ -17,21 +17,177 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
using de4dot.renamer.asmmodules;
namespace de4dot.renamer {
class MemberInfo {
Ref memberRef;
public string oldFullName;
public string oldName;
public string newName;
public bool renamed;
public MemberInfo(Ref memberRef) {
this.memberRef = memberRef;
oldFullName = memberRef.memberReference.FullName;
oldName = memberRef.memberReference.Name;
newName = memberRef.memberReference.Name;
}
public void rename(string newTypeName) {
renamed = true;
newName = newTypeName;
}
public bool gotNewName() {
return oldName != newName;
}
}
class TypeInfo : MemberInfo {
public string oldNamespace;
public string newNamespace;
public TypeInfo(TypeDef type)
: base(type) {
oldNamespace = type.TypeDefinition.Namespace;
}
}
class GenericParamInfo : MemberInfo {
public GenericParamInfo(GenericParamDef genericParamDef)
: base(genericParamDef) {
}
}
class Renamer {
bool renameSymbols = true;
bool renameFields = true;
bool renameProperties = true;
bool renameEvents = true;
bool renameMethods = true;
public bool RenameNamespaces { get; set; }
public bool RenameTypes { get; set; }
public bool RenameProperties { get; set; }
public bool RenameEvents { get; set; }
public bool RenameFields { get; set; }
public bool RenameGenericParams { get; set; }
public bool RenameMethodArgs { get; set; }
Modules modules = new Modules();
DerivedFrom isWinFormsClass;
Dictionary<TypeDef, TypeInfo> allTypeInfos = new Dictionary<TypeDef, TypeInfo>();
Dictionary<GenericParamDef, GenericParamInfo> allGenericParamInfos = new Dictionary<GenericParamDef, GenericParamInfo>();
Dictionary<MethodDef, string> suggestedMethodNames = new Dictionary<MethodDef, string>();
static string[] WINFORMS_CLASSES = new string[] {
#region Win Forms class names
"System.Windows.Forms.Control",
"System.Windows.Forms.AxHost",
"System.Windows.Forms.ButtonBase",
"System.Windows.Forms.Button",
"System.Windows.Forms.CheckBox",
"System.Windows.Forms.RadioButton",
"System.Windows.Forms.DataGrid",
"System.Windows.Forms.DataGridView",
"System.Windows.Forms.DataVisualization.Charting.Chart",
"System.Windows.Forms.DateTimePicker",
"System.Windows.Forms.GroupBox",
"System.Windows.Forms.Integration.ElementHost",
"System.Windows.Forms.Label",
"System.Windows.Forms.LinkLabel",
"System.Windows.Forms.ListControl",
"System.Windows.Forms.ComboBox",
"Microsoft.VisualBasic.Compatibility.VB6.DriveListBox",
"System.Windows.Forms.DataGridViewComboBoxEditingControl",
"System.Windows.Forms.ListBox",
"Microsoft.VisualBasic.Compatibility.VB6.DirListBox",
"Microsoft.VisualBasic.Compatibility.VB6.FileListBox",
"System.Windows.Forms.CheckedListBox",
"System.Windows.Forms.ListView",
"System.Windows.Forms.MdiClient",
"System.Windows.Forms.MonthCalendar",
"System.Windows.Forms.PictureBox",
"System.Windows.Forms.PrintPreviewControl",
"System.Windows.Forms.ProgressBar",
"System.Windows.Forms.ScrollableControl",
"System.Windows.Forms.ContainerControl",
"System.Windows.Forms.Form",
"System.ComponentModel.Design.CollectionEditor.CollectionForm",
"System.Messaging.Design.QueuePathDialog",
"System.ServiceProcess.Design.ServiceInstallerDialog",
"System.Web.UI.Design.WebControls.CalendarAutoFormatDialog",
"System.Web.UI.Design.WebControls.RegexEditorDialog",
"System.Windows.Forms.Design.ComponentEditorForm",
"System.Windows.Forms.PrintPreviewDialog",
"System.Windows.Forms.ThreadExceptionDialog",
"System.Workflow.Activities.Rules.Design.RuleConditionDialog",
"System.Workflow.Activities.Rules.Design.RuleSetDialog",
"System.Workflow.ComponentModel.Design.ThemeConfigurationDialog",
"System.Workflow.ComponentModel.Design.TypeBrowserDialog",
"System.Workflow.ComponentModel.Design.WorkflowPageSetupDialog",
"System.Windows.Forms.PropertyGrid",
"System.Windows.Forms.SplitContainer",
"System.Windows.Forms.ToolStripContainer",
"System.Windows.Forms.ToolStripPanel",
"System.Windows.Forms.UpDownBase",
"System.Windows.Forms.DomainUpDown",
"System.Windows.Forms.NumericUpDown",
"System.Windows.Forms.UserControl",
"Microsoft.VisualBasic.Compatibility.VB6.ADODC",
"System.Web.UI.Design.WebControls.ParameterEditorUserControl",
"System.Workflow.ComponentModel.Design.WorkflowOutline",
"System.Workflow.ComponentModel.Design.WorkflowView",
"System.Windows.Forms.Design.ComponentTray",
"System.Windows.Forms.Panel",
"System.Windows.Forms.Design.ComponentEditorPage",
"System.Windows.Forms.FlowLayoutPanel",
"System.Windows.Forms.SplitterPanel",
"System.Windows.Forms.TableLayoutPanel",
"System.ComponentModel.Design.ByteViewer",
"System.Windows.Forms.TabPage",
"System.Windows.Forms.ToolStripContentPanel",
"System.Windows.Forms.ToolStrip",
"System.Windows.Forms.BindingNavigator",
"System.Windows.Forms.MenuStrip",
"System.Windows.Forms.StatusStrip",
"System.Windows.Forms.ToolStripDropDown",
"System.Windows.Forms.ToolStripDropDownMenu",
"System.Windows.Forms.ContextMenuStrip",
"System.Windows.Forms.ToolStripOverflow",
"System.Windows.Forms.ScrollBar",
"System.Windows.Forms.HScrollBar",
"System.Windows.Forms.VScrollBar",
"System.Windows.Forms.Splitter",
"System.Windows.Forms.StatusBar",
"System.Windows.Forms.TabControl",
"System.Windows.Forms.TextBoxBase",
"System.Windows.Forms.MaskedTextBox",
"System.Windows.Forms.RichTextBox",
"System.Windows.Forms.TextBox",
"System.Windows.Forms.DataGridTextBox",
"System.Windows.Forms.DataGridViewTextBoxEditingControl",
"System.Windows.Forms.ToolBar",
"System.Windows.Forms.TrackBar",
"System.Windows.Forms.TreeView",
"System.ComponentModel.Design.ObjectSelectorEditor.Selector",
"System.Windows.Forms.WebBrowserBase",
"System.Windows.Forms.WebBrowser",
#endregion
};
public Renamer(IEnumerable<IObfuscatedFile> files) {
RenameNamespaces = true;
RenameTypes = true;
RenameProperties = true;
RenameEvents = true;
RenameFields = true;
RenameGenericParams = true;
RenameMethodArgs = true;
foreach (var file in files)
modules.add(new Module(file));
isWinFormsClass = new DerivedFrom(WINFORMS_CLASSES);
}
public void rename() {
@ -41,7 +197,224 @@ namespace de4dot.renamer {
modules.initialize();
modules.initializeVirtualMembers();
renameTypeDefinitions();
modules.cleanUp();
}
void renameTypeDefinitions() {
Log.v("Renaming obfuscated type definitions");
prepareRenameTypes();
}
void prepareRenameTypes() {
foreach (var type in modules.AllTypes)
allTypeInfos[type] = new TypeInfo(type);
var state = new TypeRenamerState();
prepareRenameTypes(modules.BaseTypes, state);
fixClsTypeNames();
renameTypeDefinitions(modules.NonNestedTypes);
}
void renameTypeDefinitions(IEnumerable<TypeDef> typeDefs) {
Log.indent();
foreach (var typeDef in typeDefs) {
rename(typeDef);
renameTypeDefinitions(typeDef.NestedTypes);
}
Log.deIndent();
}
void rename(TypeDef type) {
var typeDefinition = type.TypeDefinition;
var info = allTypeInfos[type];
Log.v("Type: {0} ({1:X8})", typeDefinition.FullName, typeDefinition.MetadataToken.ToUInt32());
Log.indent();
renameGenericParams(type.GenericParams);
if (RenameTypes && info.gotNewName()) {
var old = typeDefinition.Name;
typeDefinition.Name = info.newName;
Log.v("Name: {0} => {1}", old, typeDefinition.Name);
}
if (RenameNamespaces && info.newNamespace != null) {
var old = typeDefinition.Namespace;
typeDefinition.Namespace = info.newNamespace;
Log.v("Namespace: {0} => {1}", old, typeDefinition.Namespace);
}
Log.deIndent();
}
void renameGenericParams(IEnumerable<GenericParamDef> genericParams) {
if (!RenameGenericParams)
return;
foreach (var param in genericParams) {
var info = allGenericParamInfos[param];
if (!info.gotNewName())
continue;
param.GenericParameter.Name = info.newName;
Log.v("GenParam: {0} => {1}", info.oldFullName, param.GenericParameter.FullName);
}
}
// Make sure the renamed types are using valid CLS names. That means renaming all
// generic types from eg. Class1 to Class1`2. If we don't do this, some decompilers
// (eg. ILSpy v1.0) won't produce correct output.
void fixClsTypeNames() {
foreach (var type in modules.NonNestedTypes)
fixClsTypeNames(null, type);
}
void fixClsTypeNames(TypeDef nesting, TypeDef nested) {
int nestingCount = nesting == null ? 0 : nesting.GenericParams.Count;
int arity = nested.GenericParams.Count - nestingCount;
var nestedInfo = allTypeInfos[nested];
if (nestedInfo.renamed && arity > 0)
nestedInfo.newName += "`" + arity;
foreach (var nestedType in nested.NestedTypes)
fixClsTypeNames(nested, nestedType);
}
void prepareRenameTypes(IEnumerable<TypeDef> types, TypeRenamerState state) {
foreach (var typeDef in types) {
prepareRenameTypes(typeDef, state);
prepareRenameTypes(typeDef.derivedTypes, state);
}
}
void prepareRenameTypes(TypeDef type, TypeRenamerState state) {
var info = allTypeInfos[type];
var checker = type.Module.ObfuscatedFile.NameChecker;
if (RenameNamespaces) {
if (info.newNamespace == null && info.oldNamespace != "") {
if (!checker.isValidNamespaceName(info.oldNamespace)) {
info.newNamespace = state.createNamespace(info.oldNamespace);
}
}
}
if (RenameTypes) {
if (info.oldFullName != "<Module>" && !checker.isValidTypeName(info.oldName)) {
string origClassName = null;
if (isWinFormsClass.check(type))
origClassName = findWindowsFormsClassName(type);
if (origClassName != null && checker.isValidTypeName(origClassName))
info.rename(state.getTypeName(info.oldName, origClassName));
else {
ITypeNameCreator nameCreator = type.isGlobalType() ?
state.globalTypeNameCreator :
state.internalTypeNameCreator;
string newBaseType = null;
TypeInfo baseInfo;
if (type.baseType != null && allTypeInfos.TryGetValue(type.baseType.typeDef, out baseInfo)) {
if (baseInfo.renamed)
newBaseType = baseInfo.newName;
}
info.rename(nameCreator.create(type.TypeDefinition, newBaseType));
}
}
}
if (RenameGenericParams)
prepareRenameGenericParams(type.GenericParams, checker);
}
void prepareRenameGenericParams(IEnumerable<GenericParamDef> genericParams, INameChecker checker, IEnumerable<GenericParamDef> otherGenericParams = null) {
var usedNames = new Dictionary<string, bool>(StringComparer.Ordinal);
var nameCreator = new GenericParamNameCreator();
foreach (var gp in genericParams)
allGenericParamInfos[gp] = new GenericParamInfo(gp);
if (otherGenericParams != null) {
foreach (var param in otherGenericParams) {
var gpInfo = allGenericParamInfos[param];
usedNames[gpInfo.newName] = true;
}
}
foreach (var param in genericParams) {
var gpInfo = allGenericParamInfos[param];
if (!checker.isValidGenericParamName(gpInfo.oldName) || usedNames.ContainsKey(gpInfo.oldName)) {
string newName;
do {
newName = nameCreator.create();
} while (usedNames.ContainsKey(newName));
usedNames[newName] = true;
gpInfo.rename(newName);
}
}
}
string findWindowsFormsClassName(TypeDef type) {
foreach (var methodDef in type.getAllMethods()) {
if (methodDef.MethodDefinition.Body == null)
continue;
if (methodDef.MethodDefinition.IsStatic || methodDef.MethodDefinition.IsVirtual)
continue;
var instructions = methodDef.MethodDefinition.Body.Instructions;
for (int i = 2; i < instructions.Count; i++) {
var call = instructions[i];
if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt)
continue;
if (!isWindowsFormsSetNameMethod(call.Operand as MethodReference))
continue;
var ldstr = instructions[i - 1];
if (ldstr.OpCode.Code != Code.Ldstr)
continue;
var className = ldstr.Operand as string;
if (className == null)
continue;
if (DotNetUtils.getArgIndex(methodDef.MethodDefinition, instructions[i - 2]) != 0)
continue;
findInitializeComponentMethod(type, methodDef);
return className;
}
}
return null;
}
void findInitializeComponentMethod(TypeDef type, MethodDef possibleInitMethod) {
foreach (var methodDef in type.getAllMethods()) {
if (methodDef.MethodDefinition.Name != ".ctor")
continue;
if (methodDef.MethodDefinition.Body == null)
continue;
foreach (var instr in methodDef.MethodDefinition.Body.Instructions) {
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
continue;
if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(possibleInitMethod.MethodDefinition, instr.Operand as MethodReference))
continue;
suggestedMethodNames[possibleInitMethod] = "InitializeComponent";
return;
}
}
}
static bool isWindowsFormsSetNameMethod(MethodReference method) {
if (method == null)
return false;
if (method.Name != "set_Name")
return false;
if (method.MethodReturnType.ReturnType.FullName != "System.Void")
return false;
if (method.Parameters.Count != 1)
return false;
if (method.Parameters[0].ParameterType.FullName != "System.String")
return false;
if (!method.DeclaringType.FullName.StartsWith("System.Windows.Forms.", StringComparison.Ordinal))
return false;
return true;
}
}
}

View File

@ -0,0 +1,50 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace de4dot.renamer {
class TypeRenamerState {
ExistingNames existingNames;
Dictionary<string, string> namespaceToNewName;
INameCreator createNamespaceName;
public ITypeNameCreator globalTypeNameCreator;
public ITypeNameCreator internalTypeNameCreator;
public TypeRenamerState() {
existingNames = new ExistingNames();
namespaceToNewName = new Dictionary<string, string>(StringComparer.Ordinal);
createNamespaceName = new GlobalNameCreator(new NameCreator("ns"));
globalTypeNameCreator = new GlobalTypeNameCreator(existingNames);
internalTypeNameCreator = new TypeNameCreator(existingNames);
}
public string getTypeName(string oldName, string newName) {
return existingNames.getName(oldName, new NameCreator2(newName));
}
public string createNamespace(string ns) {
string newName;
if (namespaceToNewName.TryGetValue(ns, out newName))
return newName;
return namespaceToNewName[ns] = createNamespaceName.create();
}
}
}

View File

@ -0,0 +1,43 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using Mono.Cecil;
namespace de4dot.renamer.asmmodules {
class GenericParamDef : Ref {
public GenericParameter GenericParameter {
get { return (GenericParameter)memberReference; }
}
public GenericParamDef(GenericParameter genericParameter, int index)
: base(genericParameter, null, index) {
}
public static List<GenericParamDef> createGenericParamDefList(IEnumerable<GenericParameter> parameters) {
var list = new List<GenericParamDef>();
if (parameters == null)
return list;
int i = 0;
foreach (var param in parameters)
list.Add(new GenericParamDef(param, i++));
return list;
}
}
}

View File

@ -17,16 +17,20 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using Mono.Cecil;
namespace de4dot.renamer.asmmodules {
class MethodDef : Ref {
IList<GenericParamDef> genericParams;
public MethodDefinition MethodDefinition {
get { return (MethodDefinition)memberReference; }
}
public MethodDef(MethodDefinition methodDefinition, TypeDef owner, int index)
: base(methodDefinition, owner, index) {
genericParams = GenericParamDef.createGenericParamDefList(MethodDefinition.GenericParameters);
}
public bool isPublic() {

View File

@ -40,6 +40,10 @@ namespace de4dot.renamer.asmmodules {
}
}
public IObfuscatedFile ObfuscatedFile {
get { return obfuscatedFile; }
}
public string Filename {
get { return obfuscatedFile.Filename; }
}

View File

@ -30,8 +30,20 @@ namespace de4dot.renamer.asmmodules {
AssemblyHash assemblyHash = new AssemblyHash();
List<TypeDef> allTypes = new List<TypeDef>();
List<TypeDef> baseTypes = new List<TypeDef>(); //TODO: Do we need this?
List<TypeDef> nonNestedTypes; //TODO: Do we need this?
List<TypeDef> baseTypes = new List<TypeDef>();
List<TypeDef> nonNestedTypes;
public IEnumerable<TypeDef> AllTypes {
get { return allTypes; }
}
public IEnumerable<TypeDef> BaseTypes {
get { return baseTypes; }
}
public List<TypeDef> NonNestedTypes {
get { return nonNestedTypes; }
}
class AssemblyHash {
IDictionary<string, ModuleHash> assemblyHash = new Dictionary<string, ModuleHash>(StringComparer.Ordinal);

View File

@ -21,7 +21,7 @@ using Mono.Cecil;
namespace de4dot.renamer.asmmodules {
abstract class Ref {
protected readonly MemberReference memberReference;
public readonly MemberReference memberReference;
public int Index { get; set; }
public TypeDef Owner { get; set; }

View File

@ -204,6 +204,7 @@ namespace de4dot.renamer.asmmodules {
MethodDefDict methods = new MethodDefDict();
PropertyDefDict properties = new PropertyDefDict();
TypeDefDict types = new TypeDefDict();
List<GenericParamDef> genericParams;
internal TypeInfo baseType = null;
internal IList<TypeInfo> interfaces = new List<TypeInfo>(); // directly implemented interfaces
internal IList<TypeDef> derivedTypes = new List<TypeDef>();
@ -214,10 +215,18 @@ namespace de4dot.renamer.asmmodules {
Dictionary<TypeInfo, bool> allImplementedInterfaces = new Dictionary<TypeInfo, bool>();
InterfaceMethodInfos interfaceMethodInfos = new InterfaceMethodInfos();
public Module Module {
get { return module; }
}
public bool HasModule {
get { return module != null; }
}
public IList<GenericParamDef> GenericParams {
get { return genericParams; }
}
public IEnumerable<TypeDef> NestedTypes {
get { return types.getSorted(); }
}
@ -231,6 +240,7 @@ namespace de4dot.renamer.asmmodules {
public TypeDef(TypeDefinition typeDefinition, Module module, int index)
: base(typeDefinition, null, index) {
this.module = module;
genericParams = GenericParamDef.createGenericParamDefList(TypeDefinition.GenericParameters);
}
public void addInterface(TypeDef ifaceDef, TypeReference iface) {
@ -290,6 +300,28 @@ namespace de4dot.renamer.asmmodules {
add(new PropertyDef(type.Properties[i], this, i));
}
public bool isNested() {
return NestingType != null;
}
public bool isGlobalType() {
if (!isNested())
return TypeDefinition.IsPublic;
var mask = TypeDefinition.Attributes & TypeAttributes.VisibilityMask;
switch (mask) {
case TypeAttributes.NestedPrivate:
case TypeAttributes.NestedAssembly:
case TypeAttributes.NestedFamANDAssem:
return false;
case TypeAttributes.NestedPublic:
case TypeAttributes.NestedFamily:
case TypeAttributes.NestedFamORAssem:
return NestingType.isGlobalType();
default:
return false;
}
}
public void initializeVirtualMembers(MethodNameScopes scopes, IResolver resolver) {
if (initializeVirtualMembersCalled)
return;