2011-11-15 21:26:51 +08:00
|
|
|
|
/*
|
|
|
|
|
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 de4dot.renamer.asmmodules;
|
|
|
|
|
|
|
|
|
|
namespace de4dot.renamer {
|
|
|
|
|
class Renamer {
|
2011-11-17 11:17:03 +08:00
|
|
|
|
public bool RenameNamespaces { get; set; }
|
|
|
|
|
public bool RenameTypes { get; set; }
|
2011-11-18 23:55:54 +08:00
|
|
|
|
public bool RenameGenericParams { get; set; }
|
2011-11-17 11:17:03 +08:00
|
|
|
|
public bool RenameProperties { get; set; }
|
|
|
|
|
public bool RenameEvents { get; set; }
|
|
|
|
|
public bool RenameFields { get; set; }
|
2011-11-18 23:55:54 +08:00
|
|
|
|
public bool RenameMethods { get; set; }
|
2011-11-17 11:17:03 +08:00
|
|
|
|
public bool RenameMethodArgs { get; set; }
|
2011-11-15 21:26:51 +08:00
|
|
|
|
Modules modules = new Modules();
|
2011-11-18 23:55:54 +08:00
|
|
|
|
MemberInfos memberInfos = new MemberInfos();
|
2011-11-15 21:26:51 +08:00
|
|
|
|
|
|
|
|
|
public Renamer(IEnumerable<IObfuscatedFile> files) {
|
2011-11-17 11:17:03 +08:00
|
|
|
|
RenameNamespaces = true;
|
|
|
|
|
RenameTypes = true;
|
|
|
|
|
RenameProperties = true;
|
|
|
|
|
RenameEvents = true;
|
|
|
|
|
RenameFields = true;
|
|
|
|
|
RenameGenericParams = true;
|
|
|
|
|
RenameMethodArgs = true;
|
|
|
|
|
|
2011-11-15 21:26:51 +08:00
|
|
|
|
foreach (var file in files)
|
|
|
|
|
modules.add(new Module(file));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void rename() {
|
|
|
|
|
if (modules.Empty)
|
|
|
|
|
return;
|
|
|
|
|
Log.n("Renaming all obfuscated symbols");
|
|
|
|
|
|
|
|
|
|
modules.initialize();
|
2011-11-17 06:08:27 +08:00
|
|
|
|
modules.initializeVirtualMembers();
|
2011-11-18 23:55:54 +08:00
|
|
|
|
memberInfos.initialize(modules);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
renameTypeDefinitions();
|
2011-11-18 23:55:54 +08:00
|
|
|
|
renameTypeReferences();
|
|
|
|
|
modules.onTypesRenamed();
|
|
|
|
|
prepareRenameMemberDefinitions();
|
2011-11-17 06:08:27 +08:00
|
|
|
|
modules.cleanUp();
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
|
|
|
|
void renameTypeDefinitions() {
|
|
|
|
|
Log.v("Renaming obfuscated type definitions");
|
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
prepareRenameTypes(modules.BaseTypes, new TypeRenamerState());
|
2011-11-17 11:17:03 +08:00
|
|
|
|
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;
|
2011-11-18 23:55:54 +08:00
|
|
|
|
var info = memberInfos.type(type);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
|
|
|
|
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) {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
var info = memberInfos.gparam(param);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
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;
|
2011-11-18 23:55:54 +08:00
|
|
|
|
var nestedInfo = memberInfos.type(nested);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
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) {
|
2011-11-18 23:55:54 +08:00
|
|
|
|
memberInfos.type(typeDef).prepareRenameTypes(state);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
prepareRenameTypes(typeDef.derivedTypes, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
void renameTypeReferences() {
|
|
|
|
|
Log.v("Renaming references to type definitions");
|
|
|
|
|
var theModules = modules.TheModules;
|
|
|
|
|
foreach (var module in theModules) {
|
|
|
|
|
if (theModules.Count > 1)
|
|
|
|
|
Log.v("Renaming references to type definitions ({0})", module.Filename);
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var refToDef in module.TypeRefsToRename) {
|
|
|
|
|
refToDef.reference.Name = refToDef.definition.Name;
|
|
|
|
|
refToDef.reference.Namespace = refToDef.definition.Namespace;
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
2011-11-18 23:55:54 +08:00
|
|
|
|
Log.deIndent();
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
2011-11-18 23:55:54 +08:00
|
|
|
|
}
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
void prepareRenameMemberDefinitions() {
|
|
|
|
|
Log.v("Renaming member definitions #1");
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
prepareRenameEntryPoints();
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
foreach (var typeDef in modules.BaseTypes)
|
|
|
|
|
memberInfos.type(typeDef).variableNameState = new VariableNameState();
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
foreach (var typeDef in modules.AllTypes)
|
|
|
|
|
prepareRenameMembers(typeDef);
|
|
|
|
|
}
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
Dictionary<TypeDef, bool> prepareRenameMembersCalled = new Dictionary<TypeDef, bool>();
|
|
|
|
|
void prepareRenameMembers(TypeDef type) {
|
|
|
|
|
if (prepareRenameMembersCalled.ContainsKey(type))
|
|
|
|
|
return;
|
|
|
|
|
prepareRenameMembersCalled[type] = true;
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
foreach (var ifaceInfo in type.interfaces)
|
|
|
|
|
prepareRenameMembers(ifaceInfo.typeDef);
|
|
|
|
|
if (type.baseType != null)
|
|
|
|
|
prepareRenameMembers(type.baseType.typeDef);
|
|
|
|
|
|
|
|
|
|
TypeInfo info;
|
|
|
|
|
if (memberInfos.tryGetType(type, out info))
|
|
|
|
|
info.prepareRenameMembers();
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-18 23:55:54 +08:00
|
|
|
|
void prepareRenameEntryPoints() {
|
|
|
|
|
foreach (var module in modules.TheModules) {
|
|
|
|
|
var entryPoint = module.ModuleDefinition.EntryPoint;
|
|
|
|
|
if (entryPoint == null)
|
2011-11-17 11:17:03 +08:00
|
|
|
|
continue;
|
2011-11-18 23:55:54 +08:00
|
|
|
|
var methodDef = modules.resolve(entryPoint);
|
|
|
|
|
if (methodDef == null) {
|
|
|
|
|
Log.w(string.Format("Could not find entry point. Module: {0}, Method: {1}", module.ModuleDefinition.FullyQualifiedName, entryPoint));
|
2011-11-17 11:17:03 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2011-11-18 23:55:54 +08:00
|
|
|
|
if (!methodDef.isStatic())
|
2011-11-17 11:17:03 +08:00
|
|
|
|
continue;
|
2011-11-18 23:55:54 +08:00
|
|
|
|
memberInfos.method(methodDef).suggestedName = "Main";
|
|
|
|
|
if (methodDef.ParamDefs.Count == 1) {
|
|
|
|
|
var paramDef = methodDef.ParamDefs[0];
|
|
|
|
|
var type = paramDef.ParameterDefinition.ParameterType;
|
|
|
|
|
if (type.FullName == "System.String[]")
|
|
|
|
|
memberInfos.param(paramDef).newName = "args";
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-11-15 21:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|