2012-08-07 20:40:51 +08:00
|
|
|
|
/*
|
2014-03-12 05:17:50 +08:00
|
|
|
|
Copyright (C) 2011-2014 de4dot@gmail.com
|
2012-08-07 20:40:51 +08:00
|
|
|
|
|
|
|
|
|
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;
|
2012-08-07 23:51:43 +08:00
|
|
|
|
using System.Text;
|
2012-12-23 04:08:29 +08:00
|
|
|
|
using dnlib.DotNet;
|
|
|
|
|
using dnlib.DotNet.Emit;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
using de4dot.blocks;
|
|
|
|
|
|
|
|
|
|
namespace de4dot.code.deobfuscators.Confuser {
|
2012-08-08 07:19:59 +08:00
|
|
|
|
// From v1.7 r74708 to v1.8 r75349
|
2012-08-07 20:40:51 +08:00
|
|
|
|
class ConstantsDecrypterV17 : ConstantsDecrypterBase {
|
2012-11-19 06:42:43 +08:00
|
|
|
|
MethodDef initMethod;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
ConfuserVersion version = ConfuserVersion.Unknown;
|
2012-08-07 23:51:43 +08:00
|
|
|
|
string resourceName;
|
2012-08-08 07:19:29 +08:00
|
|
|
|
int keyArraySize = 8;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
|
|
|
|
|
enum ConfuserVersion {
|
|
|
|
|
Unknown,
|
|
|
|
|
v17_r74708_normal,
|
|
|
|
|
v17_r74708_dynamic,
|
|
|
|
|
v17_r74708_native,
|
2012-08-07 21:26:16 +08:00
|
|
|
|
v17_r74788_normal,
|
|
|
|
|
v17_r74788_dynamic,
|
|
|
|
|
v17_r74788_native,
|
2012-08-07 23:28:53 +08:00
|
|
|
|
v17_r74816_normal,
|
|
|
|
|
v17_r74816_dynamic,
|
|
|
|
|
v17_r74816_native,
|
2012-08-07 23:51:43 +08:00
|
|
|
|
v17_r75056_normal,
|
|
|
|
|
v17_r75056_dynamic,
|
|
|
|
|
v17_r75056_native,
|
2012-08-08 03:57:14 +08:00
|
|
|
|
v18_r75257_normal,
|
|
|
|
|
v18_r75257_dynamic,
|
|
|
|
|
v18_r75257_native,
|
2012-08-08 07:19:59 +08:00
|
|
|
|
// 1.8 r75349 was the last version using this constants encrypter. Starting
|
|
|
|
|
// from 1.8 r75367, the new constants encrypter (generic methods) is used.
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class DecrypterInfoV17 : DecrypterInfo {
|
|
|
|
|
public readonly ConfuserVersion version = ConfuserVersion.Unknown;
|
2012-08-07 21:26:16 +08:00
|
|
|
|
public uint key4, key5;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
public DecrypterInfoV17(ConfuserVersion version, MethodDef decryptMethod) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
this.version = version;
|
|
|
|
|
this.decryptMethod = decryptMethod;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
protected override bool InitializeKeys() {
|
|
|
|
|
if (!FindKey0(decryptMethod, out key0))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return false;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!FindKey1_v17(decryptMethod, out key1))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return false;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!FindKey2Key3(decryptMethod, out key2, out key3))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return false;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!FindKey4(decryptMethod, out key4))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return false;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!FindKey5(decryptMethod, out key5))
|
2012-08-07 21:26:16 +08:00
|
|
|
|
return false;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static bool FindKey1_v17(MethodDef method, out uint key) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
for (int i = 0; i < instrs.Count - 4; i++) {
|
|
|
|
|
var stloc = instrs[i];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!stloc.IsStloc())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
var ldci4 = instrs[i + 1];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldci4.IsLdcI4())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
var ldcloc = instrs[i + 2];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldcloc.IsLdloc())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
2012-11-20 15:02:10 +08:00
|
|
|
|
if (stloc.GetLocal(method.Body.Variables) != ldcloc.GetLocal(method.Body.Variables))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
if (instrs[i + 3].OpCode.Code != Code.Xor)
|
|
|
|
|
continue;
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!instrs[i + 4].IsStloc())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
key = (uint)ldci4.GetLdcI4Value();
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
key = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
bool FindKey4(MethodDef method, out uint key) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
switch (version) {
|
2012-08-07 21:26:16 +08:00
|
|
|
|
case ConfuserVersion.v17_r74708_normal:
|
|
|
|
|
case ConfuserVersion.v17_r74788_normal:
|
2012-08-07 23:28:53 +08:00
|
|
|
|
case ConfuserVersion.v17_r74816_normal:
|
2012-08-07 23:51:43 +08:00
|
|
|
|
case ConfuserVersion.v17_r75056_normal:
|
2012-08-08 03:57:14 +08:00
|
|
|
|
case ConfuserVersion.v18_r75257_normal:
|
2013-01-19 20:09:49 +08:00
|
|
|
|
return FindKey4_normal(method, out key);
|
2012-08-07 21:26:16 +08:00
|
|
|
|
case ConfuserVersion.v17_r74708_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74708_native:
|
|
|
|
|
case ConfuserVersion.v17_r74788_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74788_native:
|
2012-08-07 23:28:53 +08:00
|
|
|
|
case ConfuserVersion.v17_r74816_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74816_native:
|
2012-08-07 23:51:43 +08:00
|
|
|
|
case ConfuserVersion.v17_r75056_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r75056_native:
|
2012-08-08 03:57:14 +08:00
|
|
|
|
case ConfuserVersion.v18_r75257_dynamic:
|
|
|
|
|
case ConfuserVersion.v18_r75257_native:
|
2013-01-19 20:09:49 +08:00
|
|
|
|
return FindKey4_other(method, out key);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
default:
|
|
|
|
|
throw new ApplicationException("Invalid version");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static bool FindKey4_normal(MethodDef method, out uint key) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
for (int i = 0; i < instrs.Count - 5; i++) {
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!instrs[i].IsLdloc())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!instrs[i + 1].IsLdloc())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
if (instrs[i + 2].OpCode.Code != Code.Add)
|
|
|
|
|
continue;
|
|
|
|
|
var ldci4 = instrs[i + 3];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldci4.IsLdcI4())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
if (instrs[i + 4].OpCode.Code != Code.Mul)
|
|
|
|
|
continue;
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!instrs[i + 5].IsStloc())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
key = (uint)ldci4.GetLdcI4Value();
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
key = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static bool FindKey4_other(MethodDef method, out uint key) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
for (int i = 0; i < instrs.Count; i++) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
int index = ConfuserUtils.FindCallMethod(instrs, i, Code.Callvirt, "System.Int32 System.IO.BinaryReader::ReadInt32()");
|
2012-08-07 20:40:51 +08:00
|
|
|
|
if (index < 0)
|
|
|
|
|
break;
|
|
|
|
|
if (index + 1 >= instrs.Count)
|
|
|
|
|
break;
|
|
|
|
|
var ldci4 = instrs[index + 1];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldci4.IsLdcI4())
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
key = (uint)ldci4.GetLdcI4Value();
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
key = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-08-07 21:26:16 +08:00
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
bool FindKey5(MethodDef method, out uint key) {
|
2012-08-07 21:26:16 +08:00
|
|
|
|
switch (version) {
|
|
|
|
|
case ConfuserVersion.v17_r74788_normal:
|
|
|
|
|
case ConfuserVersion.v17_r74788_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74788_native:
|
2012-08-07 23:28:53 +08:00
|
|
|
|
case ConfuserVersion.v17_r74816_normal:
|
|
|
|
|
case ConfuserVersion.v17_r74816_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74816_native:
|
2012-08-07 23:51:43 +08:00
|
|
|
|
case ConfuserVersion.v17_r75056_normal:
|
|
|
|
|
case ConfuserVersion.v17_r75056_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r75056_native:
|
2012-08-08 03:57:14 +08:00
|
|
|
|
case ConfuserVersion.v18_r75257_normal:
|
|
|
|
|
case ConfuserVersion.v18_r75257_dynamic:
|
|
|
|
|
case ConfuserVersion.v18_r75257_native:
|
2013-01-19 20:09:49 +08:00
|
|
|
|
return FindKey5_v17_r74788(method, out key);
|
2012-08-07 21:26:16 +08:00
|
|
|
|
default:
|
|
|
|
|
key = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static bool FindKey5_v17_r74788(MethodDef method, out uint key) {
|
2012-08-07 21:26:16 +08:00
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
for (int i = 0; i < instrs.Count; i++) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
i = ConfuserUtils.FindCallMethod(instrs, i, Code.Callvirt, "System.Reflection.Module System.Reflection.Assembly::GetModule(System.String)");
|
2012-08-07 21:26:16 +08:00
|
|
|
|
if (i < 0)
|
|
|
|
|
break;
|
|
|
|
|
if (i + 1 >= instrs.Count)
|
|
|
|
|
break;
|
|
|
|
|
var ldci4 = instrs[i + 1];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldci4.IsLdcI4())
|
2012-08-07 21:26:16 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
key = (uint)ldci4.GetLdcI4Value();
|
2012-08-07 21:26:16 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
key = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Detected {
|
|
|
|
|
get { return initMethod != null; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
public ConstantsDecrypterV17(ModuleDefMD module, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator)
|
2012-08-07 20:40:51 +08:00
|
|
|
|
: base(module, fileData, simpleDeobfuscator) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static readonly string[] requiredLocalsCctor = new string[] {
|
|
|
|
|
"System.Reflection.Assembly",
|
|
|
|
|
"System.IO.Compression.DeflateStream",
|
|
|
|
|
"System.Byte[]",
|
|
|
|
|
"System.Int32",
|
|
|
|
|
};
|
2013-01-19 20:09:49 +08:00
|
|
|
|
public void Find() {
|
|
|
|
|
var cctor = DotNetUtils.GetModuleTypeCctor(module);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
if (cctor == null)
|
|
|
|
|
return;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!new LocalTypes(cctor).All(requiredLocalsCctor))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return;
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
simpleDeobfuscator.Deobfuscate(cctor, true);
|
|
|
|
|
if (!Add(ConstantsDecrypterUtils.FindDictField(cctor, cctor.DeclaringType)))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!Add(ConstantsDecrypterUtils.FindStreamField(cctor, cctor.DeclaringType)))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return;
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
var method = GetDecryptMethod();
|
2012-08-07 20:40:51 +08:00
|
|
|
|
if (method == null)
|
|
|
|
|
return;
|
2012-08-07 23:51:43 +08:00
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
resourceName = GetResourceName(cctor);
|
2012-08-07 23:51:43 +08:00
|
|
|
|
|
2012-08-08 03:57:14 +08:00
|
|
|
|
if (resourceName != null) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
simpleDeobfuscator.Deobfuscate(method);
|
|
|
|
|
keyArraySize = GetKeyArraySize(method);
|
2012-08-08 03:57:14 +08:00
|
|
|
|
if (keyArraySize == 8)
|
2013-01-19 20:09:49 +08:00
|
|
|
|
InitVersion(method, ConfuserVersion.v17_r75056_normal, ConfuserVersion.v17_r75056_dynamic, ConfuserVersion.v17_r75056_native);
|
2012-08-08 03:57:14 +08:00
|
|
|
|
else if (keyArraySize == 16)
|
2013-01-19 20:09:49 +08:00
|
|
|
|
InitVersion(method, ConfuserVersion.v18_r75257_normal, ConfuserVersion.v18_r75257_dynamic, ConfuserVersion.v18_r75257_native);
|
2012-08-08 03:57:14 +08:00
|
|
|
|
else
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-01-19 20:09:49 +08:00
|
|
|
|
else if (DotNetUtils.CallsMethod(method, "System.String System.Reflection.Module::get_ScopeName()"))
|
|
|
|
|
InitVersion(method, ConfuserVersion.v17_r74816_normal, ConfuserVersion.v17_r74816_dynamic, ConfuserVersion.v17_r74816_native);
|
|
|
|
|
else if (DotNetUtils.CallsMethod(method, "System.Reflection.Module System.Reflection.Assembly::GetModule(System.String)"))
|
|
|
|
|
InitVersion(method, ConfuserVersion.v17_r74788_normal, ConfuserVersion.v17_r74788_dynamic, ConfuserVersion.v17_r74788_native);
|
2012-08-07 21:26:16 +08:00
|
|
|
|
else
|
2013-01-19 20:09:49 +08:00
|
|
|
|
InitVersion(method, ConfuserVersion.v17_r74708_normal, ConfuserVersion.v17_r74708_dynamic, ConfuserVersion.v17_r74708_native);
|
2012-08-07 21:26:16 +08:00
|
|
|
|
|
|
|
|
|
initMethod = cctor;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
void InitVersion(MethodDef method, ConfuserVersion normal, ConfuserVersion dynamic, ConfuserVersion native) {
|
|
|
|
|
if (DeobUtils.HasInteger(method, 0x100) &&
|
|
|
|
|
DeobUtils.HasInteger(method, 0x10000) &&
|
|
|
|
|
DeobUtils.HasInteger(method, 0xFFFF))
|
2012-08-07 21:26:16 +08:00
|
|
|
|
version = normal;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
else if ((nativeMethod = FindNativeMethod(method)) == null)
|
2012-08-07 21:26:16 +08:00
|
|
|
|
version = dynamic;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
else
|
2012-08-07 21:26:16 +08:00
|
|
|
|
version = native;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
MethodDef GetDecryptMethod() {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
foreach (var type in module.Types) {
|
|
|
|
|
if (type.Attributes != (TypeAttributes.Abstract | TypeAttributes.Sealed))
|
|
|
|
|
continue;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!CheckMethods(type.Methods))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
foreach (var method in type.Methods) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.UInt32,System.UInt32)"))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return method;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
protected override byte[] DecryptData(DecrypterInfo info2, MethodDef caller, object[] args, out byte typeCode) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
var info = (DecrypterInfoV17)info2;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
uint offs = info.CalcHash(info2.decryptMethod.MDToken.ToUInt32() ^ (info2.decryptMethod.DeclaringType.MDToken.ToUInt32() * (uint)args[0])) ^ (uint)args[1];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
reader.Position = offs;
|
2012-08-07 20:40:51 +08:00
|
|
|
|
typeCode = reader.ReadByte();
|
|
|
|
|
if (typeCode != info.int32Type && typeCode != info.int64Type &&
|
|
|
|
|
typeCode != info.singleType && typeCode != info.doubleType &&
|
|
|
|
|
typeCode != info.stringType)
|
|
|
|
|
throw new ApplicationException("Invalid type code");
|
|
|
|
|
|
|
|
|
|
var encrypted = reader.ReadBytes(reader.ReadInt32());
|
2013-01-19 20:09:49 +08:00
|
|
|
|
return DecryptConstant(info, encrypted, offs, typeCode);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
switch (info.version) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
case ConfuserVersion.v17_r74708_normal: return DecryptConstant_v17_r74708_normal(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74708_dynamic: return DecryptConstant_v17_r74708_dynamic(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74708_native: return DecryptConstant_v17_r74708_native(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74788_normal: return DecryptConstant_v17_r74788_normal(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74788_dynamic: return DecryptConstant_v17_r74788_dynamic(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74788_native: return DecryptConstant_v17_r74788_native(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74816_normal: return DecryptConstant_v17_r74788_normal(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74816_dynamic: return DecryptConstant_v17_r74788_dynamic(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r74816_native: return DecryptConstant_v17_r74788_native(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r75056_normal: return DecryptConstant_v17_r74788_normal(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r75056_dynamic: return DecryptConstant_v17_r74788_dynamic(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v17_r75056_native: return DecryptConstant_v17_r74788_native(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v18_r75257_normal: return DecryptConstant_v17_r74788_normal(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v18_r75257_dynamic: return DecryptConstant_v17_r74788_dynamic(info, encrypted, offs, typeCode);
|
|
|
|
|
case ConfuserVersion.v18_r75257_native: return DecryptConstant_v17_r74788_native(info, encrypted, offs, typeCode);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
default:
|
|
|
|
|
throw new ApplicationException("Invalid version");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant_v17_r74708_normal(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
|
|
|
|
return ConfuserUtils.Decrypt(info.key4 * (offs + typeCode), encrypted);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant_v17_r74708_dynamic(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
|
|
|
|
return DecryptConstant_v17_r73740_dynamic(info, encrypted, offs, info.key4);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant_v17_r74708_native(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
|
|
|
|
return DecryptConstant_v17_r73764_native(info, encrypted, offs, info.key4);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant_v17_r74788_normal(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
|
|
|
|
return ConfuserUtils.Decrypt(info.key4 * (offs + typeCode), encrypted, GetKey_v17_r74788(info));
|
2012-08-07 21:26:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant_v17_r74788_dynamic(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
|
|
|
|
return DecryptConstant_v17_r73740_dynamic(info, encrypted, offs, info.key4, GetKey_v17_r74788(info));
|
2012-08-07 21:26:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] DecryptConstant_v17_r74788_native(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
|
|
|
|
return DecryptConstant_v17_r73764_native(info, encrypted, offs, info.key4, GetKey_v17_r74788(info));
|
2012-08-07 21:26:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
byte[] GetKey_v17_r74788(DecrypterInfoV17 info) {
|
2012-11-19 06:42:43 +08:00
|
|
|
|
var key = module.ReadBlob(info.decryptMethod.MDToken.ToUInt32() ^ info.key5);
|
2012-08-08 03:57:14 +08:00
|
|
|
|
if (key.Length != keyArraySize)
|
|
|
|
|
throw new ApplicationException("Invalid key size");
|
|
|
|
|
return key;
|
2012-08-07 21:26:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
public override void Initialize() {
|
2012-08-07 23:51:43 +08:00
|
|
|
|
if (resourceName != null)
|
2013-01-19 20:09:49 +08:00
|
|
|
|
resource = DotNetUtils.GetResource(module, resourceName) as EmbeddedResource;
|
2012-08-07 23:51:43 +08:00
|
|
|
|
else
|
2013-01-19 20:09:49 +08:00
|
|
|
|
resource = FindResource(initMethod);
|
2012-08-07 23:51:43 +08:00
|
|
|
|
if (resource == null)
|
2012-08-07 20:40:51 +08:00
|
|
|
|
throw new ApplicationException("Could not find encrypted consts resource");
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
FindDecrypterInfos();
|
|
|
|
|
InitializeDecrypterInfos();
|
2012-08-07 20:40:51 +08:00
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
SetConstantsData(DeobUtils.Inflate(resource.GetResourceData(), true));
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
void FindDecrypterInfos() {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
foreach (var type in module.Types) {
|
|
|
|
|
if (type.Attributes != (TypeAttributes.Abstract | TypeAttributes.Sealed))
|
|
|
|
|
continue;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!CheckMethods(type.Methods))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
foreach (var method in type.Methods) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.UInt32,System.UInt32)"))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var info = new DecrypterInfoV17(version, method);
|
2013-01-19 20:09:49 +08:00
|
|
|
|
Add(info);
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static bool CheckMethods(IEnumerable<MethodDef> methods) {
|
2012-08-07 20:40:51 +08:00
|
|
|
|
int numMethods = 0;
|
|
|
|
|
foreach (var method in methods) {
|
|
|
|
|
if (method.Name == ".ctor" || method.Name == ".cctor")
|
|
|
|
|
return false;
|
|
|
|
|
if (method.Attributes != (MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.CompilerControlled))
|
|
|
|
|
return false;
|
2013-01-19 20:09:49 +08:00
|
|
|
|
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.UInt32,System.UInt32)"))
|
2012-08-07 20:40:51 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
numMethods++;
|
|
|
|
|
}
|
|
|
|
|
return numMethods > 0;
|
|
|
|
|
}
|
2012-08-07 23:51:43 +08:00
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static string GetResourceName(MethodDef method) {
|
2012-08-07 23:51:43 +08:00
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
for (int i = 0; i < instrs.Count; i++) {
|
2013-01-19 20:09:49 +08:00
|
|
|
|
i = ConfuserUtils.FindCallMethod(instrs, i, Code.Call, "System.Byte[] System.BitConverter::GetBytes(System.Int32)");
|
2012-08-07 23:51:43 +08:00
|
|
|
|
if (i < 0)
|
|
|
|
|
break;
|
|
|
|
|
if (i == 0)
|
|
|
|
|
continue;
|
|
|
|
|
var ldci4 = instrs[i - 1];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldci4.IsLdcI4())
|
2012-08-07 23:51:43 +08:00
|
|
|
|
continue;
|
2012-11-19 06:42:43 +08:00
|
|
|
|
return Encoding.UTF8.GetString(BitConverter.GetBytes(ldci4.GetLdcI4Value()));
|
2012-08-07 23:51:43 +08:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2012-08-08 03:57:14 +08:00
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
static int GetKeyArraySize(MethodDef method) {
|
2012-08-08 03:57:14 +08:00
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
for (int i = 0; i < instrs.Count - 4; i++) {
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!instrs[i].IsLdloc())
|
2012-08-08 03:57:14 +08:00
|
|
|
|
continue;
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!instrs[i + 1].IsLdloc())
|
2012-08-08 03:57:14 +08:00
|
|
|
|
continue;
|
|
|
|
|
var ldci4 = instrs[i + 2];
|
2012-11-19 06:42:43 +08:00
|
|
|
|
if (!ldci4.IsLdcI4())
|
2012-08-08 03:57:14 +08:00
|
|
|
|
continue;
|
|
|
|
|
if (instrs[i + 3].OpCode.Code != Code.Rem)
|
|
|
|
|
continue;
|
|
|
|
|
if (instrs[i + 4].OpCode.Code != Code.Ldelem_U1)
|
|
|
|
|
continue;
|
|
|
|
|
|
2012-11-19 06:42:43 +08:00
|
|
|
|
return ldci4.GetLdcI4Value();
|
2012-08-08 03:57:14 +08:00
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2012-08-09 17:47:18 +08:00
|
|
|
|
|
2013-01-19 20:09:49 +08:00
|
|
|
|
public override bool GetRevisionRange(out int minRev, out int maxRev) {
|
2012-08-09 17:47:18 +08:00
|
|
|
|
switch (version) {
|
|
|
|
|
case ConfuserVersion.Unknown:
|
|
|
|
|
minRev = maxRev = 0;
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case ConfuserVersion.v17_r74708_normal:
|
|
|
|
|
case ConfuserVersion.v17_r74708_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74708_native:
|
|
|
|
|
minRev = 74708;
|
|
|
|
|
maxRev = 74708;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case ConfuserVersion.v17_r74788_normal:
|
|
|
|
|
case ConfuserVersion.v17_r74788_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74788_native:
|
|
|
|
|
minRev = 74788;
|
|
|
|
|
maxRev = 74788;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case ConfuserVersion.v17_r74816_normal:
|
|
|
|
|
case ConfuserVersion.v17_r74816_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r74816_native:
|
|
|
|
|
minRev = 74816;
|
|
|
|
|
maxRev = 74852;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case ConfuserVersion.v17_r75056_normal:
|
|
|
|
|
case ConfuserVersion.v17_r75056_dynamic:
|
|
|
|
|
case ConfuserVersion.v17_r75056_native:
|
|
|
|
|
minRev = 75056;
|
|
|
|
|
maxRev = 75184;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case ConfuserVersion.v18_r75257_normal:
|
|
|
|
|
case ConfuserVersion.v18_r75257_dynamic:
|
|
|
|
|
case ConfuserVersion.v18_r75257_native:
|
|
|
|
|
minRev = 75257;
|
|
|
|
|
maxRev = 75349;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default: throw new ApplicationException("Invalid version");
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-07 20:40:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|