de4dot-cex/de4dot.code/deobfuscators/SmartAssembly/StringEncoderClassFinder.cs

210 lines
6.3 KiB
C#
Raw Normal View History

2011-09-22 10:55:30 +08:00
/*
2015-10-30 05:45:26 +08:00
Copyright (C) 2011-2015 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.Collections.Generic;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
2011-09-24 16:26:29 +08:00
using de4dot.blocks;
2011-09-22 10:55:30 +08:00
namespace de4dot.code.deobfuscators.SmartAssembly {
2011-09-22 10:55:30 +08:00
class StringsEncoderInfo {
// SmartAssembly.HouseOfCards.Strings, the class that creates the string decrypter
// delegates
public TypeDef StringsType { get; set; }
public TypeDef GetStringDelegate { get; set; }
public MethodDef CreateStringDelegateMethod { get; set; }
2011-09-22 10:55:30 +08:00
// The class that decodes the strings. Called by the strings delegate or normal code.
public TypeDef StringDecrypterClass { get; set; }
2011-09-22 10:55:30 +08:00
}
class StringEncoderClassFinder {
2012-11-19 00:07:02 +08:00
ModuleDefMD module;
2011-09-22 10:55:30 +08:00
ISimpleDeobfuscator simpleDeobfuscator;
IList<StringsEncoderInfo> stringsEncoderInfos = new List<StringsEncoderInfo>();
public IList<StringsEncoderInfo> StringsEncoderInfos {
get { return stringsEncoderInfos; }
}
2012-11-19 00:07:02 +08:00
public StringEncoderClassFinder(ModuleDefMD module, ISimpleDeobfuscator simpleDeobfuscator) {
2011-09-22 10:55:30 +08:00
this.module = module;
this.simpleDeobfuscator = simpleDeobfuscator;
}
2013-01-19 20:03:57 +08:00
TypeDef GetType(ITypeDefOrRef typeRef) {
return DotNetUtils.GetType(module, typeRef);
2011-09-22 10:55:30 +08:00
}
2013-01-19 20:03:57 +08:00
public void Find() {
FindHouseOfCardsStrings_v2();
2011-09-22 10:55:30 +08:00
if (stringsEncoderInfos.Count == 0)
2013-01-19 20:03:57 +08:00
FindHouseOfCardsStrings_v1();
2011-09-22 10:55:30 +08:00
2013-01-19 20:03:57 +08:00
FindStringDecrypterClasses();
2011-09-22 10:55:30 +08:00
}
// Finds SmartAssembly.HouseOfCards.Strings. It's the class that creates the string
// decrypter delegates.
2013-01-19 20:03:57 +08:00
void FindHouseOfCardsStrings_v2() {
2011-09-22 10:55:30 +08:00
foreach (var type in module.Types) {
if (type.Methods.Count != 1)
continue;
2013-01-19 20:03:57 +08:00
foreach (var method in DotNetUtils.FindMethods(type.Methods, "System.Void", new string[] { "System.Type" })) {
if (CheckDelegateCreatorMethod(type, method))
2011-09-22 10:55:30 +08:00
break;
}
}
}
2013-01-19 20:03:57 +08:00
void FindHouseOfCardsStrings_v1() {
2011-09-22 10:55:30 +08:00
foreach (var type in module.Types) {
if (type.Methods.Count != 1)
continue;
2013-01-19 20:03:57 +08:00
foreach (var method in DotNetUtils.FindMethods(type.Methods, "System.Void", new string[] { })) {
if (CheckDelegateCreatorMethod(type, method))
2011-09-22 10:55:30 +08:00
break;
}
}
}
2013-01-19 20:03:57 +08:00
bool CheckDelegateCreatorMethod(TypeDef type, MethodDef method) {
simpleDeobfuscator.Deobfuscate(method);
2011-09-22 10:55:30 +08:00
2013-01-19 20:03:57 +08:00
var getStringDelegate = FindGetStringDelegate(method);
2011-09-22 10:55:30 +08:00
if (getStringDelegate == null)
return false;
2013-01-19 20:03:57 +08:00
var stringDecrypterClass = FindStringDecrypterClass(method);
2011-09-22 10:55:30 +08:00
if (stringDecrypterClass == null)
return false;
stringsEncoderInfos.Add(new StringsEncoderInfo {
StringsType = type,
GetStringDelegate = getStringDelegate,
StringDecrypterClass = stringDecrypterClass,
CreateStringDelegateMethod = method,
});
return true;
}
// Finds the SmartAssembly.Delegates.GetString delegate
2013-01-19 20:03:57 +08:00
TypeDef FindGetStringDelegate(MethodDef stringsCreateDelegateMethod) {
2011-09-22 10:55:30 +08:00
if (!stringsCreateDelegateMethod.HasBody)
return null;
foreach (var ldtoken in stringsCreateDelegateMethod.Body.Instructions) {
if (ldtoken.OpCode.Code != Code.Ldtoken)
continue;
2012-11-19 00:07:02 +08:00
var typeToken = ldtoken.Operand as ITypeDefOrRef;
2011-09-22 10:55:30 +08:00
if (typeToken == null)
continue;
2013-01-19 20:03:57 +08:00
var delegateType = GetType(typeToken);
if (!DotNetUtils.DerivesFromDelegate(delegateType))
2011-09-22 10:55:30 +08:00
continue;
2012-11-19 00:07:02 +08:00
var invoke = delegateType.FindMethod("Invoke");
2013-01-19 20:03:57 +08:00
if (invoke == null || !DotNetUtils.IsMethod(invoke, "System.String", "(System.Int32)"))
2011-09-22 10:55:30 +08:00
continue;
return delegateType;
}
return null;
}
// Finds the SmartAssembly.StringsEncoding.Strings class. This class decrypts the
// strings in the resources. It gets called by the SmartAssembly.Delegates.GetString
// delegate instances which were created by SmartAssembly.HouseOfCards.Strings.
2013-01-19 20:03:57 +08:00
TypeDef FindStringDecrypterClass(MethodDef stringsCreateDelegateMethod) {
2011-09-22 10:55:30 +08:00
if (!stringsCreateDelegateMethod.HasBody)
return null;
foreach (var ldtoken in stringsCreateDelegateMethod.Body.Instructions) {
if (ldtoken.OpCode.Code != Code.Ldtoken)
continue;
2012-11-19 00:07:02 +08:00
var typeToken = ldtoken.Operand as ITypeDefOrRef;
2011-09-22 10:55:30 +08:00
if (typeToken == null)
continue;
2013-01-19 20:03:57 +08:00
var type = GetType(typeToken);
if (type == null || DotNetUtils.DerivesFromDelegate(type))
2011-09-22 10:55:30 +08:00
continue;
2013-01-19 20:03:57 +08:00
if (!CouldBeStringDecrypterClass(type))
2011-09-22 10:55:30 +08:00
continue;
return type;
}
return null;
}
2013-01-19 20:03:57 +08:00
void FindStringDecrypterClasses() {
var foundClasses = new Dictionary<TypeDef, bool>();
2011-09-22 10:55:30 +08:00
foreach (var info in stringsEncoderInfos)
foundClasses[info.StringDecrypterClass] = true;
foreach (var type in module.Types) {
2013-01-19 20:03:57 +08:00
if (!foundClasses.ContainsKey(type) && CouldBeStringDecrypterClass(type)) {
2011-09-22 10:55:30 +08:00
stringsEncoderInfos.Add(new StringsEncoderInfo {
StringsType = null,
GetStringDelegate = null,
StringDecrypterClass = type,
});
}
}
}
2011-12-22 12:41:28 +08:00
static string[] fields1x = new string[] {
"System.IO.Stream",
};
static string[] fields2x = new string[] {
"System.IO.Stream",
"System.Int32",
};
static string[] fields3x = new string[] {
"System.Byte[]",
"System.Int32",
};
2013-01-19 20:03:57 +08:00
bool CouldBeStringDecrypterClass(TypeDef type) {
2011-12-22 12:41:28 +08:00
var fields = new FieldTypes(type);
2013-01-19 20:03:57 +08:00
if (fields.Exists("System.Collections.Hashtable") ||
fields.Exists("System.Collections.Generic.Dictionary`2<System.Int32,System.String>") ||
fields.Exactly(fields3x)) {
2012-11-19 00:07:02 +08:00
if (type.FindStaticConstructor() == null)
2011-12-22 12:41:28 +08:00
return false;
}
2013-01-19 20:03:57 +08:00
else if (fields.Exactly(fields1x) || fields.Exactly(fields2x)) {
2011-09-22 10:55:30 +08:00
}
2011-12-22 12:41:28 +08:00
else
2011-09-22 10:55:30 +08:00
return false;
2013-01-19 20:03:57 +08:00
var methods = new List<MethodDef>(DotNetUtils.GetNormalMethods(type));
2011-09-22 10:55:30 +08:00
if (methods.Count != 1)
return false;
var method = methods[0];
2013-01-19 20:03:57 +08:00
if (!DotNetUtils.IsMethod(method, "System.String", "(System.Int32)"))
2011-09-22 10:55:30 +08:00
return false;
if (!method.IsStatic || !method.HasBody)
return false;
return true;
}
}
}