diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index e8045c41..c09a92d9 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -58,6 +58,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/de4dot.code/deobfuscators/Babel_NET/ConstantsDecrypter.cs b/de4dot.code/deobfuscators/Babel_NET/ConstantsDecrypter.cs
new file mode 100644
index 00000000..cb6f9f12
--- /dev/null
+++ b/de4dot.code/deobfuscators/Babel_NET/ConstantsDecrypter.cs
@@ -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 .
+*/
+
+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();
+ 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;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs
new file mode 100644
index 00000000..1c68361c
--- /dev/null
+++ b/de4dot.code/deobfuscators/Babel_NET/Deobfuscator.cs
@@ -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 .
+*/
+
+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