Support Confuser 1.7 r74708 constants encrypter
This commit is contained in:
parent
9db99626f2
commit
6baa3f0e2f
|
@ -75,6 +75,7 @@
|
|||
<Compile Include="deobfuscators\Confuser\ConstantsDecrypterBase.cs" />
|
||||
<Compile Include="deobfuscators\Confuser\ConstantsDecrypterUtils.cs" />
|
||||
<Compile Include="deobfuscators\Confuser\ConstantsDecrypterV15.cs" />
|
||||
<Compile Include="deobfuscators\Confuser\ConstantsDecrypterV17.cs" />
|
||||
<Compile Include="deobfuscators\Confuser\ConstantsFolder.cs" />
|
||||
<Compile Include="deobfuscators\Confuser\ConstantsInliner.cs" />
|
||||
<Compile Include="deobfuscators\Confuser\Deobfuscator.cs" />
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
ushort _c = (ushort)seed;
|
||||
ushort m = _c; ushort c = _m;
|
||||
for (int i = 0; i < decrypted.Length; i++) {
|
||||
decrypted[i] = (byte)(encrypted[i] ^ ((seed * m + c) & 0xFF));
|
||||
decrypted[i] = (byte)(encrypted[i] ^ (seed * m + c));
|
||||
m = (ushort)(seed * m + _m);
|
||||
c = (ushort)(seed * c + _c);
|
||||
}
|
||||
|
|
|
@ -24,12 +24,14 @@ using System.Text;
|
|||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
using de4dot.PE;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Confuser {
|
||||
abstract class ConstantsDecrypterBase {
|
||||
protected ModuleDefinition module;
|
||||
protected byte[] fileData;
|
||||
protected ISimpleDeobfuscator simpleDeobfuscator;
|
||||
protected MethodDefinition nativeMethod;
|
||||
MethodDefinitionAndDeclaringTypeDict<DecrypterInfo> methodToDecrypterInfo = new MethodDefinitionAndDeclaringTypeDict<DecrypterInfo>();
|
||||
FieldDefinitionAndDeclaringTypeDict<bool> fields = new FieldDefinitionAndDeclaringTypeDict<bool>();
|
||||
protected EmbeddedResource resource;
|
||||
|
@ -37,7 +39,6 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
|
||||
public class DecrypterInfo {
|
||||
public MethodDefinition decryptMethod;
|
||||
public MethodDefinition nativeMethod;
|
||||
public uint key0, key1, key2, key3;
|
||||
public byte doubleType, singleType, int32Type, int64Type, stringType;
|
||||
|
||||
|
@ -48,7 +49,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
throw new ApplicationException("Could not find all type codes");
|
||||
}
|
||||
|
||||
bool initializeKeys() {
|
||||
protected virtual bool initializeKeys() {
|
||||
if (!findKey0(decryptMethod, out key0))
|
||||
return false;
|
||||
if (!findKey1(decryptMethod, out key1))
|
||||
|
@ -59,7 +60,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool findKey0(MethodDefinition method, out uint key) {
|
||||
protected static bool findKey0(MethodDefinition method, out uint key) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 5; i++) {
|
||||
if (!DotNetUtils.isLdloc(instrs[i]))
|
||||
|
@ -104,7 +105,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool findKey2Key3(MethodDefinition method, out uint key2, out uint key3) {
|
||||
protected static bool findKey2Key3(MethodDefinition method, out uint key2, out uint key3) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 3; i++) {
|
||||
var ldci4_1 = instrs[i];
|
||||
|
@ -231,6 +232,10 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
|
||||
public abstract bool Detected { get; }
|
||||
|
||||
public MethodDefinition NativeMethod {
|
||||
get { return nativeMethod; }
|
||||
}
|
||||
|
||||
public EmbeddedResource Resource {
|
||||
get { return resource; }
|
||||
}
|
||||
|
@ -273,6 +278,129 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
}
|
||||
}
|
||||
|
||||
protected void setConstantsData(byte[] constants) {
|
||||
reader = new BinaryReader(new MemoryStream(constants));
|
||||
}
|
||||
|
||||
protected EmbeddedResource findResource(MethodDefinition method) {
|
||||
return DotNetUtils.getResource(module, DotNetUtils.getCodeStrings(method)) as EmbeddedResource;
|
||||
}
|
||||
|
||||
protected static MethodDefinition findNativeMethod(MethodDefinition method) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
var call = instrs[i];
|
||||
if (call.OpCode.Code != Code.Call)
|
||||
continue;
|
||||
var calledMethod = call.Operand as MethodDefinition;
|
||||
if (calledMethod == null || !calledMethod.IsStatic || !calledMethod.IsNative)
|
||||
continue;
|
||||
if (!DotNetUtils.isMethod(calledMethod, "System.Int32", "(System.Int32)"))
|
||||
continue;
|
||||
|
||||
return calledMethod;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static VariableDefinition getDynamicLocal_v17_r73740(MethodDefinition method) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
i = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Byte System.IO.BinaryReader::ReadByte()");
|
||||
if (i < 0 || i + 5 >= instrs.Count)
|
||||
break;
|
||||
if (!DotNetUtils.isStloc(instrs[i + 1]))
|
||||
continue;
|
||||
var ldloc = instrs[i + 2];
|
||||
if (!DotNetUtils.isLdloc(ldloc))
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 3]))
|
||||
continue;
|
||||
var ldci4 = instrs[i + 4];
|
||||
if (!DotNetUtils.isLdcI4(ldci4) || DotNetUtils.getLdcI4Value(ldci4) != 0x7F)
|
||||
continue;
|
||||
if (instrs[i + 5].OpCode.Code != Code.And)
|
||||
continue;
|
||||
|
||||
return DotNetUtils.getLocalVar(method.Body.Variables, ldloc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static int getDynamicEndIndex_v17_r73740(MethodDefinition method, VariableDefinition local) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 5; i++) {
|
||||
var stloc = instrs[i];
|
||||
if (!DotNetUtils.isStloc(stloc) || DotNetUtils.getLocalVar(method.Body.Variables, stloc) != local)
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 1]))
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 2]))
|
||||
continue;
|
||||
var ldloc = instrs[i + 3];
|
||||
if (!DotNetUtils.isLdloc(ldloc) || DotNetUtils.getLocalVar(method.Body.Variables, ldloc) != local)
|
||||
continue;
|
||||
if (instrs[i + 4].OpCode.Code != Code.Conv_U1)
|
||||
continue;
|
||||
if (instrs[i + 5].OpCode.Code != Code.Stelem_I1)
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int getDynamicStartIndex_v17_r73740(MethodDefinition method, int endIndex) {
|
||||
if (endIndex < 0)
|
||||
return -1;
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = endIndex; i >= 0; i--) {
|
||||
if (i == 0)
|
||||
return i == endIndex ? -1 : i + 1;
|
||||
if (instrs[i].OpCode.FlowControl == FlowControl.Next)
|
||||
continue;
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected byte[] decryptConstant_v17_r73740_dynamic(DecrypterInfo info, byte[] encrypted, uint offs, uint key) {
|
||||
var local = getDynamicLocal_v17_r73740(info.decryptMethod);
|
||||
if (local == null)
|
||||
throw new ApplicationException("Could not find local");
|
||||
|
||||
int endIndex = getDynamicEndIndex_v17_r73740(info.decryptMethod, local);
|
||||
int startIndex = getDynamicStartIndex_v17_r73740(info.decryptMethod, endIndex);
|
||||
if (startIndex < 0)
|
||||
throw new ApplicationException("Could not find start/end index");
|
||||
|
||||
var constReader = new ConstantsReader(info.decryptMethod);
|
||||
return decrypt(encrypted, key, magic => {
|
||||
constReader.setConstantInt32(local, magic);
|
||||
int index = startIndex, result;
|
||||
if (!constReader.getNextInt32(ref index, out result) || index != endIndex)
|
||||
throw new ApplicationException("Could not decrypt integer");
|
||||
return (byte)result;
|
||||
});
|
||||
}
|
||||
|
||||
protected byte[] decryptConstant_v17_r73764_native(DecrypterInfo info, byte[] encrypted, uint offs, uint key) {
|
||||
var x86Emu = new x86Emulator(new PeImage(fileData));
|
||||
return decrypt(encrypted, key, magic => (byte)x86Emu.emulate((uint)nativeMethod.RVA, magic));
|
||||
}
|
||||
|
||||
static byte[] decrypt(byte[] encrypted, uint key, Func<uint, byte> decryptFunc) {
|
||||
var reader = new BinaryReader(new MemoryStream(encrypted));
|
||||
var decrypted = new byte[reader.ReadInt32() ^ key];
|
||||
for (int i = 0; i < decrypted.Length; i++) {
|
||||
uint magic = Utils.readEncodedUInt32(reader);
|
||||
decrypted[i] = decryptFunc(magic);
|
||||
}
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
public object decryptInt32(MethodDefinition caller, MethodDefinition decryptMethod, object[] args) {
|
||||
var info = methodToDecrypterInfo.find(decryptMethod);
|
||||
byte typeCode;
|
||||
|
|
|
@ -71,6 +71,14 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
}
|
||||
|
||||
public static FieldDefinition findStreamField(MethodDefinition method, TypeDefinition declaringType) {
|
||||
return findStreamField(method, declaringType, "System.IO.Stream");
|
||||
}
|
||||
|
||||
public static FieldDefinition findMemoryStreamField(MethodDefinition method, TypeDefinition declaringType) {
|
||||
return findStreamField(method, declaringType, "System.IO.MemoryStream");
|
||||
}
|
||||
|
||||
public static FieldDefinition findStreamField(MethodDefinition method, TypeDefinition declaringType, string fieldTypeName) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var newobj = instrs[i];
|
||||
|
@ -86,7 +94,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
var field = stsfld.Operand as FieldDefinition;
|
||||
if (field == null || field.DeclaringType != declaringType)
|
||||
continue;
|
||||
if (field.FieldType.FullName != "System.IO.MemoryStream")
|
||||
if (field.FieldType.FullName != fieldTypeName)
|
||||
continue;
|
||||
|
||||
return field;
|
||||
|
|
|
@ -23,7 +23,6 @@ using System.IO;
|
|||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
using de4dot.PE;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Confuser {
|
||||
class ConstantsDecrypterV15 : ConstantsDecrypterBase {
|
||||
|
@ -91,7 +90,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
version = ConfuserVersion.v17_r73740_dynamic;
|
||||
}
|
||||
else if (DotNetUtils.callsMethod(method, "System.String System.Text.Encoding::GetString(System.Byte[],System.Int32,System.Int32)")) {
|
||||
if ((info.nativeMethod = findNativeMethod(method)) == null)
|
||||
if ((nativeMethod = findNativeMethod(method)) == null)
|
||||
version = ConfuserVersion.v17_r73764_dynamic;
|
||||
else
|
||||
version = ConfuserVersion.v17_r73764_native;
|
||||
|
@ -104,7 +103,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
DeobUtils.hasInteger(method, 0x10000) &&
|
||||
DeobUtils.hasInteger(method, 0xFFFF))
|
||||
version = ConfuserVersion.v17_r73822_normal;
|
||||
else if ((info.nativeMethod = findNativeMethod(method)) == null)
|
||||
else if ((nativeMethod = findNativeMethod(method)) == null)
|
||||
version = ConfuserVersion.v17_r73822_dynamic;
|
||||
else
|
||||
version = ConfuserVersion.v17_r73822_native;
|
||||
|
@ -119,23 +118,6 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
}
|
||||
}
|
||||
|
||||
static MethodDefinition findNativeMethod(MethodDefinition method) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
var call = instrs[i];
|
||||
if (call.OpCode.Code != Code.Call)
|
||||
continue;
|
||||
var calledMethod = call.Operand as MethodDefinition;
|
||||
if (calledMethod == null || !calledMethod.IsStatic || !calledMethod.IsNative)
|
||||
continue;
|
||||
if (!DotNetUtils.isMethod(calledMethod, "System.Int32", "(System.Int32)"))
|
||||
continue;
|
||||
|
||||
return calledMethod;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void initialize() {
|
||||
if ((resource = findResource(theDecrypterInfo.decryptMethod)) == null)
|
||||
throw new ApplicationException("Could not find encrypted consts resource");
|
||||
|
@ -144,8 +126,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
if (!initializeFields(theDecrypterInfo))
|
||||
throw new ApplicationException("Could not find all fields");
|
||||
|
||||
var constants = DeobUtils.inflate(resource.GetResourceData(), true);
|
||||
reader = new BinaryReader(new MemoryStream(constants));
|
||||
setConstantsData(DeobUtils.inflate(resource.GetResourceData(), true));
|
||||
}
|
||||
|
||||
bool initializeFields(DecrypterInfo info) {
|
||||
|
@ -155,7 +136,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v17_r73822_native:
|
||||
if (!add(ConstantsDecrypterUtils.findDictField(info.decryptMethod, info.decryptMethod.DeclaringType)))
|
||||
return false;
|
||||
if (!add(ConstantsDecrypterUtils.findStreamField(info.decryptMethod, info.decryptMethod.DeclaringType)))
|
||||
if (!add(ConstantsDecrypterUtils.findMemoryStreamField(info.decryptMethod, info.decryptMethod.DeclaringType)))
|
||||
return false;
|
||||
break;
|
||||
|
||||
|
@ -166,10 +147,6 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return true;
|
||||
}
|
||||
|
||||
EmbeddedResource findResource(MethodDefinition method) {
|
||||
return DotNetUtils.getResource(module, DotNetUtils.getCodeStrings(method)) as EmbeddedResource;
|
||||
}
|
||||
|
||||
protected override byte[] decryptData(DecrypterInfo info, MethodDefinition caller, object[] args, out byte typeCode) {
|
||||
uint offs = info.calcHash(caller.MetadataToken.ToUInt32()) ^ (uint)args[0];
|
||||
reader.BaseStream.Position = offs;
|
||||
|
@ -188,12 +165,12 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v15_r60785_normal: return decryptConstant_v15_r60785_normal(info, encrypted, offs);
|
||||
case ConfuserVersion.v15_r60785_dynamic: return decryptConstant_v15_r60785_dynamic(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73404_normal: return decryptConstant_v17_r73404_normal(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73740_dynamic: return decryptConstant_v17_r73740_dynamic(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73764_dynamic: return decryptConstant_v17_r73740_dynamic(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73764_native: return decryptConstant_v17_r73764_native(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73740_dynamic: return decryptConstant_v17_r73740_dynamic(info, encrypted, offs, 0);
|
||||
case ConfuserVersion.v17_r73764_dynamic: return decryptConstant_v17_r73740_dynamic(info, encrypted, offs, 0);
|
||||
case ConfuserVersion.v17_r73764_native: return decryptConstant_v17_r73764_native(info, encrypted, offs, 0);
|
||||
case ConfuserVersion.v17_r73822_normal: return decryptConstant_v17_r73404_normal(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73822_dynamic: return decryptConstant_v17_r73740_dynamic(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73822_native: return decryptConstant_v17_r73764_native(info, encrypted, offs);
|
||||
case ConfuserVersion.v17_r73822_dynamic: return decryptConstant_v17_r73740_dynamic(info, encrypted, offs, 0);
|
||||
case ConfuserVersion.v17_r73822_native: return decryptConstant_v17_r73764_native(info, encrypted, offs, 0);
|
||||
default: throw new ApplicationException("Invalid version");
|
||||
}
|
||||
}
|
||||
|
@ -254,103 +231,5 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
byte[] decryptConstant_v17_r73404_normal(DecrypterInfo info, byte[] encrypted, uint offs) {
|
||||
return ConfuserUtils.decrypt(info.key0 ^ offs, encrypted);
|
||||
}
|
||||
|
||||
static VariableDefinition getDynamicLocal_v17_r73740(MethodDefinition method) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
i = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Byte System.IO.BinaryReader::ReadByte()");
|
||||
if (i < 0 || i + 5 >= instrs.Count)
|
||||
break;
|
||||
if (!DotNetUtils.isStloc(instrs[i + 1]))
|
||||
continue;
|
||||
var ldloc = instrs[i + 2];
|
||||
if (!DotNetUtils.isLdloc(ldloc))
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 3]))
|
||||
continue;
|
||||
var ldci4 = instrs[i + 4];
|
||||
if (!DotNetUtils.isLdcI4(ldci4) || DotNetUtils.getLdcI4Value(ldci4) != 0x7F)
|
||||
continue;
|
||||
if (instrs[i + 5].OpCode.Code != Code.And)
|
||||
continue;
|
||||
|
||||
return DotNetUtils.getLocalVar(method.Body.Variables, ldloc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static int getDynamicEndIndex_v17_r73740(MethodDefinition method, VariableDefinition local) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 5; i++) {
|
||||
var stloc = instrs[i];
|
||||
if (!DotNetUtils.isStloc(stloc) || DotNetUtils.getLocalVar(method.Body.Variables, stloc) != local)
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 1]))
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 2]))
|
||||
continue;
|
||||
var ldloc = instrs[i + 3];
|
||||
if (!DotNetUtils.isLdloc(ldloc) || DotNetUtils.getLocalVar(method.Body.Variables, ldloc) != local)
|
||||
continue;
|
||||
if (instrs[i + 4].OpCode.Code != Code.Conv_U1)
|
||||
continue;
|
||||
if (instrs[i + 5].OpCode.Code != Code.Stelem_I1)
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int getDynamicStartIndex_v17_r73740(MethodDefinition method, int endIndex) {
|
||||
if (endIndex < 0)
|
||||
return -1;
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = endIndex; i >= 0; i--) {
|
||||
if (i == 0)
|
||||
return i == endIndex ? -1 : i + 1;
|
||||
if (instrs[i].OpCode.FlowControl == FlowControl.Next)
|
||||
continue;
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
byte[] decryptConstant_v17_r73740_dynamic(DecrypterInfo info, byte[] encrypted, uint offs) {
|
||||
var local = getDynamicLocal_v17_r73740(info.decryptMethod);
|
||||
if (local == null)
|
||||
throw new ApplicationException("Could not find local");
|
||||
|
||||
int endIndex = getDynamicEndIndex_v17_r73740(info.decryptMethod, local);
|
||||
int startIndex = getDynamicStartIndex_v17_r73740(info.decryptMethod, endIndex);
|
||||
if (startIndex < 0)
|
||||
throw new ApplicationException("Could not find start/end index");
|
||||
|
||||
var constReader = new ConstantsReader(info.decryptMethod);
|
||||
return decrypt(encrypted, magic => {
|
||||
constReader.setConstantInt32(local, magic);
|
||||
int index = startIndex, result;
|
||||
if (!constReader.getNextInt32(ref index, out result) || index != endIndex)
|
||||
throw new ApplicationException("Could not decrypt integer");
|
||||
return (byte)result;
|
||||
});
|
||||
}
|
||||
|
||||
byte[] decryptConstant_v17_r73764_native(DecrypterInfo info, byte[] encrypted, uint offs) {
|
||||
var x86Emu = new x86Emulator(new PeImage(fileData));
|
||||
return decrypt(encrypted, magic => (byte)x86Emu.emulate((uint)info.nativeMethod.RVA, magic));
|
||||
}
|
||||
|
||||
byte[] decrypt(byte[] encrypted, Func<uint, byte> decryptFunc) {
|
||||
var reader = new BinaryReader(new MemoryStream(encrypted));
|
||||
var decrypted = new byte[reader.ReadInt32()];
|
||||
for (int i = 0; i < decrypted.Length; i++) {
|
||||
uint magic = Utils.readEncodedUInt32(reader);
|
||||
decrypted[i] = decryptFunc(magic);
|
||||
}
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
276
de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs
Normal file
276
de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Confuser {
|
||||
// Since v1.7 r74708
|
||||
class ConstantsDecrypterV17 : ConstantsDecrypterBase {
|
||||
MethodDefinition initMethod;
|
||||
ConfuserVersion version = ConfuserVersion.Unknown;
|
||||
|
||||
enum ConfuserVersion {
|
||||
Unknown,
|
||||
v17_r74708_normal,
|
||||
v17_r74708_dynamic,
|
||||
v17_r74708_native,
|
||||
}
|
||||
|
||||
class DecrypterInfoV17 : DecrypterInfo {
|
||||
public readonly ConfuserVersion version = ConfuserVersion.Unknown;
|
||||
public uint key4;
|
||||
|
||||
public DecrypterInfoV17(ConfuserVersion version, MethodDefinition decryptMethod) {
|
||||
this.version = version;
|
||||
this.decryptMethod = decryptMethod;
|
||||
}
|
||||
|
||||
protected override bool initializeKeys() {
|
||||
if (!findKey0(decryptMethod, out key0))
|
||||
return false;
|
||||
if (!findKey1_v17(decryptMethod, out key1))
|
||||
return false;
|
||||
if (!findKey2Key3(decryptMethod, out key2, out key3))
|
||||
return false;
|
||||
if (!findKey4(decryptMethod, out key4))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool findKey1_v17(MethodDefinition method, out uint key) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 4; i++) {
|
||||
var stloc = instrs[i];
|
||||
if (!DotNetUtils.isStloc(stloc))
|
||||
continue;
|
||||
var ldci4 = instrs[i + 1];
|
||||
if (!DotNetUtils.isLdcI4(ldci4))
|
||||
continue;
|
||||
var ldcloc = instrs[i + 2];
|
||||
if (!DotNetUtils.isLdloc(ldcloc))
|
||||
continue;
|
||||
if (DotNetUtils.getLocalVar(method.Body.Variables, stloc) != DotNetUtils.getLocalVar(method.Body.Variables, ldcloc))
|
||||
continue;
|
||||
if (instrs[i + 3].OpCode.Code != Code.Xor)
|
||||
continue;
|
||||
if (!DotNetUtils.isStloc(instrs[i + 4]))
|
||||
continue;
|
||||
|
||||
key = (uint)DotNetUtils.getLdcI4Value(ldci4);
|
||||
return true;
|
||||
}
|
||||
key = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findKey4(MethodDefinition method, out uint key) {
|
||||
switch (version) {
|
||||
case ConfuserVersion.v17_r74708_normal: return findKey4_normal(method, out key);
|
||||
case ConfuserVersion.v17_r74708_dynamic: return findKey4_other(method, out key);
|
||||
case ConfuserVersion.v17_r74708_native: return findKey4_other(method, out key);
|
||||
default:
|
||||
throw new ApplicationException("Invalid version");
|
||||
}
|
||||
}
|
||||
|
||||
static bool findKey4_normal(MethodDefinition method, out uint key) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 5; i++) {
|
||||
if (!DotNetUtils.isLdloc(instrs[i]))
|
||||
continue;
|
||||
if (!DotNetUtils.isLdloc(instrs[i + 1]))
|
||||
continue;
|
||||
if (instrs[i + 2].OpCode.Code != Code.Add)
|
||||
continue;
|
||||
var ldci4 = instrs[i + 3];
|
||||
if (!DotNetUtils.isLdcI4(ldci4))
|
||||
continue;
|
||||
if (instrs[i + 4].OpCode.Code != Code.Mul)
|
||||
continue;
|
||||
if (!DotNetUtils.isStloc(instrs[i + 5]))
|
||||
continue;
|
||||
|
||||
key = (uint)DotNetUtils.getLdcI4Value(ldci4);
|
||||
return true;
|
||||
}
|
||||
key = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool findKey4_other(MethodDefinition method, out uint key) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
int index = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Int32 System.IO.BinaryReader::ReadInt32()");
|
||||
if (index < 0)
|
||||
break;
|
||||
if (index + 1 >= instrs.Count)
|
||||
break;
|
||||
var ldci4 = instrs[index + 1];
|
||||
if (!DotNetUtils.isLdcI4(ldci4))
|
||||
continue;
|
||||
|
||||
key = (uint)DotNetUtils.getLdcI4Value(ldci4);
|
||||
return true;
|
||||
}
|
||||
key = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Detected {
|
||||
get { return initMethod != null; }
|
||||
}
|
||||
|
||||
public ConstantsDecrypterV17(ModuleDefinition module, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator)
|
||||
: base(module, fileData, simpleDeobfuscator) {
|
||||
}
|
||||
|
||||
static readonly string[] requiredLocalsCctor = new string[] {
|
||||
"System.Reflection.Assembly",
|
||||
"System.IO.Compression.DeflateStream",
|
||||
"System.Byte[]",
|
||||
"System.Int32",
|
||||
};
|
||||
public void find() {
|
||||
var cctor = DotNetUtils.getModuleTypeCctor(module);
|
||||
if (cctor == null)
|
||||
return;
|
||||
if (!new LocalTypes(cctor).all(requiredLocalsCctor))
|
||||
return;
|
||||
|
||||
simpleDeobfuscator.deobfuscate(cctor, true);
|
||||
if (!add(ConstantsDecrypterUtils.findDictField(cctor, cctor.DeclaringType)))
|
||||
return;
|
||||
if (!add(ConstantsDecrypterUtils.findStreamField(cctor, cctor.DeclaringType)))
|
||||
return;
|
||||
|
||||
var method = getDecryptMethod();
|
||||
if (method == null)
|
||||
return;
|
||||
if (DeobUtils.hasInteger(method, 0x100) &&
|
||||
DeobUtils.hasInteger(method, 0x10000) &&
|
||||
DeobUtils.hasInteger(method, 0xFFFF))
|
||||
version = ConfuserVersion.v17_r74708_normal;
|
||||
else if ((nativeMethod = findNativeMethod(method)) == null)
|
||||
version = ConfuserVersion.v17_r74708_dynamic;
|
||||
else
|
||||
version = ConfuserVersion.v17_r74708_native;
|
||||
|
||||
initMethod = cctor;
|
||||
}
|
||||
|
||||
MethodDefinition getDecryptMethod() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.Attributes != (TypeAttributes.Abstract | TypeAttributes.Sealed))
|
||||
continue;
|
||||
if (!checkMethods(type.Methods))
|
||||
continue;
|
||||
foreach (var method in type.Methods) {
|
||||
if (!DotNetUtils.isMethod(method, "System.Object", "(System.UInt32,System.UInt32)"))
|
||||
continue;
|
||||
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override byte[] decryptData(DecrypterInfo info2, MethodDefinition caller, object[] args, out byte typeCode) {
|
||||
var info = (DecrypterInfoV17)info2;
|
||||
uint offs = info.calcHash(info2.decryptMethod.MetadataToken.ToUInt32() ^ (info2.decryptMethod.DeclaringType.MetadataToken.ToUInt32() * (uint)args[0])) ^ (uint)args[1];
|
||||
reader.BaseStream.Position = offs;
|
||||
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());
|
||||
return decryptConstant(info, encrypted, offs, typeCode);
|
||||
}
|
||||
|
||||
byte[] decryptConstant(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
||||
switch (info.version) {
|
||||
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);
|
||||
default:
|
||||
throw new ApplicationException("Invalid version");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] decryptConstant_v17_r74708_normal(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
||||
return ConfuserUtils.decrypt(info.key4 * (offs + typeCode), encrypted);
|
||||
}
|
||||
|
||||
byte[] decryptConstant_v17_r74708_dynamic(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
||||
return decryptConstant_v17_r73740_dynamic(info, encrypted, offs, info.key4);
|
||||
}
|
||||
|
||||
byte[] decryptConstant_v17_r74708_native(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) {
|
||||
return decryptConstant_v17_r73764_native(info, encrypted, offs, info.key4);
|
||||
}
|
||||
|
||||
public override void initialize() {
|
||||
if ((resource = findResource(initMethod)) == null)
|
||||
throw new ApplicationException("Could not find encrypted consts resource");
|
||||
|
||||
findDecrypterInfos();
|
||||
initializeDecrypterInfos();
|
||||
|
||||
setConstantsData(DeobUtils.inflate(resource.GetResourceData(), true));
|
||||
}
|
||||
|
||||
void findDecrypterInfos() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.Attributes != (TypeAttributes.Abstract | TypeAttributes.Sealed))
|
||||
continue;
|
||||
if (!checkMethods(type.Methods))
|
||||
continue;
|
||||
foreach (var method in type.Methods) {
|
||||
if (!DotNetUtils.isMethod(method, "System.Object", "(System.UInt32,System.UInt32)"))
|
||||
continue;
|
||||
|
||||
var info = new DecrypterInfoV17(version, method);
|
||||
add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool checkMethods(IEnumerable<MethodDefinition> methods) {
|
||||
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;
|
||||
if (!DotNetUtils.isMethod(method, "System.Object", "(System.UInt32,System.UInt32)"))
|
||||
return false;
|
||||
|
||||
numMethods++;
|
||||
}
|
||||
return numMethods > 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,6 +80,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
ResourceDecrypter resourceDecrypter;
|
||||
ConstantsDecrypter constantsDecrypter;
|
||||
ConstantsDecrypterV15 constantsDecrypterV15;
|
||||
ConstantsDecrypterV17 constantsDecrypterV17;
|
||||
Int32ValueInliner int32ValueInliner;
|
||||
Int64ValueInliner int64ValueInliner;
|
||||
SingleValueInliner singleValueInliner;
|
||||
|
@ -140,6 +141,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
toInt32(resourceDecrypter != null ? resourceDecrypter.Detected : false) +
|
||||
toInt32(constantsDecrypter != null ? constantsDecrypter.Detected : false) +
|
||||
toInt32(constantsDecrypterV15 != null ? constantsDecrypterV15.Detected : false) +
|
||||
toInt32(constantsDecrypterV17 != null ? constantsDecrypterV17.Detected : false) +
|
||||
toInt32(stringDecrypter != null ? stringDecrypter.Detected : false) +
|
||||
toInt32(unpacker != null ? unpacker.Detected : false);
|
||||
if (sum > 0)
|
||||
|
@ -167,15 +169,28 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
void initTheRest() {
|
||||
resourceDecrypter = new ResourceDecrypter(module, DeobfuscatedFile);
|
||||
resourceDecrypter.find();
|
||||
|
||||
constantsDecrypter = new ConstantsDecrypter(module, getFileData(), DeobfuscatedFile);
|
||||
constantsDecrypter.find();
|
||||
constantsDecrypterV17 = new ConstantsDecrypterV17(module, getFileData(), DeobfuscatedFile);
|
||||
constantsDecrypterV15 = new ConstantsDecrypterV15(module, getFileData(), DeobfuscatedFile);
|
||||
if (!constantsDecrypter.Detected)
|
||||
do {
|
||||
constantsDecrypter.find();
|
||||
if (constantsDecrypter.Detected) {
|
||||
initializeConstantsDecrypter();
|
||||
break;
|
||||
}
|
||||
constantsDecrypterV17.find();
|
||||
if (constantsDecrypterV17.Detected) {
|
||||
initializeConstantsDecrypter17();
|
||||
break;
|
||||
}
|
||||
constantsDecrypterV15.find();
|
||||
if (constantsDecrypter.Detected)
|
||||
initializeConstantsDecrypter();
|
||||
else if (constantsDecrypterV15.Detected)
|
||||
initializeConstantsDecrypter15();
|
||||
if (constantsDecrypterV15.Detected) {
|
||||
initializeConstantsDecrypter15();
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
proxyCallFixer = new ProxyCallFixer(module, getFileData(), DeobfuscatedFile);
|
||||
proxyCallFixer.findDelegateCreator();
|
||||
if (!proxyCallFixer.Detected) {
|
||||
|
@ -431,6 +446,11 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
initialize(constantsDecrypterV15, ref hasInitializedConstantsDecrypter15);
|
||||
}
|
||||
|
||||
bool hasInitializedConstantsDecrypter17 = false;
|
||||
void initializeConstantsDecrypter17() {
|
||||
initialize(constantsDecrypterV17, ref hasInitializedConstantsDecrypter17);
|
||||
}
|
||||
|
||||
void initialize(ConstantsDecrypterBase constDecrypter, ref bool hasInitialized) {
|
||||
if (hasInitialized || (constDecrypter == null || !constDecrypter.Detected))
|
||||
return;
|
||||
|
@ -455,10 +475,14 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
doubleValueInliner.RemoveUnbox = true;
|
||||
DeobfuscatedFile.stringDecryptersAdded();
|
||||
addFieldsToBeRemoved(constDecrypter.Fields, "Constants decrypter field");
|
||||
var moduleType = DotNetUtils.getModuleType(module);
|
||||
foreach (var info in constDecrypter.DecrypterInfos) {
|
||||
addMethodToBeRemoved(info.decryptMethod, "Constants decrypter method");
|
||||
addMethodToBeRemoved(info.nativeMethod, "Constants decrypter native method");
|
||||
if (info.decryptMethod.DeclaringType == moduleType)
|
||||
addMethodToBeRemoved(info.decryptMethod, "Constants decrypter method");
|
||||
else
|
||||
addTypeToBeRemoved(info.decryptMethod.DeclaringType, "Constants decrypter type");
|
||||
}
|
||||
addMethodToBeRemoved(constDecrypter.NativeMethod, "Constants decrypter native method");
|
||||
addResourceToBeRemoved(constDecrypter.Resource, "Encrypted constants");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user