diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index a1c6b5df..3817a0cf 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -75,6 +75,7 @@
+
diff --git a/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs b/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs
index 8bc4ea9e..9a7d8d95 100644
--- a/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs
+++ b/de4dot.code/deobfuscators/Confuser/ConfuserUtils.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);
}
diff --git a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterBase.cs b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterBase.cs
index 1a351f2f..454c7993 100644
--- a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterBase.cs
+++ b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterBase.cs
@@ -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 methodToDecrypterInfo = new MethodDefinitionAndDeclaringTypeDict();
FieldDefinitionAndDeclaringTypeDict fields = new FieldDefinitionAndDeclaringTypeDict();
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 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;
diff --git a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterUtils.cs b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterUtils.cs
index 77269fa9..225d7f0b 100644
--- a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterUtils.cs
+++ b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterUtils.cs
@@ -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;
diff --git a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV15.cs b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV15.cs
index d13b4301..11ffbb9f 100644
--- a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV15.cs
+++ b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV15.cs
@@ -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 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;
- }
}
}
diff --git a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs
new file mode 100644
index 00000000..ee240bbd
--- /dev/null
+++ b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs
@@ -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 .
+*/
+
+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 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;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs b/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs
index 6ae257a3..ee60d834 100644
--- a/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs
@@ -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");
}