Add support for another obfuscator

This commit is contained in:
de4dot 2012-01-07 20:27:07 +01:00
parent 9d08a7fe34
commit 44e58066b3
14 changed files with 2446 additions and 0 deletions

View File

@ -58,6 +58,18 @@
<Compile Include="AssemblyClient\SameAppDomainAssemblyServerLoader.cs" />
<Compile Include="AssemblyResolver.cs" />
<Compile Include="deobfuscators\ArrayFinder.cs" />
<Compile Include="deobfuscators\Babel_NET\ConstantsDecrypter.cs" />
<Compile Include="deobfuscators\Babel_NET\Deobfuscator.cs" />
<Compile Include="deobfuscators\Babel_NET\ImageReader.cs" />
<Compile Include="deobfuscators\Babel_NET\MemberReferenceConverter.cs" />
<Compile Include="deobfuscators\Babel_NET\MethodBodyReader.cs" />
<Compile Include="deobfuscators\Babel_NET\MethodReferenceReader.cs" />
<Compile Include="deobfuscators\Babel_NET\MethodBodyReaderBase.cs" />
<Compile Include="deobfuscators\Babel_NET\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\Babel_NET\ProxyDelegateFinder.cs" />
<Compile Include="deobfuscators\Babel_NET\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\Babel_NET\ResourceResolver.cs" />
<Compile Include="deobfuscators\Babel_NET\StringDecrypter.cs" />
<Compile Include="deobfuscators\CliSecure\CliSecureRtType.cs" />
<Compile Include="deobfuscators\CliSecure\Deobfuscator.cs" />
<Compile Include="deobfuscators\CliSecure\MethodsDecrypter.cs" />

View File

@ -0,0 +1,296 @@
/*
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.Runtime.Serialization.Formatters.Binary;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class ConstantsDecrypter {
ModuleDefinition module;
InitializedDataCreator initializedDataCreator;
TypeDefinition decrypterType;
MethodDefinition int32Decrypter;
MethodDefinition int64Decrypter;
MethodDefinition singleDecrypter;
MethodDefinition doubleDecrypter;
MethodDefinition arrayDecrypter;
EmbeddedResource encryptedResource;
int[] decryptedInts;
long[] decryptedLongs;
float[] decryptedFloats;
double[] decryptedDoubles;
public bool Detected {
get { return decrypterType != null; }
}
public bool CanDecrypt {
get { return encryptedResource != null; }
}
public Resource Resource {
get { return encryptedResource; }
}
public TypeDefinition Type {
get { return decrypterType; }
}
public MethodDefinition Int32Decrypter {
get { return int32Decrypter; }
}
public MethodDefinition Int64Decrypter {
get { return int64Decrypter; }
}
public MethodDefinition SingleDecrypter {
get { return singleDecrypter; }
}
public MethodDefinition DoubleDecrypter {
get { return doubleDecrypter; }
}
public MethodDefinition ArrayDecrypter {
get { return arrayDecrypter; }
}
public ConstantsDecrypter(ModuleDefinition module, InitializedDataCreator initializedDataCreator) {
this.module = module;
this.initializedDataCreator = initializedDataCreator;
}
public void find() {
foreach (var type in module.Types) {
if (!isConstantDecrypter(type))
continue;
int32Decrypter = DotNetUtils.getMethod(type, "System.Int32", "(System.Int32)");
int64Decrypter = DotNetUtils.getMethod(type, "System.Int64", "(System.Int32)");
singleDecrypter = DotNetUtils.getMethod(type, "System.Single", "(System.Int32)");
doubleDecrypter = DotNetUtils.getMethod(type, "System.Double", "(System.Int32)");
arrayDecrypter = DotNetUtils.getMethod(type, "System.Array", "(System.Byte[])");
decrypterType = type;
return;
}
}
bool isConstantDecrypter(TypeDefinition type) {
if (type.HasEvents)
return false;
if (type.NestedTypes.Count != 1)
return false;
var nested = type.NestedTypes[0];
if (!checkNestedFields(nested))
return false;
if (DotNetUtils.getMethod(type, "System.Int32", "(System.Int32)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.Int64", "(System.Int32)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.Single", "(System.Int32)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.Double", "(System.Int32)") == null)
return false;
if (DotNetUtils.getMethod(type, "System.Array", "(System.Byte[])") == null)
return false;
return true;
}
static string[] requiredTypes = new string[] {
"System.Int32[]",
"System.Int64[]",
"System.Single[]",
"System.Double[]",
};
bool checkNestedFields(TypeDefinition nested) {
if (!new FieldTypes(nested).all(requiredTypes))
return false;
foreach (var field in nested.Fields) {
if (MemberReferenceHelper.compareTypes(nested, field.FieldType))
return true;
}
return false;
}
public void initialize(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
encryptedResource = findEncryptedResource(simpleDeobfuscator, deob);
if (encryptedResource == null) {
Log.w("Could not find encrypted constants resource");
return;
}
var decrypted = new ResourceDecrypter(module).decrypt(encryptedResource.GetResourceData());
var reader = new BinaryReader(new MemoryStream(decrypted));
int count;
count = reader.ReadInt32();
decryptedInts = new int[count];
while (count-- > 0)
decryptedInts[count] = reader.ReadInt32();
count = reader.ReadInt32();
decryptedLongs = new long[count];
while (count-- > 0)
decryptedLongs[count] = reader.ReadInt64();
count = reader.ReadInt32();
decryptedFloats = new float[count];
while (count-- > 0)
decryptedFloats[count] = reader.ReadSingle();
count = reader.ReadInt32();
decryptedDoubles = new double[count];
while (count-- > 0)
decryptedDoubles[count] = reader.ReadDouble();
}
EmbeddedResource findEncryptedResource(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
foreach (var method in decrypterType.Methods) {
if (!DotNetUtils.isMethod(method, "System.String", "()"))
continue;
if (!method.IsStatic)
continue;
simpleDeobfuscator.deobfuscate(method);
simpleDeobfuscator.decryptStrings(method, deob);
foreach (var s in DotNetUtils.getCodeStrings(method)) {
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
if (resource != null)
return resource;
}
}
return null;
}
public int decryptInt32(int index) {
return decryptedInts[index];
}
public long decryptInt64(int index) {
return decryptedLongs[index];
}
public float decryptSingle(int index) {
return decryptedFloats[index];
}
public double decryptDouble(int index) {
return decryptedDoubles[index];
}
struct ArrayInfo {
public FieldDefinition encryptedField;
public ArrayType arrayType;
public int start, len;
public ArrayInfo(int start, int len, FieldDefinition encryptedField, ArrayType arrayType) {
this.start = start;
this.len = len;
this.encryptedField = encryptedField;
this.arrayType = arrayType;
}
}
public void deobfuscate(Blocks blocks) {
if (arrayDecrypter == null)
return;
var infos = new List<ArrayInfo>();
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
var instrs = block.Instructions;
infos.Clear();
for (int i = 0; i < instrs.Count - 6; i++) {
int index = i;
var ldci4 = instrs[index++];
if (!ldci4.isLdcI4())
continue;
var newarr = instrs[index++];
if (newarr.OpCode.Code != Code.Newarr)
continue;
if (newarr.Operand == null || newarr.Operand.ToString() != "System.Byte")
continue;
if (instrs[index++].OpCode.Code != Code.Dup)
continue;
var ldtoken = instrs[index++];
if (ldtoken.OpCode.Code != Code.Ldtoken)
continue;
var field = ldtoken.Operand as FieldDefinition;
if (field == null)
continue;
var call1 = instrs[index++];
if (call1.OpCode.Code != Code.Call && call1.OpCode.Code != Code.Callvirt)
continue;
if (!DotNetUtils.isMethod(call1.Operand as MethodReference, "System.Void", "(System.Array,System.RuntimeFieldHandle)"))
continue;
var call2 = instrs[index++];
if (call2.OpCode.Code != Code.Call && call2.OpCode.Code != Code.Callvirt)
continue;
if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(call2.Operand as MethodReference, arrayDecrypter))
continue;
var castclass = instrs[index++];
if (castclass.OpCode.Code != Code.Castclass)
continue;
var arrayType = castclass.Operand as ArrayType;
if (arrayType == null)
continue;
if (arrayType.ElementType.PrimitiveSize == -1) {
Log.w("Can't decrypt non-primitive type array in method {0}", blocks.Method.MetadataToken.ToInt32());
continue;
}
infos.Add(new ArrayInfo(i, index - i, field, arrayType));
}
infos.Reverse();
foreach (var info in infos) {
var elemSize = info.arrayType.ElementType.PrimitiveSize;
var decrypted = decryptArray(info.encryptedField.InitialValue, elemSize);
initializedDataCreator.addInitializeArrayCode(block, info.start, info.len, info.arrayType.ElementType, decrypted);
Log.v("Decrypted {0} array: {1} elements", info.arrayType.ElementType.ToString(), decrypted.Length / elemSize);
}
}
}
byte[] decryptArray(byte[] encryptedData, int elemSize) {
var decrypted = new ResourceDecrypter(module).decrypt(encryptedData);
var ary = (Array)new BinaryFormatter().Deserialize(new MemoryStream(decrypted));
if (ary is byte[])
return (byte[])ary;
var newAry = new byte[ary.Length * elemSize];
Buffer.BlockCopy(ary, 0, newAry, 0, newAry.Length);
return newAry;
}
}
}

View File

@ -0,0 +1,231 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using Mono.Cecil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
public const string THE_NAME = "Babel .NET";
public const string THE_TYPE = "bl";
BoolOption decryptMethods;
BoolOption decryptResources;
BoolOption decryptConstants;
public DeobfuscatorInfo()
: base() {
decryptMethods = new BoolOption(null, makeArgName("methods"), "Decrypt methods", true);
decryptResources = new BoolOption(null, makeArgName("rsrc"), "Decrypt resources", true);
decryptConstants = new BoolOption(null, makeArgName("consts"), "Decrypt constants and arrays", true);
}
public override string Name {
get { return THE_NAME; }
}
public override string Type {
get { return THE_TYPE; }
}
public override IDeobfuscator createDeobfuscator() {
return new Deobfuscator(new Deobfuscator.Options {
ValidNameRegex = validNameRegex.get(),
DecryptMethods = decryptMethods.get(),
DecryptResources = decryptResources.get(),
DecryptConstants = decryptConstants.get(),
});
}
protected override IEnumerable<Option> getOptionsInternal() {
return new List<Option>() {
decryptMethods,
decryptResources,
decryptConstants,
};
}
}
class Deobfuscator : DeobfuscatorBase {
Options options;
bool foundBabelAttribute = false;
ResourceResolver resourceResolver;
StringDecrypter stringDecrypter;
ConstantsDecrypter constantsDecrypter;
Int32ValueInliner int32ValueInliner;
Int64ValueInliner int64ValueInliner;
SingleValueInliner singleValueInliner;
DoubleValueInliner doubleValueInliner;
ProxyDelegateFinder proxyDelegateFinder;
MethodsDecrypter methodsDecrypter;
internal class Options : OptionsBase {
public bool DecryptMethods { get; set; }
public bool DecryptResources { get; set; }
public bool DecryptConstants { get; set; }
}
public override string Type {
get { return DeobfuscatorInfo.THE_TYPE; }
}
public override string TypeLong {
get { return DeobfuscatorInfo.THE_NAME; }
}
public override string Name {
get { return DeobfuscatorInfo.THE_NAME; }
}
public Deobfuscator(Options options)
: base(options) {
this.options = options;
}
public override void init(ModuleDefinition module) {
base.init(module);
}
protected override int detectInternal() {
int val = 0;
int sum = toInt32(foundBabelAttribute) +
toInt32(resourceResolver.Detected) +
toInt32(stringDecrypter.Detected) +
toInt32(constantsDecrypter.Detected) +
toInt32(proxyDelegateFinder.Detected) +
toInt32(methodsDecrypter.Detected) +
toInt32(hasMetadataStream("Babel"));
if (sum > 0)
val += 100 + 10 * (sum - 1);
return val;
}
protected override void scanForObfuscator() {
findBabelAttribute();
resourceResolver = new ResourceResolver(module);
resourceResolver.find();
stringDecrypter = new StringDecrypter(module);
stringDecrypter.find();
constantsDecrypter = new ConstantsDecrypter(module, initializedDataCreator);
constantsDecrypter.find();
proxyDelegateFinder = new ProxyDelegateFinder(module);
proxyDelegateFinder.findDelegateCreator();
methodsDecrypter = new MethodsDecrypter(module);
methodsDecrypter.find();
}
void findBabelAttribute() {
foreach (var type in module.Types) {
if (type.FullName == "BabelAttribute" || type.FullName == "BabelObfuscatorAttribute") {
foundBabelAttribute = true;
addAttributeToBeRemoved(type, "Obfuscator attribute");
return;
}
}
}
public override void deobfuscateBegin() {
base.deobfuscateBegin();
if (options.DecryptResources) {
addCctorInitCallToBeRemoved(resourceResolver.InitMethod);
addTypeToBeRemoved(resourceResolver.Type, "Resource resolver type");
}
decryptResources();
stringDecrypter.initialize();
if (Operations.DecryptStrings != OpDecryptString.None) {
addResourceToBeRemoved(stringDecrypter.Resource, "Encrypted strings");
addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
if (stringDecrypter.Resource != null) {
Log.v("Adding string decrypter. Resource: {0}", Utils.toCsharpString(stringDecrypter.Resource.Name));
staticStringDecrypter.add(stringDecrypter.DecryptMethod, (method, args) => {
return stringDecrypter.decrypt((int)args[0]);
});
DeobfuscatedFile.stringDecryptersAdded();
}
}
if (options.DecryptMethods) {
methodsDecrypter.initialize(DeobfuscatedFile, this);
methodsDecrypter.decrypt();
}
if (options.DecryptConstants) {
constantsDecrypter.initialize(DeobfuscatedFile, this);
addTypeToBeRemoved(constantsDecrypter.Type, "Constants decrypter type");
addResourceToBeRemoved(constantsDecrypter.Resource, "Encrypted constants");
int32ValueInliner = new Int32ValueInliner();
int32ValueInliner.add(constantsDecrypter.Int32Decrypter, (method, args) => constantsDecrypter.decryptInt32((int)args[0]));
int64ValueInliner = new Int64ValueInliner();
int64ValueInliner.add(constantsDecrypter.Int64Decrypter, (method, args) => constantsDecrypter.decryptInt64((int)args[0]));
singleValueInliner = new SingleValueInliner();
singleValueInliner.add(constantsDecrypter.SingleDecrypter, (method, args) => constantsDecrypter.decryptSingle((int)args[0]));
doubleValueInliner = new DoubleValueInliner();
doubleValueInliner.add(constantsDecrypter.DoubleDecrypter, (method, args) => constantsDecrypter.decryptDouble((int)args[0]));
}
proxyDelegateFinder.find();
}
void decryptResources() {
if (!options.DecryptResources)
return;
var rsrc = resourceResolver.mergeResources();
if (rsrc == null)
return;
addResourceToBeRemoved(rsrc, "Encrypted resources");
}
public override void deobfuscateMethodEnd(Blocks blocks) {
proxyDelegateFinder.deobfuscate(blocks);
if (options.DecryptConstants) {
if (int32ValueInliner.HasHandlers)
int32ValueInliner.decrypt(blocks);
if (int64ValueInliner.HasHandlers)
int64ValueInliner.decrypt(blocks);
if (singleValueInliner.HasHandlers)
singleValueInliner.decrypt(blocks);
if (doubleValueInliner.HasHandlers)
doubleValueInliner.decrypt(blocks);
constantsDecrypter.deobfuscate(blocks);
}
base.deobfuscateMethodEnd(blocks);
}
public override void deobfuscateEnd() {
removeProxyDelegates(proxyDelegateFinder);
methodsDecrypter.Dispose();
base.deobfuscateEnd();
}
public override IEnumerable<string> getStringDecrypterMethods() {
var list = new List<string>();
if (stringDecrypter.DecryptMethod != null)
list.Add(stringDecrypter.DecryptMethod.MetadataToken.ToInt32().ToString("X8"));
return list;
}
}
}

View File

@ -0,0 +1,494 @@
/*
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.Runtime.InteropServices;
using System.IO;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class ImageReader : IDisposable {
static int METHODS_SIG = 0x0000BEBA;
static int METADATA_SIG = 0x0100BEBA;
static int METHOD_NAMES_SIG = 0x0200BEBA;
static int ASSEMBLY_NAMES_SIG = 0x0201BEBA;
static int TYPEREFS_SIG = 0x0202BEBA;
static int STRINGS_SIG = 0x0203BEBA;
enum TypeId : byte {
TypeRef = 0,
GenericInstance = 1,
Pointer = 2,
Array = 3,
ByRef = 4,
}
ModuleDefinition module;
BinaryReader reader;
string[] strings;
AssemblyNameReference[] assemblyNames;
Dictionary<string, int> methodOffsets;
List<TypeReference> typeReferences;
MemberReferenceConverter memberReferenceConverter;
ExternalAssemblies externalAssemblies = new ExternalAssemblies();
public ImageReader(ModuleDefinition module, byte[] data) {
this.module = module;
this.reader = new BinaryReader(new MemoryStream(data));
this.memberReferenceConverter = new MemberReferenceConverter(module);
}
public bool initialize() {
if (reader.ReadInt32() != METHODS_SIG)
return false;
int metadataOffset = getMetadataOffset();
if (metadataOffset < 0)
return false;
reader.BaseStream.Position = metadataOffset + 4;
int version = reader.ReadInt16(); // major, minor
if (version != 0x0001)
return false;
initializeV10();
return true;
}
public void Dispose() {
externalAssemblies.unloadAll();
}
void initializeV10() {
reader.ReadInt16();
int methodNamesOffset = (int)reader.ReadInt64();
int typeReferencesOffset = (int)reader.ReadInt64();
int assemblyReferencesOffset = (int)reader.ReadInt64();
int stringsOffset = (int)reader.ReadInt64();
initializeStrings(stringsOffset);
initializeAssemblyNames(assemblyReferencesOffset);
initializeMethodNames(methodNamesOffset);
initializeTypeReferences(typeReferencesOffset);
}
public void restore(string name, MethodDefinition method) {
var babelMethod = getMethod(name);
var body = method.Body;
body.MaxStackSize = babelMethod.MaxStack;
body.InitLocals = babelMethod.InitLocals;
body.Variables.Clear();
foreach (var local in babelMethod.Locals)
body.Variables.Add(local);
var toNewOperand = new Dictionary<object, object>();
if (babelMethod.ThisParameter != null)
toNewOperand[babelMethod.ThisParameter] = body.ThisParameter;
for (int i = 0; i < method.Parameters.Count; i++)
toNewOperand[babelMethod.Parameters[i]] = method.Parameters[i];
body.Instructions.Clear();
foreach (var instr in babelMethod.Instructions) {
object newOperand;
if (instr.Operand != null && toNewOperand.TryGetValue(instr.Operand, out newOperand))
instr.Operand = newOperand;
body.Instructions.Add(instr);
}
body.ExceptionHandlers.Clear();
foreach (var eh in babelMethod.ExceptionHandlers)
body.ExceptionHandlers.Add(eh);
}
BabelMethodDefinition getMethod(string name) {
int offset = methodOffsets[name];
methodOffsets.Remove(name);
reader.BaseStream.Position = offset;
return new MethodDefinitionReader(this, reader).read();
}
public string readString() {
return strings[readVariableLengthInt32()];
}
public TypeReference readTypeReference() {
return typeReferences[readVariableLengthInt32()];
}
public TypeReference[] readTypeReferences() {
var refs = new TypeReference[readVariableLengthInt32()];
for (int i = 0; i < refs.Length; i++)
refs[i] = readTypeReference();
return refs;
}
public FieldReference readFieldReference() {
var name = readString();
var declaringType = readTypeReference();
var fields = getFields(resolve(declaringType), name);
if (fields == null || fields.Count != 1) {
throw new ApplicationException(string.Format("Couldn't find one field named '{0}' in type {1}",
name,
Utils.removeNewlines(declaringType)));
}
return memberReferenceConverter.convert(fields[0]);
}
static List<FieldDefinition> getFields(TypeDefinition type, string name) {
if (type == null)
return null;
var fields = new List<FieldDefinition>();
foreach (var field in type.Fields) {
if (field.Name == name)
fields.Add(field);
}
return fields;
}
public MethodReference readMethodReference() {
var babelMethodRef = new MethodReferenceReader(this, reader).read();
var method = getMethodReference(babelMethodRef);
if (method == null) {
throw new ApplicationException(string.Format("Could not find method '{0}' in type '{1}'",
Utils.removeNewlines(babelMethodRef.Name),
Utils.removeNewlines(babelMethodRef.DeclaringType)));
}
var git = babelMethodRef.DeclaringType as GenericInstanceType;
if (git == null)
return method;
var newMethod = memberReferenceConverter.copy(method);
newMethod.DeclaringType = babelMethodRef.DeclaringType;
return newMethod;
}
MethodReference getMethodReference(BabelMethodreference babelMethodRef) {
var declaringType = resolve(babelMethodRef.DeclaringType);
if (declaringType == null)
return null;
var methods = getMethods(declaringType, babelMethodRef);
if (methods.Count != 1) {
throw new ApplicationException(string.Format("Couldn't find one method named '{0}' in type {1}",
babelMethodRef.Name,
Utils.removeNewlines(declaringType)));
}
return methods[0];
}
List<MethodReference> getMethods(TypeDefinition declaringType, BabelMethodreference babelMethodRef) {
var methods = new List<MethodReference>();
var git = babelMethodRef.DeclaringType as GenericInstanceType;
IGenericInstance gim = babelMethodRef.IsGenericMethod ? babelMethodRef : null;
foreach (var method in declaringType.Methods) {
if (compareMethod(MethodReferenceInstance.make(method, git, gim), babelMethodRef)) {
if (!babelMethodRef.IsGenericMethod)
methods.Add(memberReferenceConverter.convert(method));
else {
var gim2 = new GenericInstanceMethod(memberReferenceConverter.convert(method));
foreach (var arg in babelMethodRef.GenericArguments)
gim2.GenericArguments.Add(arg);
methods.Add(gim2);
}
}
}
return methods;
}
bool compareMethod(MethodReference method, BabelMethodreference babelMethodRef) {
if (method.Parameters.Count != babelMethodRef.Parameters.Length)
return false;
if (method.Name != babelMethodRef.Name)
return false;
if (method.HasThis != babelMethodRef.HasThis)
return false;
if (method.GenericParameters.Count != babelMethodRef.GenericArguments.Length)
return false;
if (!MemberReferenceHelper.compareTypes(method.MethodReturnType.ReturnType, babelMethodRef.ReturnType))
return false;
for (int i = 0; i < babelMethodRef.Parameters.Length; i++) {
if (!MemberReferenceHelper.compareTypes(method.Parameters[i].ParameterType, babelMethodRef.Parameters[i].ParameterType))
return false;
}
return true;
}
TypeDefinition resolve(TypeReference type) {
if (type is TypeDefinition)
return (TypeDefinition)type;
if (type.IsGenericInstance)
type = ((GenericInstanceType)type).ElementType;
if (type.Scope == module)
return DotNetUtils.getType(module, type);
return externalAssemblies.resolve(type);
}
public CallSite readCallSite() {
var returnType = readTypeReference();
var paramTypes = readTypeReferences();
var callingConvention = (CallingConvention)reader.ReadInt32();
var cs = new CallSite(returnType);
foreach (var paramType in paramTypes)
cs.Parameters.Add(new ParameterDefinition(paramType));
cs.CallingConvention = convertCallingConvention(callingConvention);
return cs;
}
static MethodCallingConvention convertCallingConvention(CallingConvention callingConvention) {
switch (callingConvention) {
case CallingConvention.Winapi: return MethodCallingConvention.Default;
case CallingConvention.Cdecl: return MethodCallingConvention.C;
case CallingConvention.StdCall: return MethodCallingConvention.StdCall;
case CallingConvention.ThisCall: return MethodCallingConvention.ThisCall;
case CallingConvention.FastCall: return MethodCallingConvention.FastCall;
default: throw new ApplicationException(string.Format("Unknown CallingConvention {0}", callingConvention));
}
}
void initializeStrings(int headerOffset) {
reader.BaseStream.Position = headerOffset;
if (reader.ReadInt32() != STRINGS_SIG)
throw new ApplicationException("Invalid strings sig");
strings = new string[readVariableLengthInt32()];
for (int i = 0; i < strings.Length; i++)
strings[i] = reader.ReadString();
}
void initializeAssemblyNames(int headerOffset) {
reader.BaseStream.Position = headerOffset;
if (reader.ReadInt32() != ASSEMBLY_NAMES_SIG)
throw new ApplicationException("Invalid assembly names sig");
assemblyNames = new AssemblyNameReference[readVariableLengthInt32()];
for (int i = 0; i < assemblyNames.Length; i++)
assemblyNames[i] = getModuleAssemblyReference(AssemblyNameReference.Parse(readString()));
}
bool isModuleAssembly(IMetadataScope scope) {
return DotNetUtils.isReferenceToModule(module, scope);
}
AssemblyNameReference getModuleAssemblyReference(AssemblyNameReference asmRef) {
if (isModuleAssembly(asmRef))
return module.Assembly.Name;
return memberReferenceConverter.convert(asmRef);
}
void initializeMethodNames(int headerOffset) {
reader.BaseStream.Position = headerOffset;
if (reader.ReadInt32() != METHOD_NAMES_SIG)
throw new ApplicationException("Invalid methods sig");
int numMethods = readVariableLengthInt32();
methodOffsets = new Dictionary<string, int>(numMethods, StringComparer.Ordinal);
for (int i = 0; i < numMethods; i++) {
var methodName = readString();
methodOffsets[methodName] = readVariableLengthInt32();
}
}
void initializeTypeReferences(int headerOffset) {
reader.BaseStream.Position = headerOffset;
if (reader.ReadInt32() != TYPEREFS_SIG)
throw new ApplicationException("Invalid typerefs sig");
int numTypeRefs = reader.ReadInt32();
typeReferences = new List<TypeReference>(numTypeRefs + 1);
typeReferences.Add(null);
var genericArgFixes = new Dictionary<GenericInstanceType, List<int>>();
for (int i = 0; i < numTypeRefs; i++) {
TypeId typeId = (TypeId)reader.ReadByte();
switch (typeId) {
case TypeId.TypeRef:
typeReferences.Add(readTypeRef());
break;
case TypeId.GenericInstance:
List<int> genericArgs;
var git = readGenericInstanceType(out genericArgs);
typeReferences.Add(git);
genericArgFixes[git] = genericArgs;
break;
case TypeId.Pointer:
typeReferences.Add(readPointerType());
break;
case TypeId.Array:
typeReferences.Add(readArrayType());
break;
case TypeId.ByRef:
typeReferences.Add(readByReferenceType());
break;
default:
throw new ApplicationException(string.Format("Unknown type id {0}", (int)typeId));
}
}
foreach (var kv in genericArgFixes) {
var git = kv.Key;
foreach (var typeNum in kv.Value)
git.GenericArguments.Add(typeReferences[typeNum]);
}
}
TypeReference readTypeRef() {
string ns, name;
parseReflectionTypeName(readString(), out ns, out name);
var asmRef = assemblyNames[readVariableLengthInt32()];
var declaringType = readTypeReference();
var typeReference = new TypeReference(ns, name, module, asmRef) {
DeclaringType = declaringType,
};
typeReference.UpdateElementType();
typeReference = memberReferenceConverter.convert(typeReference);
typeReference.IsValueType = isValueType(typeReference);
return typeReference;
}
bool isValueType(TypeReference typeRef) {
var typeDef = typeRef as TypeDefinition;
if (typeDef != null)
return typeDef.IsValueType;
if (typeRef.Module == module && isModuleAssembly(typeRef.Scope))
typeDef = DotNetUtils.getType(module, typeRef);
else
typeDef = resolve(typeRef);
if (typeDef != null)
return typeDef.IsValueType;
Log.w("Could not determine whether type '{0}' is a value type", Utils.removeNewlines(typeRef));
return false; // Assume it's a reference type
}
static void parseReflectionTypeName(string fullName, out string ns, out string name) {
int index = getLastChar(fullName, '.');
if (index < 0) {
ns = "";
name = fullName;
}
else {
ns = unEscape(fullName.Substring(0, index));
name = fullName.Substring(index + 1);
}
index = getLastChar(name, '+');
if (index < 0)
name = unEscape(name);
else {
ns = "";
name = unEscape(name.Substring(index + 1));
}
}
static int getLastChar(string name, char c) {
if (string.IsNullOrEmpty(name))
return -1;
int index = name.Length - 1;
while (true) {
index = name.LastIndexOf(c, index);
if (index < 0)
return -1;
if (index == 0)
return index;
if (name[index - 1] != '\\')
return index;
index--;
}
}
static string unEscape(string s) {
var sb = new StringBuilder(s.Length);
for (int i = 0; i < s.Length; i++) {
if (s[i] == '\\' && i + 1 < s.Length)
i++;
sb.Append(s[i]);
}
return sb.ToString();
}
GenericInstanceType readGenericInstanceType(out List<int> genericArgs) {
var git = new GenericInstanceType(readTypeReference());
int numArgs = readVariableLengthInt32();
genericArgs = new List<int>(numArgs);
for (int i = 0; i < numArgs; i++)
genericArgs.Add(readVariableLengthInt32());
return git;
}
PointerType readPointerType() {
return new PointerType(readTypeReference());
}
ArrayType readArrayType() {
return new ArrayType(readTypeReference(), readVariableLengthInt32());
}
ByReferenceType readByReferenceType() {
return new ByReferenceType(readTypeReference());
}
public int readVariableLengthInt32() {
byte b = reader.ReadByte();
if ((b & 0x80) == 0)
return b;
if ((b & 0x40) == 0)
return (((int)b & 0x3F) << 8) + reader.ReadByte();
return (((int)b & 0x3F) << 24) +
((int)reader.ReadByte() << 16) +
((int)reader.ReadByte() << 8) +
reader.ReadByte();
}
int getMetadataOffset() {
reader.BaseStream.Position = reader.BaseStream.Length - 4;
for (int i = 0; i < 30; i++) {
if (reader.ReadInt32() == METADATA_SIG)
return (int)reader.BaseStream.Position - 4;
reader.BaseStream.Position -= 8;
}
return -1;
}
}
}

View File

@ -0,0 +1,187 @@
/*
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 Mono.Cecil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class TypeReferenceConverter : TypeReferenceUpdaterBase {
MemberReferenceConverter memberReferenceConverter;
ModuleDefinition Module {
get { return memberReferenceConverter.Module; }
}
public TypeReferenceConverter(MemberReferenceConverter memberReferenceConverter) {
this.memberReferenceConverter = memberReferenceConverter;
}
public TypeReference convert(TypeReference a) {
var newOne = update(a);
if (!(a is GenericParameter) && !MemberReferenceHelper.compareTypes(newOne, a))
throw new ApplicationException("Could not convert type reference");
return newOne;
}
protected override TypeReference updateTypeReference(TypeReference a) {
if (a.Module == Module)
return a;
var newTypeRef = new TypeReference(a.Namespace, a.Name, Module, memberReferenceConverter.convert(a.Scope), a.IsValueType);
foreach (var gp in a.GenericParameters)
newTypeRef.GenericParameters.Add(new GenericParameter(gp.Name, newTypeRef));
newTypeRef.DeclaringType = update(a.DeclaringType);
newTypeRef.UpdateElementType();
return newTypeRef;
}
}
// Converts type references/definitions in one module to this module
class MemberReferenceConverter {
ModuleDefinition module;
public ModuleDefinition Module {
get { return module; }
}
public MemberReferenceConverter(ModuleDefinition module) {
this.module = module;
}
bool isInOurModule(MemberReference memberRef) {
return memberRef.Module == module;
}
public TypeReference convert(TypeReference typeRef) {
if (typeRef == null)
return null;
typeRef = new TypeReferenceConverter(this).convert(typeRef);
return tryGetTypeDefinition(typeRef);
}
public FieldReference convert(FieldReference fieldRef) {
if (isInOurModule(fieldRef))
return tryGetFieldDefinition(fieldRef);
return new FieldReference(fieldRef.Name, convert(fieldRef.FieldType), convert(fieldRef.DeclaringType));
}
public MethodReference convert(MethodReference methodRef) {
if (methodRef.GetType() != typeof(MethodReference) && methodRef.GetType() != typeof(MethodDefinition))
throw new ApplicationException("Invalid method reference type");
if (isInOurModule(methodRef))
return tryGetMethodDefinition(methodRef);
return copy(methodRef);
}
public MethodReference copy(MethodReference methodRef) {
if (methodRef.GetType() != typeof(MethodReference) && methodRef.GetType() != typeof(MethodDefinition))
throw new ApplicationException("Invalid method reference type");
var newMethodRef = new MethodReference(methodRef.Name, convert(methodRef.MethodReturnType.ReturnType), convert(methodRef.DeclaringType));
newMethodRef.HasThis = methodRef.HasThis;
newMethodRef.ExplicitThis = methodRef.ExplicitThis;
newMethodRef.CallingConvention = methodRef.CallingConvention;
foreach (var param in methodRef.Parameters)
newMethodRef.Parameters.Add(new ParameterDefinition(param.Name, param.Attributes, convert(param.ParameterType)));
foreach (var gp in methodRef.GenericParameters)
newMethodRef.GenericParameters.Add(new GenericParameter(gp.Name, newMethodRef));
return newMethodRef;
}
public IMetadataScope convert(IMetadataScope scope) {
switch (scope.MetadataScopeType) {
case MetadataScopeType.AssemblyNameReference:
return convert((AssemblyNameReference)scope);
case MetadataScopeType.ModuleDefinition:
var mod = (ModuleDefinition)scope;
if (mod.Assembly != null)
return convert((AssemblyNameReference)mod.Assembly.Name);
return convert((ModuleReference)scope);
case MetadataScopeType.ModuleReference:
return convert((ModuleReference)scope);
default:
throw new ApplicationException("Unknown MetadataScopeType");
}
}
public AssemblyNameReference convert(AssemblyNameReference asmRef) {
foreach (var modAsmRef in module.AssemblyReferences) {
if (modAsmRef.FullName == asmRef.FullName)
return modAsmRef;
}
var newAsmRef = AssemblyNameReference.Parse(asmRef.FullName);
module.AssemblyReferences.Add(newAsmRef);
return newAsmRef;
}
public ModuleReference convert(ModuleReference modRef) {
foreach (var modModRef in module.ModuleReferences) {
if (modModRef.Name == modRef.Name)
return modModRef;
}
var newModRef = new ModuleReference(modRef.Name);
module.ModuleReferences.Add(newModRef);
return newModRef;
}
public TypeReference tryGetTypeDefinition(TypeReference typeRef) {
return DotNetUtils.getType(module, typeRef) ?? typeRef;
}
public FieldReference tryGetFieldDefinition(FieldReference fieldRef) {
var fieldDef = fieldRef as FieldDefinition;
if (fieldDef != null)
return fieldDef;
var declaringType = DotNetUtils.getType(module, fieldRef.DeclaringType);
if (declaringType == null)
return fieldRef;
foreach (var field in declaringType.Fields) {
if (MemberReferenceHelper.compareFieldReference(field, fieldRef))
return field;
}
return fieldRef;
}
public MethodReference tryGetMethodDefinition(MethodReference methodRef) {
var methodDef = methodRef as MethodDefinition;
if (methodDef != null)
return methodDef;
var declaringType = DotNetUtils.getType(module, methodRef.DeclaringType);
if (declaringType == null)
return methodRef;
foreach (var method in declaringType.Methods) {
if (MemberReferenceHelper.compareMethodReference(method, methodRef))
return method;
}
return methodRef;
}
}
}

View File

@ -0,0 +1,94 @@
/*
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.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace de4dot.code.deobfuscators.Babel_NET {
class MethodBodyReader : MethodBodyReaderBase {
ImageReader imageReader;
public int Flags2 { get; set; }
public short MaxStack { get; set; }
public MethodBodyReader(ImageReader imageReader, BinaryReader reader)
: base(reader) {
this.imageReader = imageReader;
}
public void read(ParameterDefinition[] parameters) {
this.parameters = parameters;
Flags2 = reader.ReadInt16();
MaxStack = reader.ReadInt16();
setLocals(imageReader.readTypeReferences());
readInstructions(imageReader.readVariableLengthInt32());
readExceptionHandlers(imageReader.readVariableLengthInt32());
}
protected override FieldReference readInlineField(Instruction instr) {
return imageReader.readFieldReference();
}
protected override MethodReference readInlineMethod(Instruction instr) {
return imageReader.readMethodReference();
}
protected override CallSite readInlineSig(Instruction instr) {
return imageReader.readCallSite();
}
protected override string readInlineString(Instruction instr) {
return imageReader.readString();
}
protected override MemberReference readInlineTok(Instruction instr) {
switch (reader.ReadByte()) {
case 0: return imageReader.readTypeReference();
case 1: return imageReader.readFieldReference();
case 2: return imageReader.readMethodReference();
default: throw new ApplicationException("Unknown token type");
}
}
protected override TypeReference readInlineType(Instruction instr) {
return imageReader.readTypeReference();
}
protected override ExceptionHandler readExceptionHandler() {
var ehType = (ExceptionHandlerType)reader.ReadByte();
int tryOffset = imageReader.readVariableLengthInt32();
int tryLength = imageReader.readVariableLengthInt32();
int handlerOffset = imageReader.readVariableLengthInt32();
int handlerLength = imageReader.readVariableLengthInt32();
var catchType = imageReader.readTypeReference();
int filterOffset = imageReader.readVariableLengthInt32();
var eh = new ExceptionHandler(ehType);
eh.TryStart = getInstruction(tryOffset);
eh.TryEnd = getInstructionOrNull(tryOffset + tryLength);
if (ehType == ExceptionHandlerType.Filter)
eh.FilterStart = getInstruction(filterOffset);
eh.HandlerStart = getInstruction(handlerOffset);
eh.HandlerEnd = getInstructionOrNull(handlerOffset + handlerLength);
eh.CatchType = catchType;
return eh;
}
}
}

View File

@ -0,0 +1,240 @@
/*
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 Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
abstract class MethodBodyReaderBase {
protected BinaryReader reader;
public List<VariableDefinition> Locals { get; set; }
public Instruction[] Instructions { get; set; }
public ExceptionHandler[] ExceptionHandlers { get; set; }
protected ParameterDefinition[] parameters;
int currentOffset;
public MethodBodyReaderBase(BinaryReader reader) {
this.reader = reader;
}
protected void setLocals(IList<TypeReference> types) {
Locals = new List<VariableDefinition>(types.Count);
foreach (var type in types)
Locals.Add(new VariableDefinition(type));
}
protected void readInstructions(int numInstrs) {
Instructions = new Instruction[numInstrs];
currentOffset = 0;
for (int i = 0; i < Instructions.Length; i++) {
var instr = readInstruction();
Instructions[i] = instr;
if (instr.OpCode.Code == Code.Switch) {
int[] targets = (int[])instr.Operand;
currentOffset += instr.OpCode.Size + 4 + 4 * targets.Length;
}
else
currentOffset += Instructions[i].GetSize();
}
foreach (var instr in Instructions) {
switch (instr.OpCode.OperandType) {
case OperandType.InlineBrTarget:
case OperandType.ShortInlineBrTarget:
instr.Operand = getInstruction((int)instr.Operand);
break;
case OperandType.InlineSwitch:
var intTargets = (int[])instr.Operand;
var targets = new Instruction[intTargets.Length];
for (int i = 0; i < intTargets.Length; i++)
targets[i] = getInstruction(intTargets[i]);
instr.Operand = targets;
break;
}
}
}
protected Instruction getInstructionOrNull(int offset) {
foreach (var instr in Instructions) {
if (instr.Offset == offset)
return instr;
}
return null;
}
protected Instruction getInstruction(int offset) {
var instr = getInstructionOrNull(offset);
if (instr != null)
return instr;
throw new ApplicationException(string.Format("No instruction found at offset {0:X4}", offset));
}
Instruction readInstruction() {
int offset = currentOffset;
var opcode = readOpCode();
var instr = new Instruction {
OpCode = opcode,
Offset = offset,
};
instr.Operand = readOperand(instr);
return instr;
}
object readOperand(Instruction instr) {
switch (instr.OpCode.OperandType) {
case OperandType.InlineBrTarget:
return readInlineBrTarget(instr);
case OperandType.InlineField:
return readInlineField(instr);
case OperandType.InlineI:
return readInlineI(instr);
case OperandType.InlineI8:
return readInlineI8(instr);
case OperandType.InlineMethod:
return readInlineMethod(instr);
case OperandType.InlineNone:
return readInlineNone(instr);
case OperandType.InlinePhi:
return readInlinePhi(instr);
case OperandType.InlineR:
return readInlineR(instr);
case OperandType.InlineSig:
return readInlineSig(instr);
case OperandType.InlineString:
return readInlineString(instr);
case OperandType.InlineSwitch:
return readInlineSwitch(instr);
case OperandType.InlineTok:
return readInlineTok(instr);
case OperandType.InlineType:
return readInlineType(instr);
case OperandType.InlineVar:
return readInlineVar(instr);
case OperandType.InlineArg:
return readInlineArg(instr);
case OperandType.ShortInlineBrTarget:
return readShortInlineBrTarget(instr);
case OperandType.ShortInlineI:
return readShortInlineI(instr);
case OperandType.ShortInlineR:
return readShortInlineR(instr);
case OperandType.ShortInlineVar:
return readShortInlineVar(instr);
case OperandType.ShortInlineArg:
return readShortInlineArg(instr);
default:
throw new ApplicationException(string.Format("Unknown operand type {0}", instr.OpCode.OperandType));
}
}
protected virtual int readInlineBrTarget(Instruction instr) {
return currentOffset + instr.GetSize() + reader.ReadInt32();
}
protected abstract FieldReference readInlineField(Instruction instr);
protected virtual int readInlineI(Instruction instr) {
return reader.ReadInt32();
}
protected virtual long readInlineI8(Instruction instr) {
return reader.ReadInt64();
}
protected abstract MethodReference readInlineMethod(Instruction instr);
protected virtual object readInlineNone(Instruction instr) {
return null;
}
protected virtual object readInlinePhi(Instruction instr) {
return null;
}
protected virtual double readInlineR(Instruction instr) {
return reader.ReadDouble();
}
protected abstract CallSite readInlineSig(Instruction instr);
protected abstract string readInlineString(Instruction instr);
protected virtual int[] readInlineSwitch(Instruction instr) {
var targets = new int[reader.ReadInt32()];
int offset = currentOffset + instr.OpCode.Size + 4 + 4 * targets.Length;
for (int i = 0; i < targets.Length; i++)
targets[i] = offset + reader.ReadInt32();
return targets;
}
protected abstract MemberReference readInlineTok(Instruction instr);
protected abstract TypeReference readInlineType(Instruction instr);
protected virtual VariableDefinition readInlineVar(Instruction instr) {
return Locals[reader.ReadUInt16()];
}
protected virtual ParameterDefinition readInlineArg(Instruction instr) {
return parameters[reader.ReadUInt16()];
}
protected virtual int readShortInlineBrTarget(Instruction instr) {
return currentOffset + instr.GetSize() + reader.ReadSByte();
}
protected virtual object readShortInlineI(Instruction instr) {
if (instr.OpCode.Code == Code.Ldc_I4_S)
return reader.ReadSByte();
return reader.ReadByte();
}
protected virtual float readShortInlineR(Instruction instr) {
return reader.ReadSingle();
}
protected virtual VariableDefinition readShortInlineVar(Instruction instr) {
return Locals[reader.ReadByte()];
}
protected virtual ParameterDefinition readShortInlineArg(Instruction instr) {
return parameters[reader.ReadByte()];
}
OpCode readOpCode() {
var op = reader.ReadByte();
if (op != 0xFE)
return OpCodes.OneByteOpCode[op];
return OpCodes.TwoBytesOpCode[reader.ReadByte()];
}
protected void readExceptionHandlers(int numExceptionHandlers) {
ExceptionHandlers = new ExceptionHandler[numExceptionHandlers];
for (int i = 0; i < ExceptionHandlers.Length; i++)
ExceptionHandlers[i] = readExceptionHandler();
}
protected abstract ExceptionHandler readExceptionHandler();
}
}

View File

@ -0,0 +1,166 @@
/*
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 Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
namespace de4dot.code.deobfuscators.Babel_NET {
class BabelMethodreference : IGenericInstance {
public string Name { get; set; }
public TypeReference DeclaringType { get; set; }
public TypeReference ReturnType { get; set; }
public ParameterDefinition[] Parameters { get; set; }
public TypeReference[] GenericArguments { get; set; }
public int Flags { get; set; }
public bool HasThis {
get { return (Flags & 1) != 0; }
}
public bool IsGenericMethod {
get { return (Flags & 2) != 0; }
}
bool IGenericInstance.HasGenericArguments {
get { return IsGenericMethod; }
}
Collection<TypeReference> IGenericInstance.GenericArguments {
get { return new Collection<TypeReference>(GenericArguments); }
}
MetadataToken IMetadataTokenProvider.MetadataToken {
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
}
class BabelMethodDefinition : BabelMethodreference {
ParameterDefinition thisParameter;
public int Flags2 { get; set; }
public short MaxStack { get; set; }
public List<VariableDefinition> Locals { get; set; }
public Instruction[] Instructions { get; set; }
public ExceptionHandler[] ExceptionHandlers { get; set; }
public bool IsStatic {
get { return (Flags2 & 0x10) != 0; }
}
public bool RequiresFatExceptionHandler {
get { return (Flags2 & 0x20) != 0; }
}
public bool InitLocals {
get { return (Flags2 & 0x40) != 0; }
}
public bool CacheMethod {
get { return (Flags2 & 0x80) != 0; }
}
public ParameterDefinition ThisParameter {
get {
if (!HasThis)
return null;
if (thisParameter != null)
return thisParameter;
return thisParameter = new ParameterDefinition(DeclaringType);
}
}
public void setBody(MethodBodyReader mbr) {
Flags2 = mbr.Flags2;
MaxStack = mbr.MaxStack;
Locals = mbr.Locals;
Instructions = mbr.Instructions;
ExceptionHandlers = mbr.ExceptionHandlers;
}
public ParameterDefinition[] getRealParameters() {
if (ThisParameter == null)
return Parameters;
var parameters = new ParameterDefinition[Parameters.Length + 1];
parameters[0] = ThisParameter;
Array.Copy(Parameters, 0, parameters, 1, Parameters.Length);
return parameters;
}
}
class MethodReferenceReader {
ImageReader imageReader;
BinaryReader reader;
BabelMethodreference bmr;
public MethodReferenceReader(ImageReader imageReader, BinaryReader reader)
: this(imageReader, reader, new BabelMethodreference()) {
}
public MethodReferenceReader(ImageReader imageReader, BinaryReader reader, BabelMethodreference bmr) {
this.imageReader = imageReader;
this.reader = reader;
this.bmr = bmr;
}
public BabelMethodreference read() {
bmr.Name = imageReader.readString();
bmr.DeclaringType = imageReader.readTypeReference();
bmr.ReturnType = imageReader.readTypeReference();
bmr.Parameters = readParameters();
bmr.Flags = reader.ReadByte();
if (bmr.IsGenericMethod)
bmr.GenericArguments = imageReader.readTypeReferences();
else
bmr.GenericArguments = new TypeReference[0];
return bmr;
}
ParameterDefinition[] readParameters() {
var typeReferences = imageReader.readTypeReferences();
var parameters = new ParameterDefinition[typeReferences.Length];
for (int i = 0; i < parameters.Length; i++)
parameters[i] = new ParameterDefinition(typeReferences[i]);
return parameters;
}
}
class MethodDefinitionReader {
MethodReferenceReader methodReferenceReader;
MethodBodyReader methodBodyReader;
BabelMethodDefinition bmd;
public MethodDefinitionReader(ImageReader imageReader, BinaryReader reader) {
this.bmd = new BabelMethodDefinition();
this.methodReferenceReader = new MethodReferenceReader(imageReader, reader, bmd);
this.methodBodyReader = new MethodBodyReader(imageReader, reader);
}
public BabelMethodDefinition read() {
methodReferenceReader.read();
methodBodyReader.read(bmd.getRealParameters());
bmd.setBody(methodBodyReader);
return bmd;
}
}
}

View File

@ -0,0 +1,216 @@
/*
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 Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class MethodsDecrypter : IDisposable {
ModuleDefinition module;
Dictionary<string, ImageReader> imageReaders = new Dictionary<string, ImageReader>(StringComparer.Ordinal);
TypeDefinition methodsDecrypterCreator;
TypeDefinition methodsDecrypter;
MethodDefinition decryptExecuteMethod;
EmbeddedResource encryptedResource;
public bool Detected {
get { return methodsDecrypterCreator != null; }
}
public MethodsDecrypter(ModuleDefinition module) {
this.module = module;
}
public void Dispose() {
foreach (var imageReader in imageReaders.Values)
imageReader.Dispose();
}
public void find() {
var requiredFields = new string[] {
"System.Threading.ReaderWriterLock",
"System.Collections.Hashtable",
};
foreach (var type in module.GetTypes()) {
var fieldTypes = new FieldTypes(type);
if (!fieldTypes.all(requiredFields))
continue;
if (DotNetUtils.getMethod(type, "Finalize") == null)
continue;
var executeMethod = DotNetUtils.getMethod(type, "System.Object", "(System.String,System.Object[])");
if (executeMethod == null || !executeMethod.IsStatic || executeMethod.Body == null)
continue;
var decrypterType = findMethodsDecrypterType(type);
if (decrypterType == null)
continue;
methodsDecrypterCreator = type;
methodsDecrypter = decrypterType;
decryptExecuteMethod = executeMethod;
return;
}
}
TypeDefinition findMethodsDecrypterType(TypeDefinition type) {
foreach (var field in type.Fields) {
var fieldType = DotNetUtils.getType(module, field.FieldType);
if (fieldType == null)
continue;
if (DotNetUtils.getMethod(fieldType, "Finalize") == null)
continue;
if (!new FieldTypes(fieldType).exists("System.Collections.Hashtable"))
continue;
if (DotNetUtils.getMethod(fieldType, "System.String", "()") == null)
continue;
return fieldType;
}
return null;
}
public void initialize(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
if (methodsDecrypter == null)
return;
encryptedResource = findEncryptedResource(simpleDeobfuscator, deob);
if (encryptedResource == null) {
Log.w("Could not find encrypted methods resource");
return;
}
addImageReader("", new ResourceDecrypter(module).decrypt(encryptedResource.GetResourceData()));
}
void addImageReader(string name, byte[] data) {
var imageReader = new ImageReader(module, data);
if (!imageReader.initialize()) {
Log.w("Could not read encrypted methods");
return;
}
if (imageReaders.ContainsKey(name))
throw new ApplicationException(string.Format("ImageReader for name '{0}' already exists", name));
imageReaders[name] = imageReader;
}
EmbeddedResource findEncryptedResource(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
foreach (var method in methodsDecrypter.Methods) {
if (!DotNetUtils.isMethod(method, "System.String", "()"))
continue;
if (!method.IsStatic)
continue;
simpleDeobfuscator.deobfuscate(method);
simpleDeobfuscator.decryptStrings(method, deob);
foreach (var s in DotNetUtils.getCodeStrings(method)) {
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
if (resource != null)
return resource;
}
}
return null;
}
class EncryptInfo {
public string encryptedMethodName;
public string feature;
public MethodDefinition method;
public EncryptInfo(string encryptedMethodName, string feature, MethodDefinition method) {
this.encryptedMethodName = encryptedMethodName;
this.feature = feature;
this.method = method;
}
public override string ToString() {
if (feature != "")
return string.Format("{0}:{1} {2:X8}", feature, encryptedMethodName, method.MetadataToken.ToInt32());
else
return string.Format("{0} {1:X8}", encryptedMethodName, method.MetadataToken.ToInt32());
}
}
public void decrypt() {
int numNonDecryptedMethods = 0;
int totalEncryptedMethods = 0;
foreach (var info in getEncryptedMethods()) {
totalEncryptedMethods++;
ImageReader imageReader;
if (!imageReaders.TryGetValue(info.feature, out imageReader)) {
numNonDecryptedMethods++;
continue;
}
Log.v("Decrypting method {0:X8}", info.method.MetadataToken.ToInt32());
imageReader.restore(info.encryptedMethodName, info.method);
}
if (numNonDecryptedMethods > 0)
Log.w("{0}/{1} methods not decrypted", numNonDecryptedMethods, totalEncryptedMethods);
}
List<EncryptInfo> getEncryptedMethods() {
var infos = new List<EncryptInfo>();
foreach (var type in module.GetTypes()) {
foreach (var method in type.Methods) {
EncryptInfo info;
if (checkEncryptedMethod(method, out info))
infos.Add(info);
}
}
return infos;
}
bool checkEncryptedMethod(MethodDefinition method, out EncryptInfo info) {
info = null;
if (method.Body == null)
return false;
if (!callsExecuteMethod(method))
return false;
var strings = DotNetUtils.getCodeStrings(method);
if (strings.Count != 1)
throw new ApplicationException(string.Format("Could not find name of encrypted method"));
string feature = "";
string name = strings[0];
int index = name.IndexOf(':');
if (index >= 0) {
feature = name.Substring(0, index);
name = name.Substring(index + 1);
}
info = new EncryptInfo(name, feature, method);
return true;
}
bool callsExecuteMethod(MethodDefinition method) {
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
continue;
if (MemberReferenceHelper.compareMethodReferenceAndDeclaringType(decryptExecuteMethod, instr.Operand as MethodReference))
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,172 @@
/*
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 Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class ProxyDelegateFinder : ProxyDelegateFinderBase {
MethodDefinitionAndDeclaringTypeDict<ProxyCreatorType> methodToType = new MethodDefinitionAndDeclaringTypeDict<ProxyCreatorType>();
public ProxyDelegateFinder(ModuleDefinition module)
: base(module) {
}
enum ProxyCreatorType {
None,
CallOrCallvirt,
Newobj,
}
class Context {
public TypeReference delegateType;
public int methodToken;
public int declaringTypeToken;
public ProxyCreatorType proxyCreatorType;
public Context(TypeReference delegateType, int methodToken, int declaringTypeToken, ProxyCreatorType proxyCreatorType) {
this.delegateType = delegateType;
this.methodToken = methodToken;
this.declaringTypeToken = declaringTypeToken;
this.proxyCreatorType = proxyCreatorType;
}
}
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
var instructions = cctor.Body.Instructions;
for (int i = 0; i < instructions.Count; i++) {
TypeReference delegateType;
FieldReference delegateField;
MethodReference createMethod;
int methodToken, declaringTypeToken;
var instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Ldtoken, OpCodes.Ldc_I4, OpCodes.Ldc_I4, OpCodes.Ldtoken, OpCodes.Call);
if (instrs != null) {
delegateType = instrs[0].Operand as TypeReference;
methodToken = DotNetUtils.getLdcI4Value(instrs[1]);
declaringTypeToken = DotNetUtils.getLdcI4Value(instrs[2]);
delegateField = instrs[3].Operand as FieldReference;
createMethod = instrs[4].Operand as MethodReference;
}
else if ((instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Ldtoken, OpCodes.Ldc_I4, OpCodes.Ldtoken, OpCodes.Call)) != null) {
delegateType = instrs[0].Operand as TypeReference;
methodToken = DotNetUtils.getLdcI4Value(instrs[1]);
declaringTypeToken = -1;
delegateField = instrs[2].Operand as FieldReference;
createMethod = instrs[3].Operand as MethodReference;
}
else
continue;
if (delegateType == null)
continue;
if (delegateField == null)
continue;
if (createMethod == null)
continue;
var proxyCreatorType = methodToType.find(createMethod);
if (proxyCreatorType == ProxyCreatorType.None)
continue;
return new Context(delegateType, methodToken, declaringTypeToken, proxyCreatorType);
}
return null;
}
protected override void onFoundProxyDelegate(TypeDefinition type) {
foreach (var method in type.Methods) {
if (!method.IsStatic || !method.HasBody || method.Name == ".cctor")
continue;
var instructions = method.Body.Instructions;
for (int i = 0; i < instructions.Count; i++) {
var instr = instructions[i];
if (instr.OpCode.Code != Code.Ldsfld)
continue;
add(method, (FieldDefinition)instr.Operand);
break;
}
}
}
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
var ctx = (Context)context;
switch (ctx.proxyCreatorType) {
case ProxyCreatorType.CallOrCallvirt:
callOpcode = field.IsAssembly ? OpCodes.Callvirt : OpCodes.Call;
break;
case ProxyCreatorType.Newobj:
callOpcode = OpCodes.Newobj;
break;
default:
throw new ApplicationException(string.Format("Invalid proxy creator type: {0}", ctx.proxyCreatorType));
}
calledMethod = module.LookupToken(ctx.methodToken) as MethodReference;
}
public void findDelegateCreator() {
var requiredTypes = new string[] {
"System.ModuleHandle",
};
foreach (var type in module.Types) {
if (!new FieldTypes(type).exactly(requiredTypes))
continue;
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (!DotNetUtils.isMethod(method, "System.Void", "(System.RuntimeTypeHandle,System.Int32,System.RuntimeFieldHandle)") &&
!DotNetUtils.isMethod(method, "System.Void", "(System.RuntimeTypeHandle,System.Int32,System.Int32,System.RuntimeFieldHandle)"))
continue;
var creatorType = getProxyCreatorType(method);
if (creatorType == ProxyCreatorType.None)
continue;
methodToType.add(method, creatorType);
setDelegateCreatorMethod(method);
}
if (methodToType.Count == 0)
continue;
return;
}
}
ProxyCreatorType getProxyCreatorType(MethodDefinition methodToCheck) {
foreach (var info in DotNetUtils.getCalledMethods(module, methodToCheck)) {
var calledMethod = info.Item2;
if (!calledMethod.IsStatic || calledMethod.Body == null)
continue;
if (!MemberReferenceHelper.compareTypes(methodToCheck.DeclaringType, calledMethod.DeclaringType))
continue;
if (DotNetUtils.isMethod(calledMethod, "System.Void", "(System.Reflection.FieldInfo,System.Type,System.Reflection.MethodInfo)"))
return ProxyCreatorType.CallOrCallvirt;
if (DotNetUtils.isMethod(calledMethod, "System.Void", "(System.Reflection.FieldInfo,System.Type,System.Reflection.ConstructorInfo)"))
return ProxyCreatorType.Newobj;
}
return ProxyCreatorType.None;
}
}
}

View File

@ -0,0 +1,75 @@
/*
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.IO;
using Mono.Cecil;
namespace de4dot.code.deobfuscators.Babel_NET {
class ResourceDecrypter {
ModuleDefinition module;
public ResourceDecrypter(ModuleDefinition module) {
this.module = module;
}
public byte[] decrypt(byte[] encryptedData) {
int index = 0;
byte[] key, iv;
bool isCompressed = getKeyIv(getHeaderData(encryptedData, ref index), out key, out iv);
var data = DeobUtils.desDecrypt(encryptedData, index, encryptedData.Length - index, key, iv);
if (isCompressed)
data = DeobUtils.inflate(data, true);
return data;
}
byte[] getHeaderData(byte[] encryptedData, ref int index) {
bool xorDecrypt = encryptedData[index++] != 0;
var headerData = new byte[BitConverter.ToUInt16(encryptedData, index)];
Array.Copy(encryptedData, index + 2, headerData, 0, headerData.Length);
index += headerData.Length + 2;
if (!xorDecrypt)
return headerData;
var key = new byte[8];
Array.Copy(encryptedData, index, key, 0, key.Length);
index += key.Length;
for (int i = 0; i < headerData.Length; i++)
headerData[i] ^= key[i % key.Length];
return headerData;
}
bool getKeyIv(byte[] headerData, out byte[] key, out byte[] iv) {
var reader = new BinaryReader(new MemoryStream(headerData));
var license = reader.ReadString();
bool isCompressed = reader.ReadBoolean();
iv = reader.ReadBytes(reader.ReadByte());
bool hasEmbeddedKey = reader.ReadBoolean();
if (hasEmbeddedKey)
key = reader.ReadBytes(reader.ReadByte());
else {
key = new byte[reader.ReadByte()];
Array.Copy(module.Assembly.Name.PublicKey, 12, key, 0, key.Length);
key[5] |= 0x80;
}
return isCompressed;
}
}
}

View File

@ -0,0 +1,140 @@
/*
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.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class ResourceResolver {
ModuleDefinition module;
TypeDefinition resolverType;
MethodDefinition registerMethod;
EmbeddedResource encryptedResource;
public bool Detected {
get { return resolverType != null; }
}
public TypeDefinition Type {
get { return resolverType; }
}
public MethodDefinition InitMethod {
get { return registerMethod; }
}
public ResourceResolver(ModuleDefinition module) {
this.module = module;
}
public void find() {
var requiredTypes = new string[] {
"System.Reflection.Assembly",
"System.Object",
"System.Int32",
"System.String[]",
};
foreach (var type in module.Types) {
if (type.HasEvents)
continue;
if (!new FieldTypes(type).exactly(requiredTypes))
continue;
MethodDefinition regMethod, handler;
if (!findRegisterMethod(type, out regMethod, out handler))
continue;
var resource = findEmbeddedResource(type);
if (resource == null)
continue;
resolverType = type;
registerMethod = regMethod;
encryptedResource = resource;
return;
}
}
bool findRegisterMethod(TypeDefinition type, out MethodDefinition regMethod, out MethodDefinition handler) {
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (method.Body.ExceptionHandlers.Count != 1)
continue;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Ldftn)
continue;
var handlerRef = instr.Operand as MethodReference;
if (handlerRef == null)
continue;
if (!DotNetUtils.isMethod(handlerRef, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)"))
continue;
if (!MemberReferenceHelper.compareTypes(type, handlerRef.DeclaringType))
continue;
handler = DotNetUtils.getMethod(type, handlerRef);
if (handler == null)
continue;
if (handler.Body == null || handler.Body.ExceptionHandlers.Count != 1)
continue;
regMethod = method;
return true;
}
}
regMethod = null;
handler = null;
return false;
}
EmbeddedResource findEmbeddedResource(TypeDefinition type) {
foreach (var method in type.Methods) {
if (!DotNetUtils.isMethod(method, "System.String", "()"))
continue;
foreach (var s in DotNetUtils.getCodeStrings(method)) {
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
if (resource != null)
return resource;
}
}
return null;
}
public EmbeddedResource mergeResources() {
if (encryptedResource == null)
return null;
DeobUtils.decryptAndAddResources(module, encryptedResource.Name, () => decryptResourceAssembly());
var result = encryptedResource;
encryptedResource = null;
return result;
}
byte[] decryptResourceAssembly() {
var decrypted = new ResourceDecrypter(module).decrypt(encryptedResource.GetResourceData());
var reader = new BinaryReader(new MemoryStream(decrypted));
int numResources = reader.ReadInt32();
for (int i = 0; i < numResources; i++)
reader.ReadString();
return reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
}
}
}

View File

@ -0,0 +1,122 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using System.IO;
using Mono.Cecil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Babel_NET {
class StringDecrypter {
ModuleDefinition module;
Dictionary<int, string> offsetToString = new Dictionary<int, string>();
TypeDefinition decrypterType;
MethodDefinition decryptMethod;
EmbeddedResource encryptedResource;
public bool Detected {
get { return decrypterType != null; }
}
public TypeDefinition Type {
get { return decrypterType; }
}
public MethodDefinition DecryptMethod {
get { return decryptMethod; }
}
public EmbeddedResource Resource {
get { return encryptedResource; }
}
public StringDecrypter(ModuleDefinition module) {
this.module = module;
}
public void find() {
foreach (var type in module.Types) {
if (!isDecrypterType(type))
continue;
var method = DotNetUtils.getMethod(type, "System.String", "(System.Int32)");
if (method == null)
continue;
decrypterType = type;
decryptMethod = method;
return;
}
}
bool isDecrypterType(TypeDefinition type) {
if (type.HasEvents)
return false;
if (type.NestedTypes.Count != 1)
return false;
if (type.Fields.Count != 0)
return false;
var nested = type.NestedTypes[0];
if (nested.HasProperties || nested.HasEvents)
return false;
if (nested.Fields.Count != 1)
return false;
if (!MemberReferenceHelper.compareTypes(nested.Fields[0].FieldType, nested))
return false;
if (DotNetUtils.getMethod(nested, "System.Reflection.Emit.MethodBuilder", "(System.Reflection.Emit.TypeBuilder)") == null)
return false;
if (DotNetUtils.getMethod(nested, "System.String", "(System.Int32)") == null)
return false;
return true;
}
public void initialize() {
if (decrypterType == null)
return;
if (encryptedResource != null)
return;
encryptedResource = findResource();
if (encryptedResource == null)
return;
var decrypted = new ResourceDecrypter(module).decrypt(encryptedResource.GetResourceData());
var reader = new BinaryReader(new MemoryStream(decrypted));
while (reader.BaseStream.Position < reader.BaseStream.Length)
offsetToString[(int)reader.BaseStream.Position] = reader.ReadString();
}
EmbeddedResource findResource() {
foreach (var method in decrypterType.Methods) {
foreach (var s in DotNetUtils.getCodeStrings(method)) {
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
if (resource != null)
return resource;
}
}
return null;
}
public string decrypt(int offset) {
return offsetToString[offset];
}
}
}

View File

@ -30,6 +30,7 @@ namespace de4dot.cui {
static IList<IDeobfuscatorInfo> createDeobfuscatorInfos() {
return new List<IDeobfuscatorInfo> {
new de4dot.code.deobfuscators.Unknown.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Babel_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CliSecure.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CryptoObfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Dotfuscator.DeobfuscatorInfo(),