2011-09-22 10:55:30 +08:00
|
|
|
|
/*
|
2012-01-10 06:02:47 +08:00
|
|
|
|
Copyright (C) 2011-2012 de4dot@gmail.com
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
|
|
|
|
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 Mono.Cecil;
|
|
|
|
|
using Mono.Cecil.Cil;
|
2011-10-29 08:23:48 +08:00
|
|
|
|
using Mono.MyStuff;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
using de4dot.blocks;
|
2011-12-09 16:02:06 +08:00
|
|
|
|
using de4dot.code.PE;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
2011-12-09 16:02:06 +08:00
|
|
|
|
namespace de4dot.code.deobfuscators {
|
2011-11-25 22:19:56 +08:00
|
|
|
|
abstract class DeobfuscatorBase : IDeobfuscator, IWriterListener {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
public const string DEFAULT_VALID_NAME_REGEX = @"^[a-zA-Z_<{$][a-zA-Z_0-9<>{}$.`-]*$";
|
|
|
|
|
|
|
|
|
|
class RemoveInfo<T> {
|
|
|
|
|
public T obj;
|
|
|
|
|
public string reason;
|
|
|
|
|
public RemoveInfo(T obj, string reason) {
|
|
|
|
|
this.obj = obj;
|
|
|
|
|
this.reason = reason;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OptionsBase optionsBase;
|
|
|
|
|
protected ModuleDefinition module;
|
|
|
|
|
protected StaticStringDecrypter staticStringDecrypter = new StaticStringDecrypter();
|
|
|
|
|
IList<RemoveInfo<TypeDefinition>> typesToRemove = new List<RemoveInfo<TypeDefinition>>();
|
|
|
|
|
IList<RemoveInfo<MethodDefinition>> methodsToRemove = new List<RemoveInfo<MethodDefinition>>();
|
|
|
|
|
IList<RemoveInfo<FieldDefinition>> fieldsToRemove = new List<RemoveInfo<FieldDefinition>>();
|
|
|
|
|
IList<RemoveInfo<TypeDefinition>> attrsToRemove = new List<RemoveInfo<TypeDefinition>>();
|
|
|
|
|
IList<RemoveInfo<Resource>> resourcesToRemove = new List<RemoveInfo<Resource>>();
|
|
|
|
|
IList<RemoveInfo<ModuleReference>> modrefsToRemove = new List<RemoveInfo<ModuleReference>>();
|
|
|
|
|
List<string> namesToPossiblyRemove = new List<string>();
|
2011-10-23 14:41:33 +08:00
|
|
|
|
MethodCallRemover methodCallRemover = new MethodCallRemover();
|
2011-12-01 03:19:50 +08:00
|
|
|
|
byte[] moduleBytes;
|
2011-12-29 15:23:46 +08:00
|
|
|
|
protected InitializedDataCreator initializedDataCreator;
|
2011-12-01 03:19:50 +08:00
|
|
|
|
|
|
|
|
|
protected byte[] ModuleBytes {
|
|
|
|
|
get { return moduleBytes; }
|
|
|
|
|
set { moduleBytes = value; }
|
|
|
|
|
}
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
|
|
|
|
internal class OptionsBase : IDeobfuscatorOptions {
|
|
|
|
|
public bool RenameResourcesInCode { get; set; }
|
|
|
|
|
public NameRegexes ValidNameRegex { get; set; }
|
|
|
|
|
public bool DecryptStrings { get; set; }
|
|
|
|
|
|
|
|
|
|
public OptionsBase() {
|
|
|
|
|
RenameResourcesInCode = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDeobfuscatorOptions TheOptions {
|
|
|
|
|
get { return optionsBase; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IOperations Operations { get; set; }
|
|
|
|
|
public IDeobfuscatedFile DeobfuscatedFile { get; set; }
|
|
|
|
|
public virtual StringFeatures StringFeatures { get; set; }
|
2011-11-09 19:08:48 +08:00
|
|
|
|
public virtual RenamingOptions RenamingOptions { get; set; }
|
2011-09-28 22:06:10 +08:00
|
|
|
|
public DecrypterType DefaultDecrypterType { get; set; }
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
|
|
|
|
public abstract string Type { get; }
|
2011-11-12 18:31:07 +08:00
|
|
|
|
public abstract string TypeLong { get; }
|
2011-09-22 10:55:30 +08:00
|
|
|
|
public abstract string Name { get; }
|
|
|
|
|
|
2011-11-01 21:19:53 +08:00
|
|
|
|
public virtual bool CanInlineMethods {
|
|
|
|
|
get { return false; }
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 10:55:30 +08:00
|
|
|
|
public DeobfuscatorBase(OptionsBase optionsBase) {
|
|
|
|
|
this.optionsBase = optionsBase;
|
|
|
|
|
StringFeatures = StringFeatures.AllowAll;
|
2011-09-28 22:06:10 +08:00
|
|
|
|
DefaultDecrypterType = DecrypterType.Static;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-12-01 01:26:36 +08:00
|
|
|
|
public virtual byte[] unpackNativeFile(PeImage peImage) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-09 01:33:12 +08:00
|
|
|
|
public virtual void init(ModuleDefinition module) {
|
2011-10-26 20:29:12 +08:00
|
|
|
|
setModule(module);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void setModule(ModuleDefinition module) {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
this.module = module;
|
2011-12-29 15:23:46 +08:00
|
|
|
|
initializedDataCreator = new InitializedDataCreator(module);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-10 07:47:22 +08:00
|
|
|
|
protected virtual bool checkValidName(string name) {
|
|
|
|
|
return optionsBase.ValidNameRegex.isMatch(name);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-09 01:33:12 +08:00
|
|
|
|
public virtual int earlyDetect() {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 20:29:12 +08:00
|
|
|
|
public virtual int detect() {
|
|
|
|
|
scanForObfuscator();
|
|
|
|
|
return detectInternal();
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 20:29:12 +08:00
|
|
|
|
protected abstract void scanForObfuscator();
|
|
|
|
|
protected abstract int detectInternal();
|
|
|
|
|
|
2011-10-29 08:23:48 +08:00
|
|
|
|
public virtual bool getDecryptedModule(ref byte[] newFileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
|
|
|
|
|
return false;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 20:29:12 +08:00
|
|
|
|
public virtual IDeobfuscator moduleReloaded(ModuleDefinition module) {
|
|
|
|
|
throw new ApplicationException("moduleReloaded() must be overridden by the deobfuscator");
|
|
|
|
|
}
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
|
|
|
|
public virtual void deobfuscateBegin() {
|
2011-12-01 03:19:50 +08:00
|
|
|
|
ModuleBytes = null;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void deobfuscateMethodBegin(Blocks blocks) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void deobfuscateMethodEnd(Blocks blocks) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
removeMethodCalls(blocks);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void deobfuscateStrings(Blocks blocks) {
|
|
|
|
|
if (staticStringDecrypter.HasHandlers)
|
|
|
|
|
staticStringDecrypter.decrypt(blocks);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-27 04:16:51 +08:00
|
|
|
|
public virtual bool deobfuscateOther(Blocks blocks) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 10:55:30 +08:00
|
|
|
|
public virtual void deobfuscateEnd() {
|
|
|
|
|
if (!Operations.KeepObfuscatorTypes) {
|
|
|
|
|
deleteEmptyCctors();
|
|
|
|
|
deleteMethods();
|
|
|
|
|
deleteFields();
|
|
|
|
|
deleteCustomAttributes();
|
|
|
|
|
deleteOtherAttributes();
|
|
|
|
|
|
|
|
|
|
// Delete types after removing methods, fields, and attributes. The reason is
|
|
|
|
|
// that the Scope property will be null if we remove a type. Comparing a
|
|
|
|
|
// typeref with a typedef will then fail.
|
|
|
|
|
deleteTypes();
|
|
|
|
|
|
|
|
|
|
deleteDllResources();
|
|
|
|
|
deleteModuleReferences();
|
|
|
|
|
}
|
2012-01-04 03:14:28 +08:00
|
|
|
|
|
|
|
|
|
restoreBaseType();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void restoreBaseType() {
|
2012-01-09 01:46:23 +08:00
|
|
|
|
var moduleType = DotNetUtils.getModuleType(module);
|
2012-01-04 03:14:28 +08:00
|
|
|
|
foreach (var type in module.GetTypes()) {
|
2012-01-09 01:46:23 +08:00
|
|
|
|
if (type.BaseType != null || type.IsInterface || type == moduleType)
|
2012-01-04 03:14:28 +08:00
|
|
|
|
continue;
|
|
|
|
|
Log.v("Adding System.Object as base type: {0} ({1:X8})",
|
|
|
|
|
Utils.removeNewlines(type),
|
|
|
|
|
type.MetadataToken.ToInt32());
|
|
|
|
|
type.BaseType = module.TypeSystem.Object;
|
|
|
|
|
}
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual IEnumerable<string> getStringDecrypterMethods() {
|
|
|
|
|
return new List<string>();
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-23 14:41:33 +08:00
|
|
|
|
class MethodCallRemover {
|
2011-12-31 23:32:57 +08:00
|
|
|
|
Dictionary<string, MethodDefinitionAndDeclaringTypeDict<bool>> methodNameInfos = new Dictionary<string, MethodDefinitionAndDeclaringTypeDict<bool>>();
|
|
|
|
|
MethodDefinitionAndDeclaringTypeDict<MethodDefinitionAndDeclaringTypeDict<bool>> methodRefInfos = new MethodDefinitionAndDeclaringTypeDict<MethodDefinitionAndDeclaringTypeDict<bool>>();
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
2011-10-23 14:41:33 +08:00
|
|
|
|
void checkMethod(MethodReference methodToBeRemoved) {
|
|
|
|
|
if (methodToBeRemoved.Parameters.Count != 0)
|
|
|
|
|
throw new ApplicationException(string.Format("Method takes params: {0}", methodToBeRemoved));
|
|
|
|
|
if (DotNetUtils.hasReturnValue(methodToBeRemoved))
|
|
|
|
|
throw new ApplicationException(string.Format("Method has a return value: {0}", methodToBeRemoved));
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
public void add(string method, MethodDefinition methodToBeRemoved) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
if (methodToBeRemoved == null)
|
|
|
|
|
return;
|
|
|
|
|
checkMethod(methodToBeRemoved);
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
MethodDefinitionAndDeclaringTypeDict<bool> dict;
|
2011-10-23 14:41:33 +08:00
|
|
|
|
if (!methodNameInfos.TryGetValue(method, out dict))
|
2011-12-31 23:32:57 +08:00
|
|
|
|
methodNameInfos[method] = dict = new MethodDefinitionAndDeclaringTypeDict<bool>();
|
|
|
|
|
dict.add(methodToBeRemoved, true);
|
2011-10-23 14:41:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
public void add(MethodDefinition method, MethodDefinition methodToBeRemoved) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
if (method == null || methodToBeRemoved == null)
|
|
|
|
|
return;
|
|
|
|
|
checkMethod(methodToBeRemoved);
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
var dict = methodRefInfos.find(method);
|
|
|
|
|
if (dict == null)
|
|
|
|
|
methodRefInfos.add(method, dict = new MethodDefinitionAndDeclaringTypeDict<bool>());
|
|
|
|
|
dict.add(methodToBeRemoved, true);
|
2011-10-23 14:41:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void removeAll(Blocks blocks) {
|
|
|
|
|
var allBlocks = blocks.MethodBlocks.getAllBlocks();
|
|
|
|
|
|
|
|
|
|
removeAll(allBlocks, blocks, blocks.Method.Name);
|
|
|
|
|
removeAll(allBlocks, blocks, blocks.Method);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeAll(IList<Block> allBlocks, Blocks blocks, string method) {
|
2011-12-31 23:32:57 +08:00
|
|
|
|
MethodDefinitionAndDeclaringTypeDict<bool> info;
|
2011-10-23 14:41:33 +08:00
|
|
|
|
if (!methodNameInfos.TryGetValue(method, out info))
|
|
|
|
|
return;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
2011-10-23 14:41:33 +08:00
|
|
|
|
removeCalls(allBlocks, blocks, info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeAll(IList<Block> allBlocks, Blocks blocks, MethodDefinition method) {
|
2011-12-31 23:32:57 +08:00
|
|
|
|
var info = methodRefInfos.find(method);
|
|
|
|
|
if (info == null)
|
2011-10-23 14:41:33 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
removeCalls(allBlocks, blocks, info);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
void removeCalls(IList<Block> allBlocks, Blocks blocks, MethodDefinitionAndDeclaringTypeDict<bool> info) {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
var instrsToDelete = new List<int>();
|
2011-10-23 14:41:33 +08:00
|
|
|
|
foreach (var block in allBlocks) {
|
|
|
|
|
instrsToDelete.Clear();
|
|
|
|
|
for (int i = 0; i < block.Instructions.Count; i++) {
|
|
|
|
|
var instr = block.Instructions[i];
|
|
|
|
|
if (instr.OpCode != OpCodes.Call)
|
|
|
|
|
continue;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
var destMethod = instr.Operand as MethodReference;
|
|
|
|
|
if (destMethod == null)
|
|
|
|
|
continue;
|
2011-10-23 14:41:33 +08:00
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
if (info.find(destMethod)) {
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("Removed call to {0}", Utils.removeNewlines(destMethod));
|
2011-09-22 10:55:30 +08:00
|
|
|
|
instrsToDelete.Add(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-10-23 14:41:33 +08:00
|
|
|
|
block.remove(instrsToDelete);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
public void addCctorInitCallToBeRemoved(MethodDefinition methodToBeRemoved) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
methodCallRemover.add(".cctor", methodToBeRemoved);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
public void addModuleCctorInitCallToBeRemoved(MethodDefinition methodToBeRemoved) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
methodCallRemover.add(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor"), methodToBeRemoved);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
public void addCtorInitCallToBeRemoved(MethodDefinition methodToBeRemoved) {
|
2011-11-24 17:44:01 +08:00
|
|
|
|
methodCallRemover.add(".ctor", methodToBeRemoved);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-31 23:32:57 +08:00
|
|
|
|
public void addCallToBeRemoved(MethodDefinition method, MethodDefinition methodToBeRemoved) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
methodCallRemover.add(method, methodToBeRemoved);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeMethodCalls(Blocks blocks) {
|
|
|
|
|
methodCallRemover.removeAll(blocks);
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 10:55:30 +08:00
|
|
|
|
protected void addMethodsToBeRemoved(IEnumerable<MethodDefinition> methods, string reason) {
|
|
|
|
|
foreach (var method in methods)
|
|
|
|
|
addMethodToBeRemoved(method, reason);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addMethodToBeRemoved(MethodDefinition method, string reason) {
|
|
|
|
|
methodsToRemove.Add(new RemoveInfo<MethodDefinition>(method, reason));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addFieldsToBeRemoved(IEnumerable<FieldDefinition> fields, string reason) {
|
|
|
|
|
foreach (var field in fields)
|
|
|
|
|
addFieldToBeRemoved(field, reason);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addFieldToBeRemoved(FieldDefinition field, string reason) {
|
|
|
|
|
fieldsToRemove.Add(new RemoveInfo<FieldDefinition>(field, reason));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addAttributeToBeRemoved(TypeDefinition attr, string reason) {
|
|
|
|
|
addTypeToBeRemoved(attr, reason);
|
|
|
|
|
attrsToRemove.Add(new RemoveInfo<TypeDefinition>(attr, reason));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addTypesToBeRemoved(IEnumerable<TypeDefinition> types, string reason) {
|
|
|
|
|
foreach (var type in types)
|
|
|
|
|
addTypeToBeRemoved(type, reason);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addTypeToBeRemoved(TypeDefinition type, string reason) {
|
|
|
|
|
typesToRemove.Add(new RemoveInfo<TypeDefinition>(type, reason));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addResourceToBeRemoved(Resource resource, string reason) {
|
|
|
|
|
resourcesToRemove.Add(new RemoveInfo<Resource>(resource, reason));
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-21 07:41:09 +08:00
|
|
|
|
protected void addModuleReferencesToBeRemoved(IEnumerable<ModuleReference> modrefs, string reason) {
|
|
|
|
|
foreach (var modref in modrefs)
|
|
|
|
|
addModuleReferenceToBeRemoved(modref, reason);
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 10:55:30 +08:00
|
|
|
|
protected void addModuleReferenceToBeRemoved(ModuleReference modref, string reason) {
|
|
|
|
|
modrefsToRemove.Add(new RemoveInfo<ModuleReference>(modref, reason));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteEmptyCctors() {
|
|
|
|
|
var emptyCctorsToRemove = new List<MethodDefinition>();
|
|
|
|
|
foreach (var type in module.GetTypes()) {
|
|
|
|
|
var cctor = DotNetUtils.getMethod(type, ".cctor");
|
|
|
|
|
if (cctor != null && DotNetUtils.isEmpty(cctor))
|
|
|
|
|
emptyCctorsToRemove.Add(cctor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (emptyCctorsToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing empty .cctor methods");
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var cctor in emptyCctorsToRemove) {
|
|
|
|
|
var type = cctor.DeclaringType;
|
|
|
|
|
if (type.Methods.Remove(cctor))
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("{0:X8}, type: {1} ({2:X8})",
|
|
|
|
|
cctor.MetadataToken.ToUInt32(),
|
|
|
|
|
Utils.removeNewlines(type),
|
|
|
|
|
type.MetadataToken.ToUInt32());
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteMethods() {
|
|
|
|
|
if (methodsToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing methods");
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var info in methodsToRemove) {
|
|
|
|
|
var method = info.obj;
|
|
|
|
|
if (method == null)
|
|
|
|
|
continue;
|
|
|
|
|
var type = method.DeclaringType;
|
|
|
|
|
if (type.Methods.Remove(method))
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("Removed method {0} ({1:X8}) (Type: {2}) (reason: {3})",
|
|
|
|
|
Utils.removeNewlines(method),
|
|
|
|
|
method.MetadataToken.ToUInt32(),
|
|
|
|
|
Utils.removeNewlines(type),
|
|
|
|
|
info.reason);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteFields() {
|
|
|
|
|
if (fieldsToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing fields");
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var info in fieldsToRemove) {
|
|
|
|
|
var field = info.obj;
|
|
|
|
|
if (field == null)
|
|
|
|
|
continue;
|
|
|
|
|
var type = field.DeclaringType;
|
|
|
|
|
if (type.Fields.Remove(field))
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("Removed field {0} ({1:X8}) (Type: {2}) (reason: {3})",
|
|
|
|
|
Utils.removeNewlines(field),
|
|
|
|
|
field.MetadataToken.ToUInt32(),
|
|
|
|
|
Utils.removeNewlines(type),
|
|
|
|
|
info.reason);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteTypes() {
|
|
|
|
|
var types = module.Types;
|
|
|
|
|
if (types == null || typesToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing types");
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var info in typesToRemove) {
|
|
|
|
|
var typeDef = info.obj;
|
|
|
|
|
if (typeDef == null)
|
|
|
|
|
continue;
|
2011-12-28 20:30:44 +08:00
|
|
|
|
bool removed;
|
|
|
|
|
if (typeDef.IsNested)
|
|
|
|
|
removed = typeDef.DeclaringType.NestedTypes.Remove(typeDef);
|
|
|
|
|
else
|
|
|
|
|
removed = types.Remove(typeDef);
|
|
|
|
|
if (removed)
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("Removed type {0} ({1:X8}) (reason: {2})",
|
|
|
|
|
Utils.removeNewlines(typeDef),
|
|
|
|
|
typeDef.MetadataToken.ToUInt32(),
|
|
|
|
|
info.reason);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteCustomAttributes() {
|
|
|
|
|
if (attrsToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing custom attributes");
|
|
|
|
|
Log.indent();
|
|
|
|
|
deleteCustomAttributes(module.CustomAttributes);
|
2011-10-05 14:20:32 +08:00
|
|
|
|
if (module.Assembly != null)
|
|
|
|
|
deleteCustomAttributes(module.Assembly.CustomAttributes);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteCustomAttributes(IList<CustomAttribute> customAttrs) {
|
|
|
|
|
if (customAttrs == null)
|
|
|
|
|
return;
|
|
|
|
|
foreach (var info in attrsToRemove) {
|
|
|
|
|
var typeDef = info.obj;
|
|
|
|
|
if (typeDef == null)
|
|
|
|
|
continue;
|
|
|
|
|
for (int i = 0; i < customAttrs.Count; i++) {
|
|
|
|
|
if (MemberReferenceHelper.compareTypes(customAttrs[i].AttributeType, typeDef)) {
|
|
|
|
|
customAttrs.RemoveAt(i);
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("Removed custom attribute {0} ({1:X8}) (reason: {2})",
|
|
|
|
|
Utils.removeNewlines(typeDef),
|
|
|
|
|
typeDef.MetadataToken.ToUInt32(),
|
|
|
|
|
info.reason);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteOtherAttributes() {
|
|
|
|
|
Log.v("Removing other attributes");
|
|
|
|
|
Log.indent();
|
|
|
|
|
deleteOtherAttributes(module.CustomAttributes);
|
2011-10-05 14:20:32 +08:00
|
|
|
|
if (module.Assembly != null)
|
|
|
|
|
deleteOtherAttributes(module.Assembly.CustomAttributes);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteOtherAttributes(IList<CustomAttribute> customAttributes) {
|
|
|
|
|
for (int i = customAttributes.Count - 1; i >= 0; i--) {
|
|
|
|
|
var attr = customAttributes[i].AttributeType;
|
|
|
|
|
if (attr.FullName == "System.Runtime.CompilerServices.SuppressIldasmAttribute") {
|
2012-01-04 02:52:40 +08:00
|
|
|
|
Log.v("Removed attribute {0}", Utils.removeNewlines(attr.FullName));
|
2011-09-22 10:55:30 +08:00
|
|
|
|
customAttributes.RemoveAt(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteDllResources() {
|
|
|
|
|
if (!module.HasResources || resourcesToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing resources");
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var info in resourcesToRemove) {
|
|
|
|
|
var resource = info.obj;
|
|
|
|
|
if (resource == null)
|
|
|
|
|
continue;
|
|
|
|
|
if (module.Resources.Remove(resource))
|
|
|
|
|
Log.v("Removed resource {0} (reason: {1})", Utils.toCsharpString(resource.Name), info.reason);
|
|
|
|
|
}
|
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteModuleReferences() {
|
|
|
|
|
if (!module.HasModuleReferences || modrefsToRemove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Log.v("Removing module references");
|
|
|
|
|
Log.indent();
|
|
|
|
|
foreach (var info in modrefsToRemove) {
|
|
|
|
|
var modref = info.obj;
|
|
|
|
|
if (modref == null)
|
|
|
|
|
continue;
|
|
|
|
|
if (module.ModuleReferences.Remove(modref))
|
|
|
|
|
Log.v("Removed module reference {0} (reason: {1})", modref, info.reason);
|
|
|
|
|
}
|
|
|
|
|
Log.deIndent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString() {
|
|
|
|
|
return Name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void findPossibleNamesToRemove(MethodDefinition method) {
|
|
|
|
|
if (method == null || !method.HasBody)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
foreach (var instr in method.Body.Instructions) {
|
|
|
|
|
if (instr.OpCode == OpCodes.Ldstr)
|
|
|
|
|
namesToPossiblyRemove.Add((string)instr.Operand);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addResources(string reason) {
|
|
|
|
|
if (!module.HasResources)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
foreach (var name in namesToPossiblyRemove) {
|
|
|
|
|
foreach (var resource in module.Resources) {
|
|
|
|
|
if (resource.Name == name) {
|
|
|
|
|
addResourceToBeRemoved(resource, reason);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void addModuleReferences(string reason) {
|
|
|
|
|
if (!module.HasModuleReferences)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
foreach (var name in namesToPossiblyRemove) {
|
|
|
|
|
foreach (var moduleRef in module.ModuleReferences) {
|
2011-10-09 19:19:26 +08:00
|
|
|
|
if (Utils.StartsWith(moduleRef.Name, name, StringComparison.OrdinalIgnoreCase))
|
2011-09-22 10:55:30 +08:00
|
|
|
|
addModuleReferenceToBeRemoved(moduleRef, reason);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void removeProxyDelegates(ProxyDelegateFinderBase proxyDelegateFinder) {
|
2011-11-28 18:45:48 +08:00
|
|
|
|
if (proxyDelegateFinder.Errors != 0) {
|
|
|
|
|
Log.v("Not removing proxy delegates and creator type since errors were detected.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-09-22 10:55:30 +08:00
|
|
|
|
addTypesToBeRemoved(proxyDelegateFinder.DelegateTypes, "Proxy delegate type");
|
|
|
|
|
if (proxyDelegateFinder.RemovedDelegateCreatorCalls > 0)
|
2011-10-23 19:43:32 +08:00
|
|
|
|
addTypesToBeRemoved(proxyDelegateFinder.DelegateCreatorTypes, "Proxy delegate creator type");
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Resource getResource(IEnumerable<string> strings) {
|
|
|
|
|
return DotNetUtils.getResource(module, strings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected CustomAttribute getAssemblyAttribute(TypeReference attr) {
|
|
|
|
|
var list = new List<CustomAttribute>(DotNetUtils.findAttributes(module.Assembly, attr));
|
|
|
|
|
return list.Count == 0 ? null : list[0];
|
|
|
|
|
}
|
2011-11-17 11:17:03 +08:00
|
|
|
|
|
2011-11-24 14:49:50 +08:00
|
|
|
|
protected bool hasMetadataStream(string name) {
|
|
|
|
|
foreach (var stream in module.MetadataStreams) {
|
2011-11-25 22:19:56 +08:00
|
|
|
|
if (stream.Name == name)
|
2011-11-24 14:49:50 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-26 19:21:18 +08:00
|
|
|
|
List<T> getObjectsToRemove<T>(IList<RemoveInfo<T>> removeThese) where T : MemberReference {
|
|
|
|
|
var list = new List<T>(removeThese.Count);
|
|
|
|
|
foreach (var info in removeThese) {
|
|
|
|
|
if (info.obj != null)
|
|
|
|
|
list.Add(info.obj);
|
|
|
|
|
}
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected List<TypeDefinition> getTypesToRemove() {
|
|
|
|
|
return getObjectsToRemove(typesToRemove);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected List<MethodDefinition> getMethodsToRemove() {
|
|
|
|
|
return getObjectsToRemove(methodsToRemove);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidNamespaceName(string ns) {
|
2011-11-23 18:50:34 +08:00
|
|
|
|
if (ns == null)
|
|
|
|
|
return false;
|
|
|
|
|
foreach (var part in ns.Split(new char[] { '.' })) {
|
|
|
|
|
if (!checkValidName(part))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidTypeName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidMethodName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidPropertyName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidEventName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidFieldName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidGenericParamName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-23 12:28:57 +08:00
|
|
|
|
public virtual bool isValidMethodArgName(string name) {
|
2011-11-21 18:03:45 +08:00
|
|
|
|
return name != null && checkValidName(name);
|
2011-11-17 11:17:03 +08:00
|
|
|
|
}
|
2011-11-25 22:19:56 +08:00
|
|
|
|
|
|
|
|
|
public virtual void OnBeforeAddingResources(MetadataBuilder builder) {
|
|
|
|
|
}
|
2011-12-21 04:47:45 +08:00
|
|
|
|
|
|
|
|
|
public void findAndRemoveInlinedMethods() {
|
|
|
|
|
var inlinedMethods = InlinedMethodsFinder.find(module);
|
2011-12-28 20:30:44 +08:00
|
|
|
|
addMethodsToBeRemoved(new UnusedMethodsFinder(module, inlinedMethods, getRemovedMethods()).find(), "Inlined method");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MethodCollection getRemovedMethods() {
|
|
|
|
|
var removedMethods = new MethodCollection();
|
|
|
|
|
removedMethods.add(getMethodsToRemove());
|
|
|
|
|
removedMethods.addAndNested(getTypesToRemove());
|
|
|
|
|
return removedMethods;
|
2011-12-21 04:47:45 +08:00
|
|
|
|
}
|
2011-12-21 07:30:17 +08:00
|
|
|
|
|
|
|
|
|
protected bool isTypeCalled(TypeDefinition decrypterType) {
|
|
|
|
|
if (decrypterType == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
2011-12-28 20:30:44 +08:00
|
|
|
|
var decrypterMethods = new MethodCollection();
|
|
|
|
|
decrypterMethods.addAndNested(decrypterType);
|
2011-12-21 07:30:17 +08:00
|
|
|
|
|
2011-12-28 20:30:44 +08:00
|
|
|
|
var removedMethods = getRemovedMethods();
|
2011-12-21 07:30:17 +08:00
|
|
|
|
|
|
|
|
|
foreach (var type in module.GetTypes()) {
|
|
|
|
|
foreach (var method in type.Methods) {
|
|
|
|
|
if (method.Body == null)
|
|
|
|
|
continue;
|
2011-12-28 20:30:44 +08:00
|
|
|
|
if (decrypterMethods.exists(method))
|
2011-12-21 07:30:17 +08:00
|
|
|
|
break; // decrypter type / nested type method
|
2011-12-28 20:30:44 +08:00
|
|
|
|
if (removedMethods.exists(method))
|
2011-12-21 07:30:17 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
foreach (var instr in method.Body.Instructions) {
|
|
|
|
|
switch (instr.OpCode.Code) {
|
|
|
|
|
case Code.Call:
|
|
|
|
|
case Code.Callvirt:
|
|
|
|
|
case Code.Newobj:
|
|
|
|
|
var calledMethod = instr.Operand as MethodReference;
|
|
|
|
|
if (calledMethod == null)
|
|
|
|
|
break;
|
2011-12-28 20:30:44 +08:00
|
|
|
|
if (decrypterMethods.exists(calledMethod))
|
2011-12-21 07:30:17 +08:00
|
|
|
|
return true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-08 02:14:15 +08:00
|
|
|
|
public static int toInt32(bool b) {
|
2011-12-22 02:21:06 +08:00
|
|
|
|
return b ? 1 : 0;
|
|
|
|
|
}
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|