2011-09-22 10:55:30 +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;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using Mono.Cecil;
|
|
|
|
|
using Mono.Cecil.Cil;
|
|
|
|
|
using de4dot.blocks;
|
|
|
|
|
|
|
|
|
|
// SmartAssembly can add so much junk that it's very difficult to find and remove all of it.
|
|
|
|
|
// I remove some safe types that are almost guaranteed not to have any references in the code.
|
|
|
|
|
|
|
|
|
|
namespace de4dot.deobfuscators.SmartAssembly {
|
|
|
|
|
class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
2011-11-04 03:03:32 +08:00
|
|
|
|
public const string THE_NAME = "SmartAssembly";
|
2011-09-22 10:55:30 +08:00
|
|
|
|
BoolOption removeAutomatedErrorReporting;
|
|
|
|
|
BoolOption removeTamperProtection;
|
|
|
|
|
BoolOption removeMemoryManager;
|
|
|
|
|
|
|
|
|
|
public DeobfuscatorInfo()
|
2011-11-04 03:03:32 +08:00
|
|
|
|
: base() {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
removeAutomatedErrorReporting = new BoolOption(null, makeArgName("error"), "Remove automated error reporting code", true);
|
|
|
|
|
removeTamperProtection = new BoolOption(null, makeArgName("tamper"), "Remove tamper protection code", true);
|
|
|
|
|
removeMemoryManager = new BoolOption(null, makeArgName("memory"), "Remove memory manager code", true);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-04 03:03:32 +08:00
|
|
|
|
public override string Name {
|
|
|
|
|
get { return THE_NAME; }
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string Type {
|
2011-11-04 03:03:32 +08:00
|
|
|
|
get { return "sa"; }
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override IDeobfuscator createDeobfuscator() {
|
|
|
|
|
return new Deobfuscator(new Deobfuscator.Options {
|
|
|
|
|
ValidNameRegex = validNameRegex.get(),
|
|
|
|
|
RemoveAutomatedErrorReporting = removeAutomatedErrorReporting.get(),
|
|
|
|
|
RemoveTamperProtection = removeTamperProtection.get(),
|
|
|
|
|
RemoveMemoryManager = removeMemoryManager.get(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override IEnumerable<Option> getOptionsInternal() {
|
|
|
|
|
return new List<Option>() {
|
|
|
|
|
removeAutomatedErrorReporting,
|
|
|
|
|
removeTamperProtection,
|
|
|
|
|
removeMemoryManager,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Deobfuscator : DeobfuscatorBase {
|
|
|
|
|
Options options;
|
2011-10-13 18:22:17 +08:00
|
|
|
|
bool foundVersion = false;
|
|
|
|
|
string poweredByAttributeString = null;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
string obfuscatorName = "SmartAssembly";
|
|
|
|
|
bool foundSmartAssemblyAttribute = false;
|
|
|
|
|
|
|
|
|
|
IList<StringDecrypterInfo> stringDecrypterInfos = new List<StringDecrypterInfo>();
|
|
|
|
|
IList<StringDecrypter> stringDecrypters = new List<StringDecrypter>();
|
|
|
|
|
ResourceDecrypterInfo resourceDecrypterInfo;
|
|
|
|
|
ResourceDecrypter resourceDecrypter;
|
|
|
|
|
AssemblyResolverInfo assemblyResolverInfo;
|
|
|
|
|
AssemblyResolver assemblyResolver;
|
|
|
|
|
ResourceResolverInfo resourceResolverInfo;
|
|
|
|
|
ResourceResolver resourceResolver;
|
|
|
|
|
MemoryManagerInfo memoryManagerInfo;
|
|
|
|
|
|
|
|
|
|
ProxyDelegateFinder proxyDelegateFinder;
|
|
|
|
|
AutomatedErrorReportingFinder automatedErrorReportingFinder;
|
|
|
|
|
TamperProtectionRemover tamperProtectionRemover;
|
|
|
|
|
|
|
|
|
|
internal class Options : OptionsBase {
|
|
|
|
|
public bool RemoveAutomatedErrorReporting { get; set; }
|
|
|
|
|
public bool RemoveTamperProtection { get; set; }
|
|
|
|
|
public bool RemoveMemoryManager { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string Type {
|
2011-11-04 03:03:32 +08:00
|
|
|
|
get { return DeobfuscatorInfo.THE_NAME; }
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string Name {
|
|
|
|
|
get { return obfuscatorName; }
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-13 18:22:17 +08:00
|
|
|
|
string ObfuscatorName {
|
|
|
|
|
set {
|
|
|
|
|
obfuscatorName = value;
|
|
|
|
|
foundVersion = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 10:55:30 +08:00
|
|
|
|
public Deobfuscator(Options options)
|
|
|
|
|
: base(options) {
|
|
|
|
|
this.options = options;
|
|
|
|
|
StringFeatures = StringFeatures.AllowStaticDecryption;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-09 01:33:12 +08:00
|
|
|
|
public override void init(ModuleDefinition module) {
|
|
|
|
|
base.init(module);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
automatedErrorReportingFinder = new AutomatedErrorReportingFinder(module);
|
|
|
|
|
tamperProtectionRemover = new TamperProtectionRemover(module);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 20:29:12 +08:00
|
|
|
|
protected override int detectInternal() {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
int val = 0;
|
|
|
|
|
|
|
|
|
|
if (foundSmartAssemblyAttribute)
|
|
|
|
|
val += 100;
|
|
|
|
|
|
|
|
|
|
// Since we don't remove this type, we will detect it even when we've deobfuscated
|
|
|
|
|
// an assembly. Don't use this code for now. When the type is removed, this code
|
|
|
|
|
// should be re-enabled.
|
|
|
|
|
// if (automatedErrorReportingFinder.Detected)
|
|
|
|
|
// val += 10;
|
|
|
|
|
|
|
|
|
|
if (memoryManagerInfo.Detected)
|
|
|
|
|
val += 10;
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 20:29:12 +08:00
|
|
|
|
protected override void scanForObfuscator() {
|
2011-10-09 01:33:12 +08:00
|
|
|
|
proxyDelegateFinder = new ProxyDelegateFinder(module);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
findSmartAssemblyAttributes();
|
|
|
|
|
findAutomatedErrorReportingType();
|
|
|
|
|
memoryManagerInfo = new MemoryManagerInfo(module);
|
|
|
|
|
proxyDelegateFinder.findDelegateCreator(module);
|
2011-10-13 18:22:17 +08:00
|
|
|
|
|
|
|
|
|
if (!foundVersion)
|
|
|
|
|
guessVersion();
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void findSmartAssemblyAttributes() {
|
|
|
|
|
foreach (var type in module.Types) {
|
2011-10-09 19:19:26 +08:00
|
|
|
|
if (Utils.StartsWith(type.FullName, "SmartAssembly.Attributes.PoweredByAttribute", StringComparison.Ordinal)) {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
foundSmartAssemblyAttribute = true;
|
|
|
|
|
addAttributeToBeRemoved(type, "Obfuscator attribute");
|
2011-10-13 18:22:17 +08:00
|
|
|
|
initializeVersion(type);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-13 18:22:17 +08:00
|
|
|
|
void initializeVersion(TypeDefinition attr) {
|
2011-09-22 10:55:30 +08:00
|
|
|
|
var s = DotNetUtils.getCustomArgAsString(getAssemblyAttribute(attr), 0);
|
|
|
|
|
if (s == null)
|
2011-10-13 18:22:17 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
poweredByAttributeString = s;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
|
|
|
|
var val = System.Text.RegularExpressions.Regex.Match(s, @"^Powered by (SmartAssembly \d+\.\d+\.\d+\.\d+)$");
|
|
|
|
|
if (val.Groups.Count < 2)
|
2011-10-13 18:22:17 +08:00
|
|
|
|
return;
|
|
|
|
|
ObfuscatorName = val.Groups[1].ToString();
|
|
|
|
|
return;
|
2011-10-13 05:16:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void guessVersion() {
|
2011-10-13 18:22:17 +08:00
|
|
|
|
if (poweredByAttributeString == "Powered by SmartAssembly") {
|
|
|
|
|
ObfuscatorName = "SmartAssembly 5.0/5.1";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (poweredByAttributeString == "Powered by {smartassembly}") {
|
|
|
|
|
// It's SA 1.x - 4.x
|
|
|
|
|
|
|
|
|
|
if (hasEmptyClassesInEveryNamespace() || proxyDelegateFinder.Detected) {
|
|
|
|
|
ObfuscatorName = "SmartAssembly 4.x";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ver = checkTypeIdAttribute();
|
|
|
|
|
if (ver == 2) {
|
|
|
|
|
ObfuscatorName = "SmartAssembly 2.x";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ver == 1) {
|
|
|
|
|
ObfuscatorName = "SmartAssembly 1.x-2.x";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasModuleCctor()) {
|
|
|
|
|
ObfuscatorName = "SmartAssembly 3.x";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ObfuscatorName = "SmartAssembly 1.x-4.x";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int checkTypeIdAttribute() {
|
|
|
|
|
var type = getTypeIdAttribute();
|
|
|
|
|
if (type == null)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
var fields = type.Fields;
|
|
|
|
|
if (fields.Count == 1)
|
|
|
|
|
return 1; // 1.x: int ID
|
|
|
|
|
if (fields.Count == 2)
|
|
|
|
|
return 2; // 2.x: int ID, static int AssemblyID
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TypeDefinition getTypeIdAttribute() {
|
|
|
|
|
Dictionary<TypeDefinition, bool> attrs = null;
|
|
|
|
|
int counter = 0;
|
|
|
|
|
foreach (var type in module.GetTypes()) {
|
|
|
|
|
counter++;
|
|
|
|
|
var cattrs = type.CustomAttributes;
|
|
|
|
|
if (cattrs.Count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var attrs2 = new Dictionary<TypeDefinition, bool>();
|
|
|
|
|
foreach (var cattr in cattrs) {
|
|
|
|
|
if (!DotNetUtils.isMethod(cattr.Constructor, "System.Void", "(System.Int32)"))
|
|
|
|
|
continue;
|
|
|
|
|
var attrType = cattr.AttributeType as TypeDefinition;
|
|
|
|
|
if (attrType == null)
|
|
|
|
|
continue;
|
|
|
|
|
if (attrs != null && !attrs.ContainsKey(attrType))
|
|
|
|
|
continue;
|
|
|
|
|
attrs2[attrType] = true;
|
|
|
|
|
}
|
|
|
|
|
attrs = attrs2;
|
|
|
|
|
|
|
|
|
|
if (attrs.Count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
if (attrs.Count == 1 && counter >= 30)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (attrs == null)
|
|
|
|
|
return null;
|
|
|
|
|
foreach (var type in attrs.Keys)
|
|
|
|
|
return type;
|
|
|
|
|
return null;
|
2011-10-13 05:16:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-13 18:22:17 +08:00
|
|
|
|
bool hasModuleCctor() {
|
2011-11-02 09:25:45 +08:00
|
|
|
|
var type = DotNetUtils.getModuleType(module);
|
2011-10-13 18:22:17 +08:00
|
|
|
|
if (type == null)
|
|
|
|
|
return false;
|
|
|
|
|
return DotNetUtils.getMethod(type, ".cctor") != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool hasEmptyClassesInEveryNamespace() {
|
2011-10-13 05:16:03 +08:00
|
|
|
|
var namespaces = new Dictionary<string, int>(StringComparer.Ordinal);
|
|
|
|
|
foreach (var type in module.Types) {
|
2011-10-13 18:22:17 +08:00
|
|
|
|
if (type.FullName == "<Module>")
|
|
|
|
|
continue;
|
2011-10-13 05:16:03 +08:00
|
|
|
|
var ns = type.Namespace;
|
|
|
|
|
if (!namespaces.ContainsKey(ns))
|
|
|
|
|
namespaces[ns] = 0;
|
2011-10-13 05:30:57 +08:00
|
|
|
|
if (type.Name != "" || type.IsPublic || type.HasFields || type.HasMethods || type.HasProperties || type.HasEvents)
|
2011-10-13 05:16:03 +08:00
|
|
|
|
continue;
|
|
|
|
|
namespaces[ns]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (int count in namespaces.Values) {
|
|
|
|
|
if (count < 1)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void findAutomatedErrorReportingType() {
|
|
|
|
|
automatedErrorReportingFinder.find();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void deobfuscateBegin() {
|
|
|
|
|
base.deobfuscateBegin();
|
2011-11-05 17:10:36 +08:00
|
|
|
|
if (options.RemoveMemoryManager) {
|
2011-10-23 14:41:33 +08:00
|
|
|
|
addModuleCctorInitCallToBeRemoved(memoryManagerInfo.CctorInitMethod);
|
2011-11-05 17:10:36 +08:00
|
|
|
|
addCallToBeRemoved(module.EntryPoint, memoryManagerInfo.CctorInitMethod);
|
|
|
|
|
}
|
2011-09-22 10:55:30 +08:00
|
|
|
|
initDecrypters();
|
|
|
|
|
proxyDelegateFinder.find();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initDecrypters() {
|
|
|
|
|
assemblyResolverInfo = new AssemblyResolverInfo(module, DeobfuscatedFile, this);
|
|
|
|
|
resourceDecrypterInfo = new ResourceDecrypterInfo(module, assemblyResolverInfo.SimpleZipType, DeobfuscatedFile);
|
|
|
|
|
resourceResolverInfo = new ResourceResolverInfo(module, DeobfuscatedFile, this);
|
|
|
|
|
resourceDecrypter = new ResourceDecrypter(resourceDecrypterInfo);
|
|
|
|
|
assemblyResolver = new AssemblyResolver(resourceDecrypter, assemblyResolverInfo);
|
|
|
|
|
resourceResolver = new ResourceResolver(module, assemblyResolver, resourceResolverInfo);
|
|
|
|
|
|
|
|
|
|
initStringDecrypterInfos();
|
|
|
|
|
assemblyResolverInfo.findTypes();
|
|
|
|
|
resourceResolverInfo.findTypes();
|
|
|
|
|
|
2011-10-23 14:41:33 +08:00
|
|
|
|
addModuleCctorInitCallToBeRemoved(assemblyResolverInfo.CallResolverMethod);
|
|
|
|
|
addModuleCctorInitCallToBeRemoved(resourceResolverInfo.CallResolverMethod);
|
2011-09-22 10:55:30 +08:00
|
|
|
|
|
|
|
|
|
resourceDecrypterInfo.setSimpleZipType(getGlobalSimpleZipType(), DeobfuscatedFile);
|
|
|
|
|
|
|
|
|
|
if (!decryptResources())
|
|
|
|
|
throw new ApplicationException("Could not decrypt resources");
|
|
|
|
|
|
|
|
|
|
dumpEmbeddedAssemblies();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dumpEmbeddedAssemblies() {
|
|
|
|
|
assemblyResolver.resolveResources();
|
|
|
|
|
foreach (var tuple in assemblyResolver.getDecryptedResources()) {
|
|
|
|
|
DeobfuscatedFile.createAssemblyFile(tuple.Item2, tuple.Item1.simpleName);
|
|
|
|
|
addResourceToBeRemoved(tuple.Item1.resource, string.Format("Embedded assembly: {0}", tuple.Item1.assemblyName));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool decryptResources() {
|
|
|
|
|
if (!resourceResolver.canDecryptResource())
|
|
|
|
|
return false;
|
|
|
|
|
var rsrc = resourceResolver.mergeResources();
|
|
|
|
|
if (rsrc == null)
|
|
|
|
|
return true;
|
|
|
|
|
addResourceToBeRemoved(rsrc, "Encrypted resources");
|
|
|
|
|
assemblyResolver.resolveResources();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TypeDefinition getGlobalSimpleZipType() {
|
|
|
|
|
if (assemblyResolverInfo.SimpleZipType != null)
|
|
|
|
|
return assemblyResolverInfo.SimpleZipType;
|
|
|
|
|
foreach (var info in stringDecrypterInfos) {
|
|
|
|
|
if (info.SimpleZipType != null)
|
|
|
|
|
return info.SimpleZipType;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initStringDecrypterInfos() {
|
|
|
|
|
var stringEncoderClassFinder = new StringEncoderClassFinder(module, DeobfuscatedFile);
|
|
|
|
|
stringEncoderClassFinder.find();
|
|
|
|
|
foreach (var info in stringEncoderClassFinder.StringsEncoderInfos) {
|
|
|
|
|
var sinfo = new StringDecrypterInfo(module, info.StringDecrypterClass) {
|
|
|
|
|
GetStringDelegate = info.GetStringDelegate,
|
|
|
|
|
StringsType = info.StringsType,
|
|
|
|
|
CreateStringDelegateMethod = info.CreateStringDelegateMethod,
|
|
|
|
|
};
|
|
|
|
|
stringDecrypterInfos.Add(sinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There may be more than one string decrypter. The strings in the first one's
|
|
|
|
|
// methods may be decrypted by the other string decrypter.
|
|
|
|
|
|
|
|
|
|
var initd = new Dictionary<StringDecrypterInfo, bool>(stringDecrypterInfos.Count);
|
|
|
|
|
while (initd.Count != stringDecrypterInfos.Count) {
|
|
|
|
|
StringDecrypterInfo initdInfo = null;
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
foreach (var info in stringDecrypterInfos) {
|
|
|
|
|
if (initd.ContainsKey(info))
|
|
|
|
|
continue;
|
|
|
|
|
if (info.init(this, DeobfuscatedFile)) {
|
|
|
|
|
resourceDecrypterInfo.setSimpleZipType(info.SimpleZipType, DeobfuscatedFile);
|
|
|
|
|
initdInfo = info;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (initdInfo != null)
|
|
|
|
|
break;
|
|
|
|
|
|
2011-10-07 23:32:03 +08:00
|
|
|
|
assemblyResolverInfo.findTypes();
|
|
|
|
|
resourceResolverInfo.findTypes();
|
2011-09-22 10:55:30 +08:00
|
|
|
|
decryptResources();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (initdInfo == null)
|
|
|
|
|
throw new ApplicationException("Could not initialize all stringDecrypterInfos");
|
|
|
|
|
|
|
|
|
|
initd[initdInfo] = true;
|
|
|
|
|
initStringDecrypter(initdInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initStringDecrypter(StringDecrypterInfo info) {
|
|
|
|
|
Log.v("Adding string decrypter. Resource: {0}", Utils.toCsharpString(info.StringsResource.Name));
|
|
|
|
|
var decrypter = new StringDecrypter(info);
|
|
|
|
|
if (decrypter.CanDecrypt) {
|
|
|
|
|
staticStringDecrypter.add(DotNetUtils.getMethod(info.GetStringDelegate, "Invoke"), (method, args) => {
|
|
|
|
|
var fieldDefinition = DotNetUtils.getField(module, (FieldReference)args[0]);
|
|
|
|
|
return decrypter.decrypt(fieldDefinition.MetadataToken.ToInt32(), (int)args[1]);
|
|
|
|
|
});
|
|
|
|
|
staticStringDecrypter.add(info.StringDecrypterMethod, (method, args) => {
|
|
|
|
|
return decrypter.decrypt(0, (int)args[0]);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
stringDecrypters.Add(decrypter);
|
|
|
|
|
DeobfuscatedFile.stringDecryptersAdded();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void deobfuscateMethodEnd(Blocks blocks) {
|
|
|
|
|
proxyDelegateFinder.deobfuscate(blocks);
|
|
|
|
|
removeAutomatedErrorReportingCode(blocks);
|
|
|
|
|
removeTamperProtection(blocks);
|
|
|
|
|
removeStringsInitCode(blocks);
|
|
|
|
|
base.deobfuscateMethodEnd(blocks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void deobfuscateEnd() {
|
|
|
|
|
removeProxyDelegates(proxyDelegateFinder);
|
|
|
|
|
removeMemoryManagerStuff();
|
|
|
|
|
removeTamperProtectionStuff();
|
|
|
|
|
removeStringDecryptionStuff();
|
|
|
|
|
removeResolverInfoTypes(assemblyResolverInfo, "Assembly");
|
|
|
|
|
removeResolverInfoTypes(resourceResolverInfo, "Resource");
|
|
|
|
|
base.deobfuscateEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeResolverInfoTypes(ResolverInfoBase info, string typeName) {
|
|
|
|
|
addTypeToBeRemoved(info.CallResolverType, string.Format("{0} resolver type #1", typeName));
|
2011-11-06 22:24:30 +08:00
|
|
|
|
addTypeToBeRemoved(info.Type, string.Format("{0} resolver type #2", typeName));
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeAutomatedErrorReportingCode(Blocks blocks) {
|
|
|
|
|
if (!options.RemoveAutomatedErrorReporting)
|
|
|
|
|
return;
|
|
|
|
|
if (automatedErrorReportingFinder.ExceptionLoggerRemover.remove(blocks))
|
|
|
|
|
Log.v("Removed Automated Error Reporting code");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeTamperProtection(Blocks blocks) {
|
|
|
|
|
if (!options.RemoveTamperProtection)
|
|
|
|
|
return;
|
|
|
|
|
if (tamperProtectionRemover.remove(blocks))
|
|
|
|
|
Log.v("Removed Tamper Protection code");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeMemoryManagerStuff() {
|
|
|
|
|
if (!options.RemoveMemoryManager)
|
|
|
|
|
return;
|
2011-11-06 22:24:30 +08:00
|
|
|
|
addTypeToBeRemoved(memoryManagerInfo.Type, "Memory manager type");
|
2011-09-22 10:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeTamperProtectionStuff() {
|
|
|
|
|
if (!options.RemoveTamperProtection)
|
|
|
|
|
return;
|
|
|
|
|
addMethodsToBeRemoved(tamperProtectionRemover.PinvokeMethods, "Tamper protection PInvoke method");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool canRemoveStringDecrypterStuff() {
|
|
|
|
|
return Operations.DecryptStrings != OpDecryptString.None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeStringDecryptionStuff() {
|
|
|
|
|
if (!canRemoveStringDecrypterStuff())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
foreach (var decrypter in stringDecrypters) {
|
|
|
|
|
var info = decrypter.StringDecrypterInfo;
|
|
|
|
|
addResourceToBeRemoved(info.StringsResource, "Encrypted strings");
|
|
|
|
|
addFieldsToBeRemoved(info.getAllStringDelegateFields(), "String decrypter delegate field");
|
|
|
|
|
|
|
|
|
|
addTypeToBeRemoved(info.StringsEncodingClass, "String decrypter type");
|
|
|
|
|
addTypeToBeRemoved(info.StringsType, "Creates the string decrypter delegates");
|
|
|
|
|
addTypeToBeRemoved(info.GetStringDelegate, "String decrypter delegate type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void removeStringsInitCode(Blocks blocks) {
|
|
|
|
|
if (!canRemoveStringDecrypterStuff())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (blocks.Method.Name == ".cctor") {
|
|
|
|
|
foreach (var decrypter in stringDecrypters)
|
|
|
|
|
decrypter.StringDecrypterInfo.removeInitCode(blocks);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override IEnumerable<string> getStringDecrypterMethods() {
|
|
|
|
|
var list = new List<string>();
|
|
|
|
|
foreach (var method in staticStringDecrypter.Methods)
|
|
|
|
|
list.Add(method.MetadataToken.ToInt32().ToString("X8"));
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|