diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index f1f330ca..770269c1 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -67,6 +67,8 @@
+
+
@@ -167,6 +169,8 @@
+
+
diff --git a/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs b/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs
new file mode 100644
index 00000000..1712e339
--- /dev/null
+++ b/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs
@@ -0,0 +1,124 @@
+/*
+ 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 .
+*/
+
+using System;
+using System.Collections.Generic;
+using Mono.Cecil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.ILProtector {
+ public class DeobfuscatorInfo : DeobfuscatorInfoBase {
+ public const string THE_NAME = "ILProtector";
+ public const string THE_TYPE = "il";
+
+ public DeobfuscatorInfo()
+ : base() {
+ }
+
+ 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(),
+ });
+ }
+
+ protected override IEnumerable getOptionsInternal() {
+ return new List () {
+ };
+ }
+ }
+
+ class Deobfuscator : DeobfuscatorBase {
+ Options options;
+ string obfuscatorName = DeobfuscatorInfo.THE_NAME;
+
+ MainType mainType;
+ MethodsDecrypter methodsDecrypter;
+
+ internal class Options : OptionsBase {
+ }
+
+ public override string Type {
+ get { return DeobfuscatorInfo.THE_TYPE; }
+ }
+
+ public override string TypeLong {
+ get { return DeobfuscatorInfo.THE_NAME; }
+ }
+
+ public override string Name {
+ get { return obfuscatorName; }
+ }
+
+ public Deobfuscator(Options options)
+ : base(options) {
+ this.options = options;
+ }
+
+ protected override int detectInternal() {
+ return mainType.Detected ? 150 : 0;
+ }
+
+ protected override void scanForObfuscator() {
+ mainType = new MainType(module);
+ mainType.find();
+ methodsDecrypter = new MethodsDecrypter(module, mainType);
+ methodsDecrypter.find();
+
+ if (mainType.Detected && methodsDecrypter.Detected && methodsDecrypter.Version != null)
+ obfuscatorName += " " + getVersion(methodsDecrypter.Version);
+ }
+
+ static string getVersion(Version version) {
+ if (version.Revision == 0)
+ return string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
+ return version.ToString();
+ }
+
+ public override void deobfuscateBegin() {
+ base.deobfuscateBegin();
+
+ methodsDecrypter.decrypt();
+ addTypesToBeRemoved(methodsDecrypter.DelegateTypes, "Obfuscator method delegate type");
+ addResourceToBeRemoved(methodsDecrypter.Resource, "Encrypted methods resource");
+ addTypeToBeRemoved(mainType.InvokerDelegate, "Invoker delegate type");
+ addFieldToBeRemoved(mainType.InvokerInstanceField, "Invoker delegate instance field");
+ foreach (var pm in mainType.ProtectMethods) {
+ addMethodToBeRemoved(pm, "Obfuscator 'Protect' init method");
+ addModuleReferenceToBeRemoved(pm.PInvokeInfo.Module, "Obfuscator native protection file");
+ }
+ mainType.cleanUp();
+ }
+
+ public override void deobfuscateEnd() {
+ base.deobfuscateEnd();
+ }
+
+ public override IEnumerable getStringDecrypterMethods() {
+ return new List();
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/ILProtector/MainType.cs b/de4dot.code/deobfuscators/ILProtector/MainType.cs
new file mode 100644
index 00000000..70a8724c
--- /dev/null
+++ b/de4dot.code/deobfuscators/ILProtector/MainType.cs
@@ -0,0 +1,107 @@
+/*
+ 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 .
+*/
+
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.ILProtector {
+ class MainType {
+ ModuleDefinition module;
+ List protectMethods;
+ TypeDefinition invokerDelegate;
+ FieldDefinition invokerInstanceField;
+
+ public IEnumerable ProtectMethods {
+ get { return protectMethods; }
+ }
+
+ public TypeDefinition InvokerDelegate {
+ get { return invokerDelegate; }
+ }
+
+ public FieldDefinition InvokerInstanceField {
+ get { return invokerInstanceField; }
+ }
+
+ public bool Detected {
+ get { return protectMethods != null; }
+ }
+
+ public MainType(ModuleDefinition module) {
+ this.module = module;
+ }
+
+ public void find() {
+ checkMethod(DotNetUtils.getModuleTypeCctor(module));
+ }
+
+ static string[] ilpLocals = new string[] {
+ "System.Boolean",
+ "System.IntPtr",
+ "System.Object[]",
+ };
+ bool checkMethod(MethodDefinition cctor) {
+ if (cctor == null || cctor.Body == null)
+ return false;
+ if (!new LocalTypes(cctor).exactly(ilpLocals))
+ return false;
+
+ var type = cctor.DeclaringType;
+ var methods = getPinvokeMethods(type, "Protect");
+ if (methods.Count == 0)
+ methods = getPinvokeMethods(type, "P0");
+ if (methods.Count != 2)
+ return false;
+ if (type.Fields.Count != 1)
+ return false;
+
+ var theField = type.Fields[0];
+ var theDelegate = theField.FieldType as TypeDefinition;
+ if (theDelegate == null || !DotNetUtils.derivesFromDelegate(theDelegate))
+ return false;
+
+ protectMethods = methods;
+ invokerDelegate = theDelegate;
+ invokerInstanceField = theField;
+ return true;
+ }
+
+ List getPinvokeMethods(TypeDefinition type, string name) {
+ var list = new List();
+ foreach (var method in type.Methods) {
+ if (method.PInvokeInfo != null && method.PInvokeInfo.EntryPoint == name)
+ list.Add(method);
+ }
+ return list;
+ }
+
+ public void cleanUp() {
+ var cctor = DotNetUtils.getModuleTypeCctor(module);
+ if (cctor != null) {
+ cctor.Body.InitLocals = false;
+ cctor.Body.Variables.Clear();
+ cctor.Body.Instructions.Clear();
+ cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
+ cctor.Body.ExceptionHandlers.Clear();
+ }
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/ILProtector/MethodReader.cs b/de4dot.code/deobfuscators/ILProtector/MethodReader.cs
new file mode 100644
index 00000000..d812c5a2
--- /dev/null
+++ b/de4dot.code/deobfuscators/ILProtector/MethodReader.cs
@@ -0,0 +1,220 @@
+/*
+ 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 .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.ILProtector {
+ class MethodReader : MethodBodyReaderBase {
+ ModuleDefinition module;
+ MethodFlags flags;
+ TypeDefinition delegateType;
+
+ [Flags]
+ enum MethodFlags {
+ InitLocals = 1,
+ HasLocals = 2,
+ HasInstructions = 4,
+ HasExceptionHandlers = 8,
+ }
+
+ public TypeDefinition DelegateType {
+ get { return delegateType; }
+ }
+
+ public bool InitLocals {
+ get { return (flags & MethodFlags.InitLocals) != 0; }
+ }
+
+ bool HasLocals {
+ get { return (flags & MethodFlags.HasLocals) != 0; }
+ }
+
+ bool HasInstructions {
+ get { return (flags & MethodFlags.HasInstructions) != 0; }
+ }
+
+ bool HasExceptionHandlers {
+ get { return (flags & MethodFlags.HasExceptionHandlers) != 0; }
+ }
+
+ public MethodReader(ModuleDefinition module, byte[] data, IList parameters)
+ : base(new BinaryReader(new MemoryStream(data))) {
+ this.module = module;
+ this.parameters = parameters;
+ }
+
+ public void read() {
+ flags = (MethodFlags)reader.ReadByte();
+ delegateType = resolve(readTypeToken());
+ if (!DotNetUtils.derivesFromDelegate(delegateType))
+ throw new ApplicationException("Invalid delegate type");
+ if (HasLocals)
+ readLocals(Utils.readEncodedInt32(reader));
+ if (HasInstructions)
+ readInstructions(Utils.readEncodedInt32(reader));
+ if (HasExceptionHandlers)
+ readExceptionHandlers(Utils.readEncodedInt32(reader));
+ }
+
+ int getTypeDefOrRefToken(uint token) {
+ switch (token & 3) {
+ case 0: return 0x02000000 + (int)(token >> 2);
+ case 1: return 0x01000000 + (int)(token >> 2);
+ case 2: return 0x1B000000 + (int)(token >> 2);
+ default: throw new ApplicationException("Invalid token");
+ }
+ }
+
+ void readLocals(int numLocals) {
+ var localsTypes = new List();
+ for (int i = 0; i < numLocals; i++)
+ localsTypes.Add(readType());
+ setLocals(localsTypes);
+ }
+
+ T resolve(int token) {
+ return (T)module.LookupToken(token);
+ }
+
+ int readTypeToken() {
+ return getTypeDefOrRefToken(Utils.readEncodedUInt32(reader));
+ }
+
+ TypeReference readType() {
+ TypeReference elementType;
+ switch ((ElementType)reader.ReadByte()) {
+ case ElementType.Void: return module.TypeSystem.Void;
+ case ElementType.Boolean: return module.TypeSystem.Boolean;
+ case ElementType.Char: return module.TypeSystem.Char;
+ case ElementType.I1: return module.TypeSystem.SByte;
+ case ElementType.U1: return module.TypeSystem.Byte;
+ case ElementType.I2: return module.TypeSystem.Int16;
+ case ElementType.U2: return module.TypeSystem.UInt16;
+ case ElementType.I4: return module.TypeSystem.Int32;
+ case ElementType.U4: return module.TypeSystem.UInt32;
+ case ElementType.I8: return module.TypeSystem.Int64;
+ case ElementType.U8: return module.TypeSystem.UInt64;
+ case ElementType.R4: return module.TypeSystem.Single;
+ case ElementType.R8: return module.TypeSystem.Double;
+ case ElementType.String: return module.TypeSystem.String;
+ case ElementType.Ptr: return new PointerType(readType());
+ case ElementType.ByRef: return new ByReferenceType(readType());
+ case ElementType.TypedByRef: return module.TypeSystem.TypedReference;
+ case ElementType.I: return module.TypeSystem.IntPtr;
+ case ElementType.U: return module.TypeSystem.UIntPtr;
+ case ElementType.Object: return module.TypeSystem.Object;
+ case ElementType.SzArray: return new ArrayType(readType());
+ case ElementType.Sentinel: return readType();
+ case ElementType.Pinned: return new PinnedType(readType());
+
+ case ElementType.ValueType:
+ case ElementType.Class:
+ return resolve(readTypeToken());
+
+ case ElementType.Array:
+ elementType = readType();
+ int rank = Utils.readEncodedInt32(reader);
+ return new ArrayType(elementType, rank);
+
+ case ElementType.GenericInst:
+ reader.ReadByte();
+ elementType = resolve(readTypeToken());
+ int numGenericArgs = Utils.readEncodedInt32(reader);
+ var git = new GenericInstanceType(elementType);
+ for (int i = 0; i < numGenericArgs; i++)
+ git.GenericArguments.Add(readType());
+ return git;
+
+ case ElementType.None:
+ case ElementType.Var:
+ case ElementType.MVar:
+ case ElementType.FnPtr:
+ case ElementType.CModReqD:
+ case ElementType.CModOpt:
+ case ElementType.Internal:
+ case ElementType.Modifier:
+ case ElementType.Type:
+ case ElementType.Boxed:
+ case ElementType.Enum:
+ default:
+ throw new ApplicationException("Invalid local element type");
+ }
+ }
+
+ protected override FieldReference readInlineField(Instruction instr) {
+ return resolve(reader.ReadInt32());
+ }
+
+ protected override MethodReference readInlineMethod(Instruction instr) {
+ return resolve(reader.ReadInt32());
+ }
+
+ protected override CallSite readInlineSig(Instruction instr) {
+ throw new NotImplementedException(); //TODO:
+ }
+
+ protected override string readInlineString(Instruction instr) {
+ return module.GetUserString(reader.ReadUInt32() & 0x00FFFFFF);
+ }
+
+ protected override MemberReference readInlineTok(Instruction instr) {
+ return resolve(reader.ReadInt32());
+ }
+
+ protected override TypeReference readInlineType(Instruction instr) {
+ return resolve(reader.ReadInt32());
+ }
+
+ protected override ExceptionHandler readExceptionHandler() {
+ var eh = new ExceptionHandler((ExceptionHandlerType)(Utils.readEncodedInt32(reader) & 7));
+
+ int tryOffset = Utils.readEncodedInt32(reader);
+ eh.TryStart = getInstruction(tryOffset);
+ eh.TryEnd = getInstructionOrNull(tryOffset + Utils.readEncodedInt32(reader));
+
+ int handlerOffset = Utils.readEncodedInt32(reader);
+ eh.HandlerStart = getInstruction(handlerOffset);
+ eh.HandlerEnd = getInstructionOrNull(handlerOffset + Utils.readEncodedInt32(reader));
+
+ switch (eh.HandlerType) {
+ case ExceptionHandlerType.Catch:
+ eh.CatchType = resolve(reader.ReadInt32());
+ break;
+
+ case ExceptionHandlerType.Filter:
+ eh.FilterStart = getInstruction(reader.ReadInt32());
+ break;
+
+ case ExceptionHandlerType.Finally:
+ case ExceptionHandlerType.Fault:
+ default:
+ reader.ReadInt32();
+ break;
+ }
+
+ return eh;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/ILProtector/MethodsDecrypter.cs b/de4dot.code/deobfuscators/ILProtector/MethodsDecrypter.cs
new file mode 100644
index 00000000..087d34a8
--- /dev/null
+++ b/de4dot.code/deobfuscators/ILProtector/MethodsDecrypter.cs
@@ -0,0 +1,263 @@
+/*
+ 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 .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.ILProtector {
+ class MethodsDecrypter {
+ public static readonly byte[] ilpPublicKeyToken = new byte[8] { 0x20, 0x12, 0xD3, 0xC0, 0x55, 0x1F, 0xE0, 0x3D };
+
+ // This is the first four bytes of ILProtector's public key token
+ const uint RESOURCE_MAGIC = 0xC0D31220;
+
+ ModuleDefinition module;
+ MainType mainType;
+ EmbeddedResource methodsResource;
+ Version ilpVersion;
+ Dictionary methodInfos = new Dictionary();
+ List delegateTypes = new List();
+
+ class MethodInfo2 {
+ public int id;
+ public int offset;
+ public byte[] data;
+ public MethodInfo2(int id, int offset, int size) {
+ this.id = id;
+ this.offset = offset;
+ this.data = new byte[size];
+ }
+
+ public override string ToString() {
+ return string.Format("{0} {1:X8} 0x{2:X}", id, offset, data.Length);
+ }
+ }
+
+ public EmbeddedResource Resource {
+ get { return methodsResource; }
+ }
+
+ public IEnumerable DelegateTypes {
+ get { return delegateTypes; }
+ }
+
+ public Version Version {
+ get { return ilpVersion; }
+ }
+
+ public bool Detected {
+ get { return methodsResource != null; }
+ }
+
+ public MethodsDecrypter(ModuleDefinition module, MainType mainType) {
+ this.module = module;
+ this.mainType = mainType;
+ }
+
+ public void find() {
+ foreach (var tmp in module.Resources) {
+ var resource = tmp as EmbeddedResource;
+ if (resource == null)
+ continue;
+ var reader = new BinaryReader(resource.GetResourceStream());
+ if (reader.BaseStream.Length < 8)
+ continue;
+ if (reader.ReadUInt32() != RESOURCE_MAGIC)
+ continue;
+ var version = new Version(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
+
+ methodsResource = resource;
+ ilpVersion = version;
+ break;
+ }
+ }
+
+ public void decrypt() {
+ if (methodsResource == null)
+ return;
+
+ foreach (var info in readMethodInfos(getMethodsData(methodsResource)))
+ methodInfos[info.id] = info;
+
+ restoreMethods();
+ }
+
+ static byte[] getMethodsData(EmbeddedResource resource) {
+ var reader = new BinaryReader(resource.GetResourceStream());
+ reader.BaseStream.Position += 8;
+ if ((reader.ReadInt32() & 1) != 0)
+ return decompress(reader);
+ else
+ return reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
+ }
+
+ static byte[] decompress(BinaryReader reader) {
+ return decompress(reader, ilpPublicKeyToken);
+ }
+
+ static void copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int size) {
+ for (int i = 0; i < size; i++)
+ dst[dstIndex++] = src[srcIndex++];
+ }
+
+ static byte[] decompress(BinaryReader reader, byte[] key) {
+ var decrypted = new byte[Utils.readEncodedInt32(reader)];
+
+ int destIndex = 0;
+ while (reader.BaseStream.Position < reader.BaseStream.Length) {
+ byte flags = reader.ReadByte();
+ for (int mask = 1; mask != 0x100; mask <<= 1) {
+ if (reader.BaseStream.Position >= reader.BaseStream.Length)
+ break;
+ if ((flags & mask) != 0) {
+ int displ = Utils.readEncodedInt32(reader);
+ int size = Utils.readEncodedInt32(reader);
+ copy(decrypted, destIndex - displ, decrypted, destIndex, size);
+ destIndex += size;
+ }
+ else {
+ byte b = reader.ReadByte();
+ if (key != null)
+ b ^= key[destIndex & 7];
+ decrypted[destIndex++] = b;
+ }
+ }
+ }
+
+ return decrypted;
+ }
+
+ static MethodInfo2[] readMethodInfos(byte[] data) {
+ var reader = new BinaryReader(new MemoryStream(data));
+ int numMethods = Utils.readEncodedInt32(reader);
+ int totalCodeSize = Utils.readEncodedInt32(reader);
+ var methodInfos = new MethodInfo2[numMethods];
+ int offset = 0;
+ for (int i = 0; i < numMethods; i++) {
+ int id = Utils.readEncodedInt32(reader);
+ int size = Utils.readEncodedInt32(reader);
+ methodInfos[i] = new MethodInfo2(id, offset, size);
+ offset += size;
+ }
+ long dataOffset = reader.BaseStream.Position;
+ foreach (var info in methodInfos) {
+ reader.BaseStream.Position = dataOffset + info.offset;
+ reader.BaseStream.Read(info.data, 0, info.data.Length);
+ }
+ return methodInfos;
+ }
+
+ void restoreMethods() {
+ if (methodInfos.Count == 0)
+ return;
+
+ Log.v("Restoring {0} methods", methodInfos.Count);
+ Log.indent();
+ foreach (var type in module.GetTypes()) {
+ foreach (var method in type.Methods) {
+ if (method.Body == null)
+ continue;
+
+ if (restoreMethod(method)) {
+ Log.v("Restored method {0:X8} ({1}). Instrs:{2}, Locals:{3}, Exceptions:{4}",
+ method.MetadataToken.ToInt32(),
+ Utils.removeNewlines(method.FullName),
+ method.Body.Instructions.Count,
+ method.Body.Variables.Count,
+ method.Body.ExceptionHandlers.Count);
+ }
+ }
+ }
+ Log.deIndent();
+ if (methodInfos.Count != 0)
+ Log.w("{0} methods weren't restored", methodInfos.Count);
+ }
+
+ const int INVALID_METHOD_ID = -1;
+ bool restoreMethod(MethodDefinition method) {
+ int methodId = getMethodId(method);
+ if (methodId == INVALID_METHOD_ID)
+ return false;
+
+ var parameters = DotNetUtils.getParameters(method);
+ var methodInfo = methodInfos[methodId];
+ methodInfos.Remove(methodId);
+ var methodReader = new MethodReader(module, methodInfo.data, parameters);
+ methodReader.read();
+
+ restoreMethod(method, methodReader);
+ delegateTypes.Add(methodReader.DelegateType);
+
+ return true;
+ }
+
+ static void restoreMethod(MethodDefinition method, MethodReader methodReader) {
+ var body = method.Body;
+
+ // body.MaxStackSize =
+ body.InitLocals = methodReader.InitLocals;
+
+ body.Variables.Clear();
+ if (methodReader.Locals != null) {
+ foreach (var local in methodReader.Locals)
+ body.Variables.Add(local);
+ }
+
+ body.Instructions.Clear();
+ if (methodReader.Instructions != null) {
+ foreach (var instr in methodReader.Instructions)
+ body.Instructions.Add(instr);
+ }
+
+ body.ExceptionHandlers.Clear();
+ if (methodReader.ExceptionHandlers != null) {
+ foreach (var eh in methodReader.ExceptionHandlers)
+ body.ExceptionHandlers.Add(eh);
+ }
+ }
+
+ int getMethodId(MethodDefinition method) {
+ if (method == null || method.Body == null)
+ return INVALID_METHOD_ID;
+
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 1; i++) {
+ var ldsfld = instrs[i];
+ if (ldsfld.OpCode.Code != Code.Ldsfld)
+ continue;
+
+ var ldci4 = instrs[i + 1];
+ if (!DotNetUtils.isLdcI4(ldci4))
+ continue;
+
+ var field = ldsfld.Operand as FieldDefinition;
+ if (field == null || field != mainType.InvokerInstanceField)
+ continue;
+
+ return DotNetUtils.getLdcI4Value(ldci4);
+ }
+
+ return INVALID_METHOD_ID;
+ }
+ }
+}
diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs
index a3a5f5ac..4c3bbe95 100644
--- a/de4dot.cui/Program.cs
+++ b/de4dot.cui/Program.cs
@@ -47,6 +47,7 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.dotNET_Reactor.v4.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Eazfuscator_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
+ new de4dot.code.deobfuscators.ILProtector.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MaxtoCode.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),