Decrypt main assembly and embedded assemblies

This commit is contained in:
de4dot 2012-05-31 15:38:51 +02:00
parent ddc270b963
commit 58b62ff914
6 changed files with 1099 additions and 1 deletions

View File

@ -92,6 +92,9 @@
<Compile Include="deobfuscators\CliSecure\vm\UnknownHandlerInfo.cs" />
<Compile Include="deobfuscators\CliSecure\vm\VmOpCodeHandlerDetector.cs" />
<Compile Include="deobfuscators\CliSecure\vm\VmOperands.cs" />
<Compile Include="deobfuscators\CodeFort\PasswordFinder.cs" />
<Compile Include="deobfuscators\CodeFort\AssemblyData.cs" />
<Compile Include="deobfuscators\CodeFort\AssemblyDecrypter.cs" />
<Compile Include="deobfuscators\CodeFort\CfMethodCallInliner.cs" />
<Compile Include="deobfuscators\CodeFort\Deobfuscator.cs" />
<Compile Include="deobfuscators\CodeFort\ProxyCallFixer.cs" />

View File

@ -0,0 +1,534 @@
/*
Copyright (C) 2011-2012 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.Reflection;
using System.Reflection.Emit;
using System.Text;
namespace de4dot.code.deobfuscators.CodeFort {
interface IType {
Type get(SerializedTypes serializedTypes);
}
static class ITypeCreator {
public static IType create(string name) {
return new StringType(name);
}
public static IType create(Type type) {
return new ExistingType(type);
}
}
class StringType : IType {
readonly string name;
public StringType(string name) {
this.name = name;
}
public Type get(SerializedTypes serializedTypes) {
return serializedTypes.getBuilderType(name);
}
public override string ToString() {
return name;
}
}
class ExistingType : IType {
readonly Type type;
public ExistingType(Type type) {
this.type = type;
}
public Type get(SerializedTypes serializedTypes) {
return type;
}
public override string ToString() {
return type.ToString();
}
}
class GenericType : IType {
IType type;
IType[] genericArgs;
public GenericType(string type, IType[] genericArgs)
: this(ITypeCreator.create(type), genericArgs) {
}
public GenericType(Type type, IType[] genericArgs)
: this(ITypeCreator.create(type), genericArgs) {
}
public GenericType(IType type, IType[] genericArgs) {
this.type = type;
this.genericArgs = genericArgs;
}
public Type get(SerializedTypes serializedTypes) {
var genericType = type.get(serializedTypes);
var types = new List<Type>(genericArgs.Length);
foreach (var ga in genericArgs)
types.Add(ga.get(serializedTypes));
return genericType.MakeGenericType(types.ToArray());
}
public override string ToString() {
var sb = new StringBuilder();
sb.Append(getTypeName());
if (genericArgs != null && genericArgs.Length > 0) {
sb.Append('<');
foreach (var ga in genericArgs)
sb.Append(ga.ToString());
sb.Append('>');
}
return sb.ToString();
}
string getTypeName() {
var typeName = type.ToString();
int index = typeName.LastIndexOf('`');
if (index < 0)
return typeName;
return typeName.Substring(0, index);
}
}
class ListType : GenericType {
public ListType(string type)
: this(ITypeCreator.create(type)) {
}
public ListType(Type type)
: this(ITypeCreator.create(type)) {
}
public ListType(IType type)
: base(typeof(List<>), new IType[] { type }) {
}
}
class TypeInfoBase {
public readonly string name;
public readonly string dcNamespace;
public readonly string dcName;
protected TypeInfoBase(string name, string dcNamespace, string dcName) {
this.name = name;
this.dcNamespace = dcNamespace;
this.dcName = dcName;
}
public override string ToString() {
if (!string.IsNullOrEmpty(dcNamespace))
return string.Format("{0} - {1}.{2}", name, dcNamespace, dcName);
return string.Format("{0} - {1}", name, dcName);
}
}
class TypeInfo : TypeInfoBase {
public readonly IType baseType;
public readonly TypeFieldInfo[] fieldInfos;
public TypeInfo(string name, string dcName, TypeFieldInfo[] fieldInfos)
: this(name, "", dcName, fieldInfos) {
}
public TypeInfo(string name, string dcNamespace, string dcName, TypeFieldInfo[] fieldInfos)
: this(ITypeCreator.create(typeof(object)), name, dcNamespace, dcName, fieldInfos) {
}
public TypeInfo(IType baseType, string name, string dcName, TypeFieldInfo[] fieldInfos)
: this(baseType, name, "", dcName, fieldInfos) {
}
public TypeInfo(IType baseType, string name, string dcNamespace, string dcName, TypeFieldInfo[] fieldInfos)
: base(name, dcNamespace, dcName) {
this.baseType = baseType;
this.fieldInfos = fieldInfos;
}
}
class TypeFieldInfo {
public readonly IType type;
public readonly string name;
public readonly string dmName;
public TypeFieldInfo(string type, string name, string dmName)
: this(ITypeCreator.create(type), name, dmName) {
}
public TypeFieldInfo(Type type, string name, string dmName)
: this(ITypeCreator.create(type), name, dmName) {
}
public TypeFieldInfo(IType type, string name, string dmName) {
this.type = type;
this.name = name;
this.dmName = dmName;
}
public override string ToString() {
return string.Format("{0} {1} - {2}", type, name, dmName);
}
}
class EnumInfo : TypeInfoBase {
public readonly EnumFieldInfo[] fieldInfos;
public readonly Type underlyingType = typeof(int);
public EnumInfo(string name, string dcName, EnumFieldInfo[] fieldInfos)
: this(name, "", dcName, fieldInfos) {
}
public EnumInfo(string name, string dcNamespace, string dcName, EnumFieldInfo[] fieldInfos)
: base(name, dcNamespace, dcName) {
this.fieldInfos = fieldInfos;
}
}
class EnumFieldInfo {
public readonly int value;
public readonly string name;
public readonly string emValue;
public EnumFieldInfo(int value, string name, string emValue) {
this.value = value;
this.name = name;
this.emValue = emValue;
}
public override string ToString() {
return string.Format("({0}) {1} - {2}", value, name, emValue);
}
}
class SerializedTypes {
const string serializationAssemblyname = "System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
static readonly EnumInfo[] enumInfos = new EnumInfo[] {
new EnumInfo("InstructionType", "a", new EnumFieldInfo[] {
new EnumFieldInfo(0, "BeginCatchBlock", "1"),
new EnumFieldInfo(1, "BeginExceptFilterBlock", "2"),
new EnumFieldInfo(2, "BeginExceptionBlock", "3"),
new EnumFieldInfo(3, "BeginFaultBlock", "4"),
new EnumFieldInfo(4, "BeginFinallyBlock", "5"),
new EnumFieldInfo(5, "BeginScope", "6"),
new EnumFieldInfo(6, "LocalVariable", "7"),
new EnumFieldInfo(7, "Label", "8"),
new EnumFieldInfo(8, "NoOperand", "A"),
new EnumFieldInfo(9, "ByteOperand", "B"),
new EnumFieldInfo(10, "ConstructorOperand", "C"),
new EnumFieldInfo(11, "DoubleOperand", "D"),
new EnumFieldInfo(12, "FieldOperand", "E"),
new EnumFieldInfo(13, "SingleOperand", "F"),
new EnumFieldInfo(14, "Int32Operand", "G"),
new EnumFieldInfo(15, "TargetOperand", "H"),
new EnumFieldInfo(16, "TargetsOperand", "I"),
new EnumFieldInfo(17, "LocalOperand", "J"),
new EnumFieldInfo(18, "Int64Operand", "K"),
new EnumFieldInfo(19, "MethodOperand", "L"),
new EnumFieldInfo(20, "SByteOperand", "M"),
new EnumFieldInfo(21, "Int16Operand", "N"),
new EnumFieldInfo(22, "StringOperand", "O"),
new EnumFieldInfo(23, "TypeOperand", "P"),
new EnumFieldInfo(24, "EndExceptionBlock", "b"),
new EnumFieldInfo(25, "EndScope", "c"),
new EnumFieldInfo(26, "MarkLabel", "d"),
new EnumFieldInfo(27, "NotImpl1", "e"),
new EnumFieldInfo(28, "ThrowException", "f"),
new EnumFieldInfo(29, "NotImpl2", "g"),
}),
new EnumInfo("MemberTypes1", "l", new EnumFieldInfo[] {
new EnumFieldInfo(0, "Constructor", "1"),
new EnumFieldInfo(1, "TypeInitializer", "7"),
new EnumFieldInfo(2, "Method", "2"),
new EnumFieldInfo(3, "Field", "3"),
new EnumFieldInfo(4, "Property", "4"),
new EnumFieldInfo(5, "Event", "5"),
new EnumFieldInfo(6, "NestedType", "6"),
}),
};
static readonly TypeInfo[] typeInfos = new TypeInfo[] {
new TypeInfo("AllTypes", "b", new TypeFieldInfo[] {
new TypeFieldInfo(new ListType("TypeDef"), "Types", "T"),
}),
new TypeInfo("Instruction", "c", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(object), "Operand", "A"),
new TypeFieldInfo("InstructionType", "InstructionType", "K"),
new TypeFieldInfo(typeof(string), "OpCode", "O"),
}),
new TypeInfo("InstructionLabel", "d", new TypeFieldInfo[] {
}),
new TypeInfo("LocalVariable", "e", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(bool), "IsPinned", "P"),
new TypeFieldInfo("TypeRef", "VariableType", "T"),
}),
new TypeInfo("TypeRef", "f", new TypeFieldInfo[] {
new TypeFieldInfo("AssemblyRef", "AssemblyRef", "A"),
new TypeFieldInfo(typeof(string), "ReflectionTypeFullName", "F"),
new TypeFieldInfo(new ListType("TypeRef"), "GenericArguments", "G"),
new TypeFieldInfo("TypeDef", "InternalBaseType", "I"),
new TypeFieldInfo(typeof(int?), "ArrayDimensions", "V"),
}),
new TypeInfo("AssemblyRef", "g", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(string), "Name", "N"),
}),
new TypeInfo("MemberRef", "h", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(int), "BindingFlags", "B"),
new TypeFieldInfo("TypeRef", "DeclaringType", "C"),
new TypeFieldInfo("MemberTypes1", "MemberTypes1", "K"),
new TypeFieldInfo("MemberDef", "MemberDef", "M"),
new TypeFieldInfo(typeof(string), "Name", "N"),
new TypeFieldInfo("TypeRef", "ReturnType", "T"),
}),
new TypeInfo(ITypeCreator.create("MemberRef"), "MethodRef", "i", new TypeFieldInfo[] {
new TypeFieldInfo(new ListType("ParameterRef"), "Parameters", "P"),
new TypeFieldInfo(typeof(int), "CallingConventions", "V"),
}),
new TypeInfo("ParameterRef", "j", new TypeFieldInfo[] {
new TypeFieldInfo("TypeRef", "TypeRef", "T"),
}),
new TypeInfo("TypeDef", "k", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(int), "TypeAttributes", "A"),
new TypeFieldInfo("TypeRef", "BaseType", "B"),
new TypeFieldInfo(new ListType("TypeDef"), "NestedTypes", "E"),
new TypeFieldInfo(new ListType("MemberDef"), "Members", "M"),
new TypeFieldInfo(typeof(string), "Name", "N"),
}),
new TypeInfo("MemberDef", "m", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(int), "Attributes", "B"),
new TypeFieldInfo("MemberTypes1", "MemberTypes1", "K"),
new TypeFieldInfo(typeof(string), "Name", "N"),
new TypeFieldInfo("TypeRef", "Type", "T"),
}),
new TypeInfo(ITypeCreator.create("MemberDef"), "PropertyDef", "n", new TypeFieldInfo[] {
new TypeFieldInfo("MethodDef", "GetMethod", "G"),
new TypeFieldInfo(new ListType("ParameterDef"), "ParameterTypes", "P"),
new TypeFieldInfo("MethodDef", "SetMethod", "S"),
}),
new TypeInfo(ITypeCreator.create("MemberDef"), "EventDef", "o", new TypeFieldInfo[] {
new TypeFieldInfo("MethodDef", "AddOnMethod", "A"),
new TypeFieldInfo("MethodDef", "RemoveOnMethod", "R"),
}),
new TypeInfo(ITypeCreator.create("MemberDef"), "MethodDef", "p", new TypeFieldInfo[] {
new TypeFieldInfo(new ListType("Instruction"), "Instructions", "A"),
new TypeFieldInfo(typeof(CallingConventions), "CallingConventions", "C"),
new TypeFieldInfo(typeof(MethodImplAttributes), "MethodImplAttributes", "I"),
new TypeFieldInfo(new ListType("ParameterDef"), "ParameterTypes", "P"),
}),
new TypeInfo("ParameterDef", "q", new TypeFieldInfo[] {
new TypeFieldInfo(typeof(string), "Name", "N"),
new TypeFieldInfo("TypeRef", "TypeRef", "T"),
}),
};
class PropertyInfoCreator {
Type type;
List<PropertyInfo> properties = new List<PropertyInfo>();
List<object> values = new List<object>();
public PropertyInfo[] Properties {
get { return properties.ToArray(); }
}
public object[] Values {
get { return values.ToArray(); }
}
public PropertyInfoCreator(Type type) {
this.type = type;
}
public void add(string propertyName, object value) {
var prop = type.GetProperty(propertyName);
if (prop == null)
throw new ApplicationException(string.Format("Could not find property {0} (type {1})", propertyName, type));
properties.Add(prop);
values.Add(value);
}
}
ModuleBuilder moduleBuilder;
Dictionary<string, EnumBuilder> enumBuilders = new Dictionary<string, EnumBuilder>(StringComparer.Ordinal);
Dictionary<string, TypeBuilder> typeBuilders = new Dictionary<string, TypeBuilder>(StringComparer.Ordinal);
Dictionary<string, Type> createdTypes = new Dictionary<string, Type>(StringComparer.Ordinal);
public SerializedTypes(ModuleBuilder moduleBuilder) {
this.moduleBuilder = moduleBuilder;
createTypeBuilders();
initializeEnums();
initializeTypes();
createTypes();
}
void createTypeBuilders() {
foreach (var info in enumInfos)
add(info.name, moduleBuilder.DefineEnum(info.name, TypeAttributes.Public, info.underlyingType));
foreach (var info in typeInfos)
add(info.name, moduleBuilder.DefineType(info.name, TypeAttributes.Public, info.baseType.get(this)));
}
CustomAttributeBuilder createDataContractAttribute(string ns, string name, bool isReference) {
var dcAttr = Type.GetType("System.Runtime.Serialization.DataContractAttribute," + serializationAssemblyname);
var ctor = dcAttr.GetConstructor(Type.EmptyTypes);
var propCreator = new PropertyInfoCreator(dcAttr);
propCreator.add("Namespace", ns);
propCreator.add("Name", name);
propCreator.add("IsReference", isReference);
return new CustomAttributeBuilder(ctor, new object[0], propCreator.Properties, propCreator.Values);
}
CustomAttributeBuilder createEnumMemberAttribute(string value) {
var emAttr = Type.GetType("System.Runtime.Serialization.EnumMemberAttribute," + serializationAssemblyname);
var ctor = emAttr.GetConstructor(Type.EmptyTypes);
var propCreator = new PropertyInfoCreator(emAttr);
propCreator.add("Value", value);
return new CustomAttributeBuilder(ctor, new object[0], propCreator.Properties, propCreator.Values);
}
CustomAttributeBuilder createDataMemberAttribute(string name, bool emitDefaultValue) {
var dmAttr = Type.GetType("System.Runtime.Serialization.DataMemberAttribute," + serializationAssemblyname);
var ctor = dmAttr.GetConstructor(Type.EmptyTypes);
var propCreator = new PropertyInfoCreator(dmAttr);
propCreator.add("Name", name);
propCreator.add("EmitDefaultValue", emitDefaultValue);
return new CustomAttributeBuilder(ctor, new object[0], propCreator.Properties, propCreator.Values);
}
void add(string name, EnumBuilder builder) {
if (enumBuilders.ContainsKey(name))
throw new ApplicationException(string.Format("Enum {0} already exists", name));
enumBuilders[name] = builder;
}
void add(string name, TypeBuilder builder) {
if (typeBuilders.ContainsKey(name))
throw new ApplicationException(string.Format("Type {0} already exists", name));
typeBuilders[name] = builder;
}
void initializeEnums() {
foreach (var info in enumInfos) {
var builder = enumBuilders[info.name];
builder.SetCustomAttribute(createDataContractAttribute(info.dcNamespace, info.dcName, false));
foreach (var fieldInfo in info.fieldInfos) {
var fieldBuilder = builder.DefineLiteral(fieldInfo.name, fieldInfo.value);
fieldBuilder.SetCustomAttribute(createEnumMemberAttribute(fieldInfo.emValue));
}
}
}
void initializeTypes() {
foreach (var info in typeInfos) {
var builder = typeBuilders[info.name];
builder.SetCustomAttribute(createDataContractAttribute(info.dcNamespace, info.dcName, true));
foreach (var fieldInfo in info.fieldInfos) {
var fieldBuilder = builder.DefineField(fieldInfo.name, fieldInfo.type.get(this), FieldAttributes.Public);
fieldBuilder.SetCustomAttribute(createDataMemberAttribute(fieldInfo.dmName, false));
}
}
}
void createTypes() {
foreach (var info in enumInfos)
createdTypes[info.name] = enumBuilders[info.name].CreateType();
foreach (var info in typeInfos)
createdTypes[info.name] = typeBuilders[info.name].CreateType();
moduleBuilder = null;
enumBuilders = null;
typeBuilders = null;
}
public Type getBuilderType(string name) {
EnumBuilder enumBuilder;
if (enumBuilders.TryGetValue(name, out enumBuilder))
return enumBuilder;
TypeBuilder typeBuilder;
if (typeBuilders.TryGetValue(name, out typeBuilder))
return typeBuilder;
throw new ApplicationException(string.Format("Could not find type {0}", name));
}
Type getType(string name) {
return createdTypes[name];
}
public object deserialize(byte[] data) {
var serializerType = Type.GetType("System.Runtime.Serialization.DataContractSerializer," + serializationAssemblyname);
if (serializerType == null)
throw new ApplicationException("You need .NET 3.0 or later to decrypt the assembly");
var quotasType = Type.GetType("System.Xml.XmlDictionaryReaderQuotas," + serializationAssemblyname);
var serializerCtor = serializerType.GetConstructor(new Type[] { typeof(Type), typeof(IEnumerable<Type>) });
var serializer = serializerCtor.Invoke(new object[] { getType("AllTypes"), new Type[] {
getType("MemberTypes1"),
getType("Instruction"),
getType("InstructionType"),
getType("InstructionLabel"),
getType("LocalVariable"),
getType("ParameterDef"),
getType("TypeDef"),
getType("MemberDef"),
getType("MethodDef"),
getType("EventDef"),
getType("PropertyDef"),
getType("ParameterRef"),
getType("TypeRef"),
getType("MemberRef"),
getType("MethodRef"),
}});
var xmlReaderType = Type.GetType("System.Xml.XmlDictionaryReader," + serializationAssemblyname);
var createReaderMethod = xmlReaderType.GetMethod("CreateBinaryReader", new Type[] { typeof(Stream), quotasType });
var xmlReader = createReaderMethod.Invoke(null, new object[] {
new MemoryStream(data),
quotasType.InvokeMember("Max", BindingFlags.GetProperty, null, null, new object[0]),
});
using ((IDisposable)xmlReader) {
var readObjectMethod = serializerType.GetMethod("ReadObject", new Type[] { xmlReaderType });
return readObjectMethod.Invoke(serializer, new object[] { xmlReader });
}
}
}
}

View File

@ -0,0 +1,284 @@
/*
Copyright (C) 2011-2012 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.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeFort {
class AssemblyDecrypter {
ModuleDefinition module;
EmbeddedResource assemblyEncryptedResource;
PasswordInfo embedPassword;
MethodDefinition embedInitMethod;
MethodDefinition embedResolverMethod;
public class AssemblyInfo {
public readonly byte[] data;
public readonly EmbeddedResource resource;
public readonly string asmFullName;
public readonly string asmSimpleName;
public readonly string extension;
public AssemblyInfo(byte[] data, EmbeddedResource resource, string asmFullName, string asmSimpleName, string extension) {
this.data = data;
this.resource = resource;
this.asmFullName = asmFullName;
this.asmSimpleName = asmSimpleName;
this.extension = extension;
}
public override string ToString() {
return asmFullName;
}
}
public bool EncryptedDetected {
get { return assemblyEncryptedResource != null; }
}
public bool Detected {
get { return EncryptedDetected || embedInitMethod != null; ; }
}
public TypeDefinition Type {
get { return embedInitMethod != null ? embedInitMethod.DeclaringType : null; }
}
public MethodDefinition InitMethod {
get { return embedInitMethod; }
}
public AssemblyDecrypter(ModuleDefinition module) {
this.module = module;
}
public AssemblyDecrypter(ModuleDefinition module, AssemblyDecrypter oldOne) {
this.module = module;
this.embedPassword = oldOne.embedPassword;
}
public void find() {
if (findEncrypted())
return;
findEmbedded();
}
static readonly string[] encryptedRequiredLocals = new string[] {
"System.Byte",
"System.Byte[]",
"System.Int32",
"System.IO.BinaryReader",
"System.IO.MemoryStream",
"System.IO.Stream",
"System.Object[]",
"System.Reflection.Assembly",
"System.Type[]",
};
bool findEncrypted() {
var ep = module.EntryPoint;
if (ep == null || ep.Body == null)
return false;
if (!DotNetUtils.isMethod(ep, "System.Void", "(System.String[])"))
return false;
var initMethod = checkCalledMethods(ep);
if (initMethod == null || !new LocalTypes(initMethod).all(encryptedRequiredLocals))
return false;
var resource = getResource();
if (resource == null)
return false;
assemblyEncryptedResource = resource;
return true;
}
MethodDefinition checkCalledMethods(MethodDefinition method) {
int calls = 0;
TypeDefinition type = null;
MethodDefinition initMethod = null;
foreach (var calledMethod in DotNetUtils.getCalledMethods(module, method)) {
calls++;
if (type != null && calledMethod.DeclaringType != type)
return null;
type = calledMethod.DeclaringType;
if (initMethod == null)
initMethod = calledMethod;
}
if (calls != 2)
return null;
return initMethod;
}
EmbeddedResource getResource() {
return DotNetUtils.getResource(module, "_") as EmbeddedResource;
}
bool findEmbedded() {
foreach (var calledMethod in DotNetUtils.getCalledMethods(module, DotNetUtils.getModuleTypeCctor(module))) {
var resolver = checkInitMethod(calledMethod);
if (resolver == null)
continue;
if (!checkType(calledMethod.DeclaringType))
continue;
embedInitMethod = calledMethod;
embedResolverMethod = resolver;
return true;
}
return false;
}
MethodDefinition checkInitMethod(MethodDefinition method) {
if (method == null || !method.IsStatic || method.Body == null)
return null;
if (!DotNetUtils.isMethod(method, "System.Void", "()"))
return null;
var resolver = DeobUtils.getResolveMethod(method);
if (resolver == null || resolver.DeclaringType != method.DeclaringType)
return null;
return resolver;
}
bool checkType(TypeDefinition type) {
if (DotNetUtils.getMethod(type, "System.Byte[]", "(System.Byte[],System.String,System.String,System.Int32,System.String,System.Int32)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.String", "(System.String)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.Byte[]", "(System.Reflection.Assembly,System.String)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.Void", "(System.IO.Stream,System.IO.Stream)") == null)
return false;
return true;
}
public byte[] decrypt() {
if (assemblyEncryptedResource == null)
return null;
var reader = new BinaryReader(assemblyEncryptedResource.GetResourceStream());
var encryptedData = DeobUtils.gunzip(reader.BaseStream, reader.ReadInt32());
reader = new BinaryReader(new MemoryStream(encryptedData));
var serializedData = reader.ReadBytes(reader.ReadInt32());
for (int i = 0; i < serializedData.Length; i++)
serializedData[i] ^= 0xAD;
var encryptedAssembly = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
var passwordFinder = new PasswordFinder(serializedData);
PasswordInfo mainAsmPassword;
passwordFinder.find(out mainAsmPassword, out embedPassword);
return decrypt(mainAsmPassword, encryptedAssembly);
}
static byte[] decrypt(PasswordInfo password, byte[] data) {
const int iterations = 2;
const int numBits = 0x100;
var key = new Rfc2898DeriveBytes(password.passphrase, Encoding.UTF8.GetBytes(password.salt), iterations).GetBytes(numBits / 8);
return DeobUtils.aesDecrypt(data, key, Encoding.UTF8.GetBytes(password.iv));
}
static byte[] gunzip(byte[] data) {
var reader = new BinaryReader(new MemoryStream(data));
return DeobUtils.gunzip(reader.BaseStream, reader.ReadInt32());
}
public List<AssemblyInfo> getAssemblyInfos(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
var infos = new List<AssemblyInfo>();
if (embedResolverMethod != null) {
simpleDeobfuscator.deobfuscate(embedResolverMethod);
simpleDeobfuscator.decryptStrings(embedResolverMethod, deob);
embedPassword = getEmbedPassword(embedResolverMethod);
}
if (embedPassword == null)
return infos;
foreach (var rsrc in module.Resources) {
var resource = rsrc as EmbeddedResource;
if (resource == null)
continue;
if (!Regex.IsMatch(resource.Name, "^cfd_([0-9a-f]{2})+_$"))
continue;
var asmData = decrypt(embedPassword, gunzip(resource.GetResourceData()));
var mod = ModuleDefinition.ReadModule(new MemoryStream(asmData));
infos.Add(new AssemblyInfo(asmData, resource, mod.Assembly.FullName, mod.Assembly.Name.Name, DeobUtils.getExtension(mod.Kind)));
}
return infos;
}
static PasswordInfo getEmbedPassword(MethodDefinition method) {
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 3; i++) {
int index = i;
var ldstr1 = instrs[index++];
if (ldstr1.OpCode.Code != Code.Ldstr)
continue;
var passphrase = getString(ldstr1, instrs, ref index);
var ldstr2 = instrs[index++];
if (ldstr2.OpCode.Code != Code.Ldstr)
continue;
var salt = getString(ldstr2, instrs, ref index);
var ldci4 = instrs[index++];
if (!DotNetUtils.isLdcI4(ldci4))
continue;
var ldstr3 = instrs[index++];
if (ldstr3.OpCode.Code != Code.Ldstr)
continue;
var iv = getString(ldstr3, instrs, ref index);
return new PasswordInfo(passphrase, salt, iv);
}
return null;
}
static string getString(Instruction ldstr, IList<Instruction> instrs, ref int index) {
var s = (string)ldstr.Operand;
if (index >= instrs.Count)
return s;
var call = instrs[index];
if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt)
return s;
index++;
var calledMethod = call.Operand as MethodReference;
if (calledMethod.Name == "ToUpper")
return s.ToUpper();
if (calledMethod.Name == "ToLower")
return s.ToLower();
throw new ApplicationException(string.Format("Unknown method {0}", calledMethod));
}
}
}

View File

@ -58,6 +58,7 @@ namespace de4dot.code.deobfuscators.CodeFort {
Options options;
ProxyCallFixer proxyCallFixer;
StringDecrypter stringDecrypter;
AssemblyDecrypter assemblyDecrypter;
internal class Options : OptionsBase {
}
@ -83,7 +84,8 @@ namespace de4dot.code.deobfuscators.CodeFort {
int val = 0;
int sum = toInt32(proxyCallFixer.Detected) +
toInt32(stringDecrypter.Detected);
toInt32(stringDecrypter.Detected) +
toInt32(assemblyDecrypter.Detected);
if (sum > 0)
val += 100 + 10 * (sum - 1);
@ -95,6 +97,35 @@ namespace de4dot.code.deobfuscators.CodeFort {
proxyCallFixer.findDelegateCreator();
stringDecrypter = new StringDecrypter(module);
stringDecrypter.find();
assemblyDecrypter = new AssemblyDecrypter(module);
assemblyDecrypter.find();
}
public override bool getDecryptedModule(ref byte[] newFileData, ref DumpedMethods dumpedMethods) {
if (!assemblyDecrypter.EncryptedDetected)
return false;
newFileData = assemblyDecrypter.decrypt();
return newFileData != null;
}
public override IDeobfuscator moduleReloaded(ModuleDefinition module) {
var newOne = new Deobfuscator(options);
newOne.setModule(module);
newOne.proxyCallFixer = new ProxyCallFixer(module);
newOne.proxyCallFixer.findDelegateCreator();
newOne.stringDecrypter = new StringDecrypter(module);
newOne.stringDecrypter.find();
newOne.assemblyDecrypter = new AssemblyDecrypter(module, assemblyDecrypter);
newOne.assemblyDecrypter.find();
return newOne;
}
static List<TypeDefinition> lookup(ModuleDefinition module, List<TypeDefinition> types, string errorMsg) {
var list = new List<TypeDefinition>(types.Count);
foreach (var type in types)
list.Add(DeobUtils.lookup(module, type, errorMsg));
return list;
}
public override void deobfuscateBegin() {
@ -104,6 +135,18 @@ namespace de4dot.code.deobfuscators.CodeFort {
DeobfuscatedFile.stringDecryptersAdded();
proxyCallFixer.find();
dumpEmbeddedAssemblies();
}
void dumpEmbeddedAssemblies() {
foreach (var info in assemblyDecrypter.getAssemblyInfos(DeobfuscatedFile, this)) {
DeobfuscatedFile.createAssemblyFile(info.data, info.asmSimpleName, info.extension);
addResourceToBeRemoved(info.resource, string.Format("Embedded assembly: {0}", info.asmFullName));
}
addCctorInitCallToBeRemoved(assemblyDecrypter.InitMethod);
addCallToBeRemoved(module.EntryPoint, assemblyDecrypter.InitMethod);
addTypeToBeRemoved(assemblyDecrypter.Type, "Assembly resolver type");
}
public override void deobfuscateMethodEnd(Blocks blocks) {

View File

@ -0,0 +1,224 @@
/*
Copyright (C) 2011-2012 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.Reflection;
using System.Reflection.Emit;
using Mono.Cecil;
namespace de4dot.code.deobfuscators.CodeFort {
class PasswordInfo {
public string passphrase;
public string salt;
public string iv;
public PasswordInfo(string passphrase, string salt, string iv) {
this.passphrase = passphrase;
this.salt = salt;
this.iv = iv;
}
public override string ToString() {
return string.Format("P:{0}, S:{1}, I:{2}", passphrase, salt, iv);
}
}
class PasswordFinder {
byte[] serializedData;
System.Collections.IList asmTypes;
class Obj {
object obj;
public Obj(object obj) {
this.obj = obj;
}
public string Name {
get { return (string)readField("Name"); }
}
public List<Obj> Members {
get { return getList("Members"); }
}
public List<Obj> Instructions {
get { return getList("Instructions"); }
}
public object Operand {
get { return readField("Operand"); }
}
public string OpCode {
get { return (string)readField("OpCode"); }
}
public Obj MemberDef {
get { return new Obj(readField("MemberDef")); }
}
protected object readField(string name) {
return PasswordFinder.readField(obj, name);
}
public Obj findMethod(string name) {
foreach (var member in Members) {
if (member.obj.GetType().ToString() != "MethodDef")
continue;
if (member.Name != name)
continue;
return member;
}
throw new ApplicationException(string.Format("Could not find method {0}", name));
}
List<Obj> getList(string name) {
return convertList((System.Collections.IList)readField(name));
}
static List<Obj> convertList(System.Collections.IList inList) {
var outList = new List<Obj>(inList.Count);
foreach (var e in inList)
outList.Add(new Obj(e));
return outList;
}
public override string ToString() {
return Name;
}
}
public PasswordFinder(byte[] serializedData) {
this.serializedData = serializedData;
}
static object readField(object instance, string name) {
return instance.GetType().GetField(name).GetValue(instance);
}
static System.Collections.IList toList(object obj) {
return (System.Collections.IList)obj;
}
public void find(out PasswordInfo mainAsmPassword, out PasswordInfo embedPassword) {
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("asm"), AssemblyBuilderAccess.Run);
var moduleBuilder = asmBuilder.DefineDynamicModule("mod");
var serializedTypes = new SerializedTypes(moduleBuilder);
var allTypes = serializedTypes.deserialize(serializedData);
asmTypes = toList(readField(allTypes, "Types"));
mainAsmPassword = findMainAssemblyPassword();
embedPassword = findEmbedPassword();
}
Obj findType(string name) {
foreach (var tmp in asmTypes) {
var type = new Obj(tmp);
if (type.Name == name)
return type;
}
return null;
}
PasswordInfo findMainAssemblyPassword() {
var type = findType("BootstrapDynArguments");
var cctor = type.findMethod(".cctor");
var instrs = cctor.Instructions;
var passphrase = findStringStoreValue(instrs, "KeyPassphrase");
var salt = findStringStoreValue(instrs, "KeySaltValue");
var iv = findStringStoreValue(instrs, "KeyIV");
return new PasswordInfo(passphrase, salt, iv);
}
static string findStringStoreValue(List<Obj> instrs, string fieldName) {
for (int i = 0; i < instrs.Count - 1; i++) {
var ldstr = instrs[i];
if (ldstr.OpCode != "ldstr")
continue;
var stsfld = instrs[i + 1];
if (stsfld.OpCode != "stsfld")
continue;
var memberRef = new Obj(stsfld.Operand);
if (memberRef.MemberDef == null)
continue;
if (memberRef.MemberDef.Name != fieldName)
continue;
return (string)ldstr.Operand;
}
return null;
}
PasswordInfo findEmbedPassword() {
var type = findType("CilEmbeddingHelper");
if (type == null)
return null;
var method = type.findMethod("CurrentDomain_AssemblyResolve");
var instrs = method.Instructions;
for (int i = 0; i < instrs.Count - 3; i++) {
int index = i;
var ldstr1 = instrs[index++];
if (ldstr1.OpCode != "ldstr")
continue;
var passphrase = getString(ldstr1, instrs, ref index);
var ldstr2 = instrs[index++];
if (ldstr2.OpCode != "ldstr")
continue;
var salt = getString(ldstr2, instrs, ref index);
var ldc = instrs[index++];
if (!ldc.OpCode.StartsWith("ldc.i4"))
continue;
var ldstr3 = instrs[index++];
if (ldstr3.OpCode != "ldstr")
continue;
var iv = getString(ldstr3, instrs, ref index);
return new PasswordInfo(passphrase, salt, iv);
}
return null;
}
static string getString(Obj ldstr, List<Obj> instrs, ref int index) {
var s = (string)ldstr.Operand;
if (index >= instrs.Count)
return s;
var call = instrs[index];
if (call.OpCode != "call" && call.OpCode != "callvirt")
return s;
index++;
var op = new Obj(call.Operand);
if (op.Name == "ToUpper")
return s.ToUpper();
if (op.Name == "ToLower")
return s.ToLower();
throw new ApplicationException(string.Format("Unknown method {0}", op.Name));
}
}
}

View File

@ -20,6 +20,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using Mono.Cecil;
using Mono.Cecil.Cil;
@ -154,6 +155,15 @@ namespace de4dot.code.deobfuscators {
return memStream.ToArray();
}
public static byte[] gunzip(Stream input, int decompressedSize) {
using (var gzip = new GZipStream(input, CompressionMode.Decompress)) {
var decompressed = new byte[decompressedSize];
if (gzip.Read(decompressed, 0, decompressedSize) != decompressedSize)
throw new ApplicationException("Could not gzip decompress");
return decompressed;
}
}
public static EmbeddedResource getEmbeddedResourceFromCodeStrings(ModuleDefinition module, MethodDefinition method) {
foreach (var s in DotNetUtils.getCodeStrings(method)) {
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;