Support ILProtector 1.0.7.1 - 2.0.11.0
This commit is contained in:
parent
83e3cc0f57
commit
2cc12006aa
|
@ -160,6 +160,11 @@
|
||||||
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
|
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
|
||||||
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.cs" />
|
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.cs" />
|
||||||
<Compile Include="deobfuscators\Eazfuscator_NET\Dynocode.cs" />
|
<Compile Include="deobfuscators\Eazfuscator_NET\Dynocode.cs" />
|
||||||
|
<Compile Include="deobfuscators\ILProtector\DecryptedMethodInfo.cs" />
|
||||||
|
<Compile Include="deobfuscators\ILProtector\DynamicMethodsDecrypter.cs" />
|
||||||
|
<Compile Include="deobfuscators\ILProtector\DynamicMethodsDecrypterService.cs" />
|
||||||
|
<Compile Include="deobfuscators\ILProtector\DynamicMethodsRestorer.cs" />
|
||||||
|
<Compile Include="deobfuscators\ILProtector\MethodsDecrypterBase.cs" />
|
||||||
<Compile Include="deobfuscators\MyPEImage.cs" />
|
<Compile Include="deobfuscators\MyPEImage.cs" />
|
||||||
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />
|
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />
|
||||||
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
|
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
|
||||||
|
@ -211,7 +216,7 @@
|
||||||
<Compile Include="deobfuscators\ILProtector\Deobfuscator.cs" />
|
<Compile Include="deobfuscators\ILProtector\Deobfuscator.cs" />
|
||||||
<Compile Include="deobfuscators\ILProtector\MainType.cs" />
|
<Compile Include="deobfuscators\ILProtector\MainType.cs" />
|
||||||
<Compile Include="deobfuscators\ILProtector\MethodReader.cs" />
|
<Compile Include="deobfuscators\ILProtector\MethodReader.cs" />
|
||||||
<Compile Include="deobfuscators\ILProtector\MethodsDecrypter.cs" />
|
<Compile Include="deobfuscators\ILProtector\StaticMethodsDecrypter.cs" />
|
||||||
<Compile Include="deobfuscators\InitializedDataCreator.cs" />
|
<Compile Include="deobfuscators\InitializedDataCreator.cs" />
|
||||||
<Compile Include="deobfuscators\InlinedMethodsFinder.cs" />
|
<Compile Include="deobfuscators\InlinedMethodsFinder.cs" />
|
||||||
<Compile Include="deobfuscators\ISimpleDeobfuscator.cs" />
|
<Compile Include="deobfuscators\ISimpleDeobfuscator.cs" />
|
||||||
|
|
42
de4dot.code/deobfuscators/ILProtector/DecryptedMethodInfo.cs
Normal file
42
de4dot.code/deobfuscators/ILProtector/DecryptedMethodInfo.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 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;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
|
[Serializable]
|
||||||
|
class DecryptedMethodInfo {
|
||||||
|
public int id;
|
||||||
|
public byte[] data;
|
||||||
|
|
||||||
|
public DecryptedMethodInfo(int id, int size) {
|
||||||
|
this.id = id;
|
||||||
|
this.data = new byte[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecryptedMethodInfo(int id, byte[] data) {
|
||||||
|
this.id = id;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return string.Format("ID: {0}, Size: 0x{1:X}", id, data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,7 +56,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
|
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
|
||||||
|
|
||||||
MainType mainType;
|
MainType mainType;
|
||||||
MethodsDecrypter methodsDecrypter;
|
StaticMethodsDecrypter staticMethodsDecrypter;
|
||||||
|
DynamicMethodsRestorer dynamicMethodsRestorer;
|
||||||
|
|
||||||
internal class Options : OptionsBase {
|
internal class Options : OptionsBase {
|
||||||
}
|
}
|
||||||
|
@ -85,20 +86,36 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
protected override void ScanForObfuscator() {
|
protected override void ScanForObfuscator() {
|
||||||
mainType = new MainType(module);
|
mainType = new MainType(module);
|
||||||
mainType.Find();
|
mainType.Find();
|
||||||
methodsDecrypter = new MethodsDecrypter(module, mainType);
|
|
||||||
if (mainType.Detected)
|
|
||||||
methodsDecrypter.Find();
|
|
||||||
|
|
||||||
if (mainType.Detected && methodsDecrypter.Detected && methodsDecrypter.Version != null)
|
staticMethodsDecrypter = new StaticMethodsDecrypter(module, mainType);
|
||||||
obfuscatorName += " " + methodsDecrypter.Version;
|
if (mainType.Detected)
|
||||||
|
staticMethodsDecrypter.Find();
|
||||||
|
|
||||||
|
if (mainType.Detected && !staticMethodsDecrypter.Detected)
|
||||||
|
dynamicMethodsRestorer = new DynamicMethodsRestorer(module, mainType);
|
||||||
|
|
||||||
|
if (mainType.Detected && staticMethodsDecrypter.Detected && staticMethodsDecrypter.Version != null)
|
||||||
|
obfuscatorName += " " + staticMethodsDecrypter.Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DeobfuscateBegin() {
|
public override void DeobfuscateBegin() {
|
||||||
base.DeobfuscateBegin();
|
base.DeobfuscateBegin();
|
||||||
|
|
||||||
if (mainType.Detected) {
|
if (mainType.Detected) {
|
||||||
if (methodsDecrypter.Detected) {
|
if (staticMethodsDecrypter.Detected) {
|
||||||
methodsDecrypter.Decrypt();
|
staticMethodsDecrypter.Decrypt();
|
||||||
|
RemoveObfuscatorJunk(staticMethodsDecrypter);
|
||||||
|
}
|
||||||
|
else if (dynamicMethodsRestorer != null) {
|
||||||
|
dynamicMethodsRestorer.Decrypt();
|
||||||
|
RemoveObfuscatorJunk(dynamicMethodsRestorer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Logger.w("New ILProtector version. Can't decrypt methods (yet)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveObfuscatorJunk(MethodsDecrypterBase methodsDecrypter) {
|
||||||
AddTypesToBeRemoved(methodsDecrypter.DelegateTypes, "Obfuscator method delegate type");
|
AddTypesToBeRemoved(methodsDecrypter.DelegateTypes, "Obfuscator method delegate type");
|
||||||
AddResourceToBeRemoved(methodsDecrypter.Resource, "Encrypted methods resource");
|
AddResourceToBeRemoved(methodsDecrypter.Resource, "Encrypted methods resource");
|
||||||
AddTypeToBeRemoved(mainType.InvokerDelegate, "Invoker delegate type");
|
AddTypeToBeRemoved(mainType.InvokerDelegate, "Invoker delegate type");
|
||||||
|
@ -107,10 +124,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
AddMethodToBeRemoved(pm, "Obfuscator 'Protect' init method");
|
AddMethodToBeRemoved(pm, "Obfuscator 'Protect' init method");
|
||||||
mainType.CleanUp();
|
mainType.CleanUp();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Logger.w("New ILProtector version. Can't decrypt methods (yet)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<int> GetStringDecrypterMethods() {
|
public override IEnumerable<int> GetStringDecrypterMethods() {
|
||||||
return new List<int>();
|
return new List<int>();
|
||||||
|
|
490
de4dot.code/deobfuscators/ILProtector/DynamicMethodsDecrypter.cs
Normal file
490
de4dot.code/deobfuscators/ILProtector/DynamicMethodsDecrypter.cs
Normal file
|
@ -0,0 +1,490 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 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.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using de4dot.blocks;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
|
sealed class DynamicMethodsDecrypter : IDisposable {
|
||||||
|
ModuleDefMD module;
|
||||||
|
Module reflectionModule;
|
||||||
|
Module reflectionProtectModule;
|
||||||
|
TypeDef protectMainType;
|
||||||
|
Type reflectionProtectMainType;
|
||||||
|
FieldInfo invokerFieldInfo;
|
||||||
|
ModuleDefMD moduleProtect;
|
||||||
|
IDecrypter decrypter;
|
||||||
|
|
||||||
|
interface IDecrypter {
|
||||||
|
byte[] Decrypt(int methodId, uint rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class DecrypterBase : IDecrypter {
|
||||||
|
protected readonly DynamicMethodsDecrypter dmd;
|
||||||
|
protected readonly int appDomainId;
|
||||||
|
protected readonly int asmHashCode;
|
||||||
|
|
||||||
|
class PatchData {
|
||||||
|
public int RVA { get; set; }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
|
public PatchData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PatchData(int rva, byte[] data) {
|
||||||
|
this.RVA = rva;
|
||||||
|
this.Data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PatchInfo {
|
||||||
|
public int RvaDecryptMethod { get; set; }
|
||||||
|
public List<PatchData> PatchData { get; set; }
|
||||||
|
|
||||||
|
public PatchInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PatchInfo(int rvaDecryptMethod, PatchData patchData) {
|
||||||
|
this.RvaDecryptMethod = rvaDecryptMethod;
|
||||||
|
this.PatchData = new List<PatchData> { patchData };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly byte[] nops2 = new byte[] { 0x90, 0x90 };
|
||||||
|
static readonly byte[] nops6 = new byte[] { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
|
||||||
|
static readonly Dictionary<Version, PatchInfo> patchInfos32 = new Dictionary<Version, PatchInfo> {
|
||||||
|
{ new Version(2, 0, 8, 0), new PatchInfo(0x00020B20, new PatchData(0x00005733, nops2)) },
|
||||||
|
{ new Version(2, 0, 8, 5), new PatchInfo(0x000221A0, new PatchData(0x00005742, nops2)) },
|
||||||
|
{ new Version(2, 0, 9, 0), new PatchInfo(0x00023360, new PatchData(0x000056F2, nops6)) },
|
||||||
|
{ new Version(2, 0, 10, 0), new PatchInfo(0x00023B30, new PatchData(0x00005B12, nops6)) },
|
||||||
|
{ new Version(2, 0, 11, 0), new PatchInfo(0x000207C0, new PatchData(0x00018432, nops6)) },
|
||||||
|
};
|
||||||
|
static readonly Dictionary<Version, PatchInfo> patchInfos64 = new Dictionary<Version, PatchInfo> {
|
||||||
|
{ new Version(2, 0, 8, 0), new PatchInfo(0x00026090, new PatchData(0x00005E0C, nops6)) },
|
||||||
|
{ new Version(2, 0, 8, 5), new PatchInfo(0x000273D0, new PatchData(0x000060CA, nops6)) },
|
||||||
|
{ new Version(2, 0, 9, 0), new PatchInfo(0x00028B00, new PatchData(0x00005F70, nops6)) },
|
||||||
|
{ new Version(2, 0, 10, 0), new PatchInfo(0x00029630, new PatchData(0x00006510, nops6)) },
|
||||||
|
{ new Version(2, 0, 11, 0), new PatchInfo(0x000257C0, new PatchData(0x0001C9A0, nops6)) },
|
||||||
|
};
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
static extern bool VirtualProtect(IntPtr addr, int size, uint newProtect, out uint oldProtect);
|
||||||
|
const uint PAGE_EXECUTE_READWRITE = 0x40;
|
||||||
|
|
||||||
|
public DecrypterBase(DynamicMethodsDecrypter dmd) {
|
||||||
|
this.dmd = dmd;
|
||||||
|
this.appDomainId = AppDomain.CurrentDomain.Id;
|
||||||
|
this.asmHashCode = dmd.reflectionModule.Assembly.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IntPtr GetDelegateAddress(FieldDef delegateField) {
|
||||||
|
FieldInfo delegateFieldInfo = dmd.reflectionProtectModule.ResolveField(0x04000000 + (int)delegateField.Rid);
|
||||||
|
object mainTypeInst = ((Delegate)dmd.invokerFieldInfo.GetValue(null)).Target;
|
||||||
|
return GetNativeAddressOfDelegate((Delegate)delegateFieldInfo.GetValue(mainTypeInst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static IntPtr GetNativeAddressOfDelegate(Delegate del) {
|
||||||
|
var field = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (field == null)
|
||||||
|
return IntPtr.Zero;
|
||||||
|
|
||||||
|
return (IntPtr)field.GetValue(del);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void PatchRuntime(IntPtr decryptAddr) {
|
||||||
|
if (!PatchRuntimeInternal(decryptAddr))
|
||||||
|
throw new ApplicationException("Probably a new version. Could not patch runtime.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PatchRuntimeInternal(IntPtr decryptAddr) {
|
||||||
|
var patchInfos = IntPtr.Size == 4 ? patchInfos32 : patchInfos64;
|
||||||
|
var protectVersion = dmd.reflectionProtectModule.Assembly.GetName().Version;
|
||||||
|
PatchInfo info;
|
||||||
|
if (!patchInfos.TryGetValue(protectVersion, out info))
|
||||||
|
return false;
|
||||||
|
return PatchRuntime(decryptAddr, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HandleProcessCorruptedStateExceptions, SecurityCritical] // Req'd on .NET 4.0
|
||||||
|
static bool PatchRuntime(IntPtr decryptAddr, PatchInfo info) {
|
||||||
|
try {
|
||||||
|
IntPtr baseAddr = new IntPtr(decryptAddr.ToInt64() - info.RvaDecryptMethod);
|
||||||
|
if ((baseAddr.ToInt64() & 0xFFFF) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Marshal.ReadInt16(baseAddr) != 0x5A4D)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var patchData in info.PatchData) {
|
||||||
|
var patchAddr = new IntPtr(baseAddr.ToInt64() + patchData.RVA);
|
||||||
|
uint oldProtect;
|
||||||
|
if (!VirtualProtect(patchAddr, patchData.Data.Length, PAGE_EXECUTE_READWRITE, out oldProtect))
|
||||||
|
return false;
|
||||||
|
Marshal.Copy(patchData.Data, 0, patchAddr, patchData.Data.Length);
|
||||||
|
VirtualProtect(patchAddr, patchData.Data.Length, oldProtect, out oldProtect);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract byte[] Decrypt(int methodId, uint rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.0.7.1 - 1.0.8.0
|
||||||
|
class DecrypterV1_0_7_1 : DecrypterBase {
|
||||||
|
DecryptMethod decryptMethod;
|
||||||
|
|
||||||
|
unsafe delegate bool DecryptMethod(int appDomainId, int asmHashCode, int methodId, out byte* pMethodCode, out int methodSize);
|
||||||
|
|
||||||
|
public DecrypterV1_0_7_1(DynamicMethodsDecrypter dmd, FieldDef delegateField)
|
||||||
|
: base(dmd) {
|
||||||
|
IntPtr addr = GetDelegateAddress(delegateField);
|
||||||
|
decryptMethod = (DecryptMethod)Marshal.GetDelegateForFunctionPointer(addr, typeof(DecryptMethod));
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe override byte[] Decrypt(int methodId, uint rid) {
|
||||||
|
byte* pMethodCode;
|
||||||
|
int methodSize;
|
||||||
|
if (!decryptMethod(appDomainId, asmHashCode, methodId, out pMethodCode, out methodSize))
|
||||||
|
return null;
|
||||||
|
byte[] methodData = new byte[methodSize];
|
||||||
|
Marshal.Copy(new IntPtr(pMethodCode), methodData, 0, methodData.Length);
|
||||||
|
return methodData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.0.0.0 - 2.0.7.6
|
||||||
|
class DecrypterV2_0_0_0 : DecrypterBase {
|
||||||
|
DecryptMethod decryptMethod;
|
||||||
|
|
||||||
|
unsafe delegate bool DecryptMethod(int clrMajorVersion, int appDomainId, int asmHashCode, int methodId, out byte* pMethodCode, out int methodSize);
|
||||||
|
|
||||||
|
public DecrypterV2_0_0_0(DynamicMethodsDecrypter dmd, FieldDef delegateField)
|
||||||
|
: base(dmd) {
|
||||||
|
IntPtr addr = GetDelegateAddress(delegateField);
|
||||||
|
decryptMethod = (DecryptMethod)Marshal.GetDelegateForFunctionPointer(addr, typeof(DecryptMethod));
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe override byte[] Decrypt(int methodId, uint rid) {
|
||||||
|
byte* pMethodCode;
|
||||||
|
int methodSize;
|
||||||
|
if (!decryptMethod(Environment.Version.Major, appDomainId, asmHashCode, methodId, out pMethodCode, out methodSize))
|
||||||
|
return null;
|
||||||
|
byte[] methodData = new byte[methodSize];
|
||||||
|
Marshal.Copy(new IntPtr(pMethodCode), methodData, 0, methodData.Length);
|
||||||
|
return methodData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.0.8.0
|
||||||
|
class DecrypterV2_0_8_0 : DecrypterBase {
|
||||||
|
DecryptMethod decryptMethod;
|
||||||
|
byte[] decryptedData;
|
||||||
|
|
||||||
|
delegate bool DecryptMethod(int clrMajorVersion, int appDomainId, int asmHashCode, int methodId, [MarshalAs(UnmanagedType.FunctionPtr)] DecryptCallback decryptCallback, [MarshalAs(UnmanagedType.Interface)] out Delegate createdDelegate);
|
||||||
|
unsafe delegate bool DecryptCallback(byte* pMethodCode, int methodSize, [MarshalAs(UnmanagedType.Interface)] ref Delegate createdDelegate);
|
||||||
|
|
||||||
|
public DecrypterV2_0_8_0(DynamicMethodsDecrypter dmd, FieldDef delegateField)
|
||||||
|
: base(dmd) {
|
||||||
|
IntPtr addr = GetDelegateAddress(delegateField);
|
||||||
|
decryptMethod = (DecryptMethod)Marshal.GetDelegateForFunctionPointer(addr, typeof(DecryptMethod));
|
||||||
|
PatchRuntime(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe override byte[] Decrypt(int methodId, uint rid) {
|
||||||
|
Delegate createdDelegate;
|
||||||
|
if (!decryptMethod(Environment.Version.Major, appDomainId, asmHashCode, methodId, MyDecryptCallback, out createdDelegate))
|
||||||
|
return null;
|
||||||
|
return decryptedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe bool MyDecryptCallback(byte* pMethodCode, int methodSize, ref Delegate createdDelegate) {
|
||||||
|
decryptedData = new byte[methodSize];
|
||||||
|
Marshal.Copy(new IntPtr(pMethodCode), decryptedData, 0, decryptedData.Length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.0.8.5
|
||||||
|
class DecrypterV2_0_8_5 : DecrypterBase {
|
||||||
|
DecryptMethod decryptMethod;
|
||||||
|
byte[] decryptedData;
|
||||||
|
bool decryptReturnValue;
|
||||||
|
|
||||||
|
delegate bool DecryptMethod(int clrMajorVersion, int appDomainId, int asmHashCode, int methodId, [MarshalAs(UnmanagedType.Interface)] StackTrace stackTrace, [MarshalAs(UnmanagedType.FunctionPtr)] DecryptCallback decryptCallback, [MarshalAs(UnmanagedType.Interface)] out Delegate createdDelegate);
|
||||||
|
unsafe delegate bool DecryptCallback(byte* pMethodCode, int methodSize, [MarshalAs(UnmanagedType.Interface)] ref Delegate createdDelegate);
|
||||||
|
|
||||||
|
public DecrypterV2_0_8_5(DynamicMethodsDecrypter dmd, FieldDef delegateField)
|
||||||
|
: base(dmd) {
|
||||||
|
IntPtr addr = GetDelegateAddress(delegateField);
|
||||||
|
decryptMethod = (DecryptMethod)Marshal.GetDelegateForFunctionPointer(addr, typeof(DecryptMethod));
|
||||||
|
PatchRuntime(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe override byte[] Decrypt(int methodId, uint rid) {
|
||||||
|
Delegate createdDelegate;
|
||||||
|
decryptReturnValue = false;
|
||||||
|
if (!decryptMethod(Environment.Version.Major, appDomainId, asmHashCode, methodId, new StackTrace(), MyDecryptCallback, out createdDelegate) &&
|
||||||
|
!decryptReturnValue)
|
||||||
|
return null;
|
||||||
|
return decryptedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe bool MyDecryptCallback(byte* pMethodCode, int methodSize, ref Delegate createdDelegate) {
|
||||||
|
createdDelegate = new DecryptCallback(MyDecryptCallback);
|
||||||
|
decryptedData = new byte[methodSize];
|
||||||
|
Marshal.Copy(new IntPtr(pMethodCode), decryptedData, 0, decryptedData.Length);
|
||||||
|
return decryptReturnValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.0.9.0 - 2.0.11.0
|
||||||
|
class DecrypterV2_0_9_0 : DecrypterBase {
|
||||||
|
DecryptMethod decryptMethod;
|
||||||
|
byte[] decryptedData;
|
||||||
|
|
||||||
|
delegate bool DecryptMethod(int clrMajorVersion, int appDomainId, int asmHashCode, int methodId, [MarshalAs(UnmanagedType.Interface)] StackTrace stackTrace, [MarshalAs(UnmanagedType.FunctionPtr)] DecryptCallback decryptCallback);
|
||||||
|
unsafe delegate bool DecryptCallback(byte* pMethodCode, int methodSize, int methodId);
|
||||||
|
|
||||||
|
public DecrypterV2_0_9_0(DynamicMethodsDecrypter dmd, FieldDef delegateField)
|
||||||
|
: base(dmd) {
|
||||||
|
IntPtr addr = GetDelegateAddress(delegateField);
|
||||||
|
decryptMethod = (DecryptMethod)Marshal.GetDelegateForFunctionPointer(addr, typeof(DecryptMethod));
|
||||||
|
PatchRuntime(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe override byte[] Decrypt(int methodId, uint rid) {
|
||||||
|
var encMethod = this.dmd.reflectionModule.ResolveMethod(0x06000000 + (int)rid);
|
||||||
|
var stackTrace = StackTracePatcher.WriteStackFrame(new StackTrace(), 1, encMethod);
|
||||||
|
if (!decryptMethod(Environment.Version.Major, appDomainId, asmHashCode, methodId, stackTrace, MyDecryptCallback))
|
||||||
|
return null;
|
||||||
|
return decryptedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe bool MyDecryptCallback(byte* pMethodCode, int methodSize, int methodId) {
|
||||||
|
decryptedData = new byte[methodSize];
|
||||||
|
Marshal.Copy(new IntPtr(pMethodCode), decryptedData, 0, decryptedData.Length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DynamicMethodsDecrypter(ModuleDefMD module, Module reflectionModule) {
|
||||||
|
this.module = module;
|
||||||
|
this.reflectionModule = reflectionModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize() {
|
||||||
|
RuntimeHelpers.RunModuleConstructor(reflectionModule.ModuleHandle);
|
||||||
|
var reflectionProtectAssembly = GetProtectAssembly();
|
||||||
|
if (reflectionProtectAssembly == null)
|
||||||
|
throw new ApplicationException("Could not find 'Protect' assembly");
|
||||||
|
reflectionProtectModule = reflectionProtectAssembly.ManifestModule;
|
||||||
|
moduleProtect = ModuleDefMD.Load(reflectionProtectModule);
|
||||||
|
protectMainType = FindMainType(moduleProtect);
|
||||||
|
if (protectMainType == null)
|
||||||
|
throw new ApplicationException("Could not find Protect.MainType");
|
||||||
|
var invokerField = FindInvokerField(module);
|
||||||
|
|
||||||
|
reflectionProtectMainType = reflectionProtectModule.ResolveType(0x02000000 + (int)protectMainType.Rid);
|
||||||
|
invokerFieldInfo = reflectionModule.ResolveField(0x04000000 + (int)invokerField.Rid);
|
||||||
|
|
||||||
|
decrypter = CreateDecrypter();
|
||||||
|
if (decrypter == null)
|
||||||
|
throw new ApplicationException("Probably a new version. Could not create a decrypter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecryptedMethodInfo Decrypt(int methodId, uint rid) {
|
||||||
|
byte[] methodData = decrypter.Decrypt(methodId, rid);
|
||||||
|
if (methodData == null)
|
||||||
|
throw new ApplicationException(string.Format("Probably a new version. Could not decrypt method. ID:{0}, RID:{1:X4}", methodId, rid));
|
||||||
|
return new DecryptedMethodInfo(methodId, methodData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (moduleProtect != null)
|
||||||
|
moduleProtect.Dispose();
|
||||||
|
moduleProtect = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter CreateDecrypter() {
|
||||||
|
return CreateDecrypterV1_0_7_1() ??
|
||||||
|
CreateDecrypterV2_0_0_0() ??
|
||||||
|
CreateDecrypterV2_0_8_0() ??
|
||||||
|
CreateDecrypterV2_0_8_5() ??
|
||||||
|
CreateDecrypterV2_0_9_0();
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter CreateDecrypterV1_0_7_1() {
|
||||||
|
var delegateField = FindDelegateFieldV1_0_7_1(protectMainType);
|
||||||
|
if (delegateField == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new DecrypterV1_0_7_1(this, delegateField);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter CreateDecrypterV2_0_0_0() {
|
||||||
|
var delegateField = FindDelegateFieldV2_0_0_0(protectMainType);
|
||||||
|
if (delegateField == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new DecrypterV2_0_0_0(this, delegateField);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter CreateDecrypterV2_0_8_0() {
|
||||||
|
var delegateField = FindDelegateFieldV2_0_8_0(protectMainType, FindDecryptCallbackV2_0_8_0(protectMainType));
|
||||||
|
if (delegateField == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new DecrypterV2_0_8_0(this, delegateField);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter CreateDecrypterV2_0_8_5() {
|
||||||
|
var delegateField = FindDelegateFieldV2_0_8_5(protectMainType, FindDecryptCallbackV2_0_8_0(protectMainType));
|
||||||
|
if (delegateField == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new DecrypterV2_0_8_5(this, delegateField);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter CreateDecrypterV2_0_9_0() {
|
||||||
|
var delegateField = FindDelegateFieldV2_0_9_0(protectMainType, FindDecryptCallbackV2_0_9_0(protectMainType));
|
||||||
|
if (delegateField == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new DecrypterV2_0_9_0(this, delegateField);
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly byte[] ilpPublicKeyToken = new byte[8] { 0x20, 0x12, 0xD3, 0xC0, 0x55, 0x1F, 0xE0, 0x3D };
|
||||||
|
static Assembly GetProtectAssembly() {
|
||||||
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
|
||||||
|
if (!string.IsNullOrEmpty(asm.Location))
|
||||||
|
continue;
|
||||||
|
var asmName = asm.GetName();
|
||||||
|
if (asmName.Name != "Protect")
|
||||||
|
continue;
|
||||||
|
if (!Compare(asmName.GetPublicKeyToken(), ilpPublicKeyToken))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return asm;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Compare(byte[] a, byte[] b) {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return true;
|
||||||
|
if (a == null || b == null)
|
||||||
|
return false;
|
||||||
|
if (a.Length != b.Length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < a.Length; i++) {
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeDef FindMainType(ModuleDef module) {
|
||||||
|
foreach (var type in module.Types) {
|
||||||
|
if (type.FindMethod("Finalize") != null)
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindInvokerField(ModuleDef module) {
|
||||||
|
return FindDelegateField(module.GlobalType, "System.Delegate", "(System.Int32)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDelegateFieldV1_0_7_1(TypeDef mainType) {
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", "(System.Int32,System.Int32,System.Int32,System.Byte*&,System.Int32&)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDelegateFieldV2_0_0_0(TypeDef mainType) {
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", "(System.Int32,System.Int32,System.Int32,System.Int32,System.Byte*&,System.Int32&)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDecryptCallbackV2_0_8_0(TypeDef mainType) {
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", "(System.Byte*,System.Int32,System.Delegate&)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDecryptCallbackV2_0_9_0(TypeDef mainType) {
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", "(System.Byte*,System.Int32,System.Int32)");
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDelegateFieldV2_0_8_0(TypeDef mainType, FieldDef decryptCallbackField) {
|
||||||
|
if (decryptCallbackField == null)
|
||||||
|
return null;
|
||||||
|
var type = decryptCallbackField.FieldSig.GetFieldType().ToTypeDefOrRef() as TypeDef;
|
||||||
|
if (type == null)
|
||||||
|
return null;
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", string.Format("(System.Int32,System.Int32,System.Int32,System.Int32,{0},System.Delegate&)", type.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDelegateFieldV2_0_8_5(TypeDef mainType, FieldDef decryptCallbackField) {
|
||||||
|
if (decryptCallbackField == null)
|
||||||
|
return null;
|
||||||
|
var type = decryptCallbackField.FieldSig.GetFieldType().ToTypeDefOrRef() as TypeDef;
|
||||||
|
if (type == null)
|
||||||
|
return null;
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", string.Format("(System.Int32,System.Int32,System.Int32,System.Int32,System.Diagnostics.StackTrace,{0},System.Delegate&)", type.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDelegateFieldV2_0_9_0(TypeDef mainType, FieldDef decryptCallbackField) {
|
||||||
|
if (decryptCallbackField == null)
|
||||||
|
return null;
|
||||||
|
var type = decryptCallbackField.FieldSig.GetFieldType().ToTypeDefOrRef() as TypeDef;
|
||||||
|
if (type == null)
|
||||||
|
return null;
|
||||||
|
return FindDelegateField(mainType, "System.Boolean", string.Format("(System.Int32,System.Int32,System.Int32,System.Int32,System.Diagnostics.StackTrace,{0})", type.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldDef FindDelegateField(TypeDef mainType, string returnType, string parameters) {
|
||||||
|
foreach (var field in mainType.Fields) {
|
||||||
|
var fieldSig = field.FieldSig;
|
||||||
|
if (fieldSig == null)
|
||||||
|
continue;
|
||||||
|
var fieldType = fieldSig.Type.ToTypeDefOrRef() as TypeDef;
|
||||||
|
if (fieldType == null)
|
||||||
|
continue;
|
||||||
|
if (fieldType.BaseType != null && fieldType.BaseType.FullName != "System.MulticastDelegate")
|
||||||
|
continue;
|
||||||
|
var invokeMethod = fieldType.FindMethod("Invoke");
|
||||||
|
if (!DotNetUtils.IsMethod(invokeMethod, returnType, parameters))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 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.Reflection;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using AssemblyData;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
|
sealed class DynamicMethodsDecrypterService : IUserGenericService {
|
||||||
|
public const int MSG_DECRYPT_METHODS = 0;
|
||||||
|
|
||||||
|
Module reflObfModule;
|
||||||
|
ModuleDefMD obfModule;
|
||||||
|
|
||||||
|
[CreateUserGenericService]
|
||||||
|
public static IUserGenericService Create() {
|
||||||
|
return new DynamicMethodsDecrypterService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (obfModule != null)
|
||||||
|
obfModule.Dispose();
|
||||||
|
obfModule = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssemblyLoaded(Assembly assembly) {
|
||||||
|
this.reflObfModule = assembly.ManifestModule;
|
||||||
|
this.obfModule = ModuleDefMD.Load(reflObfModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object HandleMessage(int msg, object[] args) {
|
||||||
|
switch (msg) {
|
||||||
|
case MSG_DECRYPT_METHODS:
|
||||||
|
return DecryptMethods(args[0] as IList<int>);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ApplicationException(string.Format("Invalid msg: {0:X8}", msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IList<DecryptedMethodInfo> DecryptMethods(IList<int> methodIds) {
|
||||||
|
using (var decrypter = new DynamicMethodsDecrypter(obfModule, reflObfModule)) {
|
||||||
|
decrypter.Initialize();
|
||||||
|
|
||||||
|
var infos = new List<DecryptedMethodInfo>();
|
||||||
|
|
||||||
|
for (int i = 0; i < methodIds.Count; i += 2)
|
||||||
|
infos.Add(decrypter.Decrypt(methodIds[i], (uint)methodIds[i + 1]));
|
||||||
|
|
||||||
|
return infos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 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 dnlib.DotNet;
|
||||||
|
using AssemblyData;
|
||||||
|
using de4dot.code.AssemblyClient;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
|
// Calls class to dynamically decrypt methods, then restores them.
|
||||||
|
class DynamicMethodsRestorer : MethodsDecrypterBase {
|
||||||
|
public DynamicMethodsRestorer(ModuleDefMD module, MainType mainType)
|
||||||
|
: base(module, mainType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DecryptInternal() {
|
||||||
|
IList<DecryptedMethodInfo> decryptedData;
|
||||||
|
var serverVersion = NewProcessAssemblyClientFactory.GetServerClrVersion(module);
|
||||||
|
using (var client = new NewProcessAssemblyClientFactory(serverVersion).Create(AssemblyServiceType.Generic)) {
|
||||||
|
client.Connect();
|
||||||
|
client.WaitConnected();
|
||||||
|
|
||||||
|
client.GenericService.LoadUserService(typeof(DynamicMethodsDecrypterService), null);
|
||||||
|
client.GenericService.LoadAssembly(module.Location);
|
||||||
|
decryptedData = client.GenericService.SendMessage(DynamicMethodsDecrypterService.MSG_DECRYPT_METHODS, new object[] { GetMethodIds() }) as IList<DecryptedMethodInfo>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decryptedData == null)
|
||||||
|
throw new ApplicationException("Unknown return value from dynamic methods decrypter service");
|
||||||
|
|
||||||
|
foreach (var info in decryptedData)
|
||||||
|
methodInfos[info.id] = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
IList<int> GetMethodIds() {
|
||||||
|
var ids = new List<int>();
|
||||||
|
|
||||||
|
foreach (var type in module.GetTypes()) {
|
||||||
|
foreach (var method in type.Methods) {
|
||||||
|
int? id = GetMethodId(method);
|
||||||
|
if (id == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ids.Add(id.Value);
|
||||||
|
ids.Add((int)method.Rid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,15 +53,20 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
CheckMethod(DotNetUtils.GetModuleTypeCctor(module));
|
CheckMethod(DotNetUtils.GetModuleTypeCctor(module));
|
||||||
}
|
}
|
||||||
|
|
||||||
static string[] ilpLocals = new string[] {
|
static string[] ilpLocalsV1x = new string[] {
|
||||||
"System.Boolean",
|
"System.Boolean",
|
||||||
"System.IntPtr",
|
"System.IntPtr",
|
||||||
"System.Object[]",
|
"System.Object[]",
|
||||||
};
|
};
|
||||||
|
static string[] ilpLocalsV2x = new string[] {
|
||||||
|
"System.IntPtr",
|
||||||
|
};
|
||||||
bool CheckMethod(MethodDef cctor) {
|
bool CheckMethod(MethodDef cctor) {
|
||||||
if (cctor == null || cctor.Body == null)
|
if (cctor == null || cctor.Body == null)
|
||||||
return false;
|
return false;
|
||||||
if (!new LocalTypes(cctor).Exactly(ilpLocals))
|
var localTypes = new LocalTypes(cctor);
|
||||||
|
if (!localTypes.Exactly(ilpLocalsV1x) &&
|
||||||
|
!localTypes.Exactly(ilpLocalsV2x))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var type = cctor.DeclaringType;
|
var type = cctor.DeclaringType;
|
||||||
|
@ -70,20 +75,31 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
methods = GetPinvokeMethods(type, "P0");
|
methods = GetPinvokeMethods(type, "P0");
|
||||||
if (methods.Count != 2)
|
if (methods.Count != 2)
|
||||||
return false;
|
return false;
|
||||||
if (type.Fields.Count != 1)
|
if (type.Fields.Count < 1 || type.Fields.Count > 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var theField = type.Fields[0];
|
if (!GetDelegate(type, out invokerInstanceField, out invokerDelegate))
|
||||||
var theDelegate = theField.FieldType.TryGetTypeDef();
|
|
||||||
if (theDelegate == null || !DotNetUtils.DerivesFromDelegate(theDelegate))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
protectMethods = methods;
|
protectMethods = methods;
|
||||||
invokerDelegate = theDelegate;
|
|
||||||
invokerInstanceField = theField;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetDelegate(TypeDef type, out FieldDef field, out TypeDef del) {
|
||||||
|
foreach (var fld in type.Fields) {
|
||||||
|
var theDelegate = fld.FieldType.TryGetTypeDef();
|
||||||
|
if (theDelegate != null && DotNetUtils.DerivesFromDelegate(theDelegate)) {
|
||||||
|
field = fld;
|
||||||
|
del = theDelegate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field = null;
|
||||||
|
del = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static List<MethodDef> GetPinvokeMethods(TypeDef type, string name) {
|
static List<MethodDef> GetPinvokeMethods(TypeDef type, string name) {
|
||||||
var list = new List<MethodDef>();
|
var list = new List<MethodDef>();
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
|
|
125
de4dot.code/deobfuscators/ILProtector/MethodsDecrypterBase.cs
Normal file
125
de4dot.code/deobfuscators/ILProtector/MethodsDecrypterBase.cs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 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 dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
|
abstract class MethodsDecrypterBase {
|
||||||
|
protected ModuleDefMD module;
|
||||||
|
protected MainType mainType;
|
||||||
|
protected EmbeddedResource methodsResource;
|
||||||
|
protected Dictionary<int, DecryptedMethodInfo> methodInfos = new Dictionary<int, DecryptedMethodInfo>();
|
||||||
|
List<TypeDef> delegateTypes = new List<TypeDef>();
|
||||||
|
|
||||||
|
public EmbeddedResource Resource {
|
||||||
|
get { return methodsResource; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TypeDef> DelegateTypes {
|
||||||
|
get { return delegateTypes; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodsDecrypterBase(ModuleDefMD module, MainType mainType) {
|
||||||
|
this.module = module;
|
||||||
|
this.mainType = mainType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Decrypt() {
|
||||||
|
DecryptInternal();
|
||||||
|
RestoreMethods();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void DecryptInternal();
|
||||||
|
|
||||||
|
void RestoreMethods() {
|
||||||
|
if (methodInfos.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Logger.v("Restoring {0} methods", methodInfos.Count);
|
||||||
|
Logger.Instance.Indent();
|
||||||
|
foreach (var type in module.GetTypes()) {
|
||||||
|
foreach (var method in type.Methods) {
|
||||||
|
if (method.Body == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (RestoreMethod(method)) {
|
||||||
|
Logger.v("Restored method {0} ({1:X8}). Instrs:{2}, Locals:{3}, Exceptions:{4}",
|
||||||
|
Utils.RemoveNewlines(method.FullName),
|
||||||
|
method.MDToken.ToInt32(),
|
||||||
|
method.Body.Instructions.Count,
|
||||||
|
method.Body.Variables.Count,
|
||||||
|
method.Body.ExceptionHandlers.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Logger.Instance.DeIndent();
|
||||||
|
if (methodInfos.Count != 0)
|
||||||
|
Logger.w("{0} methods weren't restored", methodInfos.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RestoreMethod(MethodDef method) {
|
||||||
|
int? methodId = GetMethodId(method);
|
||||||
|
if (methodId == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var parameters = method.Parameters;
|
||||||
|
var methodInfo = methodInfos[methodId.Value];
|
||||||
|
methodInfos.Remove(methodId.Value);
|
||||||
|
var methodReader = new MethodReader(module, methodInfo.data, parameters);
|
||||||
|
methodReader.Read();
|
||||||
|
|
||||||
|
RestoreMethod(method, methodReader);
|
||||||
|
delegateTypes.Add(methodReader.DelegateType);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RestoreMethod(MethodDef method, MethodReader methodReader) {
|
||||||
|
// body.MaxStackSize = <let dnlib calculate this>
|
||||||
|
method.Body.InitLocals = methodReader.InitLocals;
|
||||||
|
methodReader.RestoreMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int? GetMethodId(MethodDef method) {
|
||||||
|
if (method == null || method.Body == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
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 (!ldci4.IsLdcI4())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var field = ldsfld.Operand as FieldDef;
|
||||||
|
if (field == null || field != mainType.InvokerInstanceField)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return ldci4.GetLdcI4Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,16 +22,9 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using dnlib.IO;
|
using dnlib.IO;
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using dnlib.DotNet.Emit;
|
|
||||||
using de4dot.blocks;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.ILProtector {
|
namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
class MethodsDecrypter {
|
class StaticMethodsDecrypter : MethodsDecrypterBase {
|
||||||
ModuleDefMD module;
|
|
||||||
MainType mainType;
|
|
||||||
EmbeddedResource methodsResource;
|
|
||||||
Dictionary<int, MethodInfo2> methodInfos = new Dictionary<int, MethodInfo2>();
|
|
||||||
List<TypeDef> delegateTypes = new List<TypeDef>();
|
|
||||||
IDecrypter decrypter;
|
IDecrypter decrypter;
|
||||||
|
|
||||||
interface IDecrypter {
|
interface IDecrypter {
|
||||||
|
@ -153,13 +146,13 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.0.6
|
// 1.0.6 - 1.0.7.0
|
||||||
class DecrypterV106 : DecrypterBase {
|
class DecrypterV106 : DecrypterBase {
|
||||||
byte[] decryptionKey6;
|
byte[] decryptionKey6;
|
||||||
byte[] decryptionKey7;
|
byte[] decryptionKey7;
|
||||||
|
|
||||||
DecrypterV106(byte[] key0, byte[] key6, byte[] key7, int startOffset) {
|
DecrypterV106(byte[] key0, byte[] key6, byte[] key7, int startOffset) {
|
||||||
this.ilpVersion = "1.0.6";
|
this.ilpVersion = "1.0.6 - 1.0.7.0";
|
||||||
this.startOffset = startOffset;
|
this.startOffset = startOffset;
|
||||||
this.decryptionKey = key0;
|
this.decryptionKey = key0;
|
||||||
this.decryptionKey6 = key6;
|
this.decryptionKey6 = key6;
|
||||||
|
@ -185,7 +178,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
|
|
||||||
var key0 = DeobUtils.Sha1Sum(sha1Data); // 1.0.6.0
|
var key0 = DeobUtils.Sha1Sum(sha1Data); // 1.0.6.0
|
||||||
var key6 = GetKey(reader, key0, keyXorOffs6); // 1.0.6.6
|
var key6 = GetKey(reader, key0, keyXorOffs6); // 1.0.6.6
|
||||||
var key7 = GetKey(reader, key0, keyXorOffs7); // 1.0.6.7
|
var key7 = GetKey(reader, key0, keyXorOffs7); // 1.0.6.7 - 1.0.7.0
|
||||||
return new DecrypterV106(key0, key6, key7, encryptedOffs);
|
return new DecrypterV106(key0, key6, key7, encryptedOffs);
|
||||||
}
|
}
|
||||||
catch (IOException) {
|
catch (IOException) {
|
||||||
|
@ -232,29 +225,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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<TypeDef> DelegateTypes {
|
|
||||||
get { return delegateTypes; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Version {
|
public string Version {
|
||||||
get { return decrypter == null ? null : decrypter.Version; }
|
get { return decrypter == null ? null : decrypter.Version; }
|
||||||
}
|
}
|
||||||
|
@ -263,9 +233,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
get { return methodsResource != null; }
|
get { return methodsResource != null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodsDecrypter(ModuleDefMD module, MainType mainType) {
|
public StaticMethodsDecrypter(ModuleDefMD module, MainType mainType)
|
||||||
this.module = module;
|
: base(module, mainType) {
|
||||||
this.mainType = mainType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Find() {
|
public void Find() {
|
||||||
|
@ -300,108 +269,35 @@ namespace de4dot.code.deobfuscators.ILProtector {
|
||||||
return decrypter != null;
|
return decrypter != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Decrypt() {
|
protected override void DecryptInternal() {
|
||||||
if (methodsResource == null || decrypter == null)
|
if (methodsResource == null || decrypter == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var info in ReadMethodInfos(decrypter.GetMethodsData(methodsResource)))
|
foreach (var info in ReadMethodInfos(decrypter.GetMethodsData(methodsResource)))
|
||||||
methodInfos[info.id] = info;
|
methodInfos[info.id] = info;
|
||||||
|
|
||||||
RestoreMethods();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodInfo2[] ReadMethodInfos(byte[] data) {
|
static DecryptedMethodInfo[] ReadMethodInfos(byte[] data) {
|
||||||
|
var toOffset = new Dictionary<DecryptedMethodInfo, int>();
|
||||||
var reader = MemoryImageStream.Create(data);
|
var reader = MemoryImageStream.Create(data);
|
||||||
int numMethods = (int)reader.Read7BitEncodedUInt32();
|
int numMethods = (int)reader.Read7BitEncodedUInt32();
|
||||||
int totalCodeSize = (int)reader.Read7BitEncodedUInt32();
|
int totalCodeSize = (int)reader.Read7BitEncodedUInt32();
|
||||||
var methodInfos = new MethodInfo2[numMethods];
|
var methodInfos = new DecryptedMethodInfo[numMethods];
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (int i = 0; i < numMethods; i++) {
|
for (int i = 0; i < numMethods; i++) {
|
||||||
int id = (int)reader.Read7BitEncodedUInt32();
|
int id = (int)reader.Read7BitEncodedUInt32();
|
||||||
int size = (int)reader.Read7BitEncodedUInt32();
|
int size = (int)reader.Read7BitEncodedUInt32();
|
||||||
methodInfos[i] = new MethodInfo2(id, offset, size);
|
var info = new DecryptedMethodInfo(id, size);
|
||||||
|
methodInfos[i] = info;
|
||||||
|
toOffset[info] = offset;
|
||||||
offset += size;
|
offset += size;
|
||||||
}
|
}
|
||||||
long dataOffset = reader.Position;
|
long dataOffset = reader.Position;
|
||||||
foreach (var info in methodInfos) {
|
foreach (var info in methodInfos) {
|
||||||
reader.Position = dataOffset + info.offset;
|
reader.Position = dataOffset + toOffset[info];
|
||||||
reader.Read(info.data, 0, info.data.Length);
|
reader.Read(info.data, 0, info.data.Length);
|
||||||
}
|
}
|
||||||
return methodInfos;
|
return methodInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestoreMethods() {
|
|
||||||
if (methodInfos.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Logger.v("Restoring {0} methods", methodInfos.Count);
|
|
||||||
Logger.Instance.Indent();
|
|
||||||
foreach (var type in module.GetTypes()) {
|
|
||||||
foreach (var method in type.Methods) {
|
|
||||||
if (method.Body == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (RestoreMethod(method)) {
|
|
||||||
Logger.v("Restored method {0} ({1:X8}). Instrs:{2}, Locals:{3}, Exceptions:{4}",
|
|
||||||
Utils.RemoveNewlines(method.FullName),
|
|
||||||
method.MDToken.ToInt32(),
|
|
||||||
method.Body.Instructions.Count,
|
|
||||||
method.Body.Variables.Count,
|
|
||||||
method.Body.ExceptionHandlers.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Logger.Instance.DeIndent();
|
|
||||||
if (methodInfos.Count != 0)
|
|
||||||
Logger.w("{0} methods weren't restored", methodInfos.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int INVALID_METHOD_ID = -1;
|
|
||||||
bool RestoreMethod(MethodDef method) {
|
|
||||||
int methodId = GetMethodId(method);
|
|
||||||
if (methodId == INVALID_METHOD_ID)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var parameters = method.Parameters;
|
|
||||||
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(MethodDef method, MethodReader methodReader) {
|
|
||||||
// body.MaxStackSize = <let dnlib calculate this>
|
|
||||||
method.Body.InitLocals = methodReader.InitLocals;
|
|
||||||
methodReader.RestoreMethod(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetMethodId(MethodDef 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 (!ldci4.IsLdcI4())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var field = ldsfld.Operand as FieldDef;
|
|
||||||
if (field == null || field != mainType.InvokerInstanceField)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return ldci4.GetLdcI4Value();
|
|
||||||
}
|
|
||||||
|
|
||||||
return INVALID_METHOD_ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user