Support Confuser 1.9 r77172
This commit is contained in:
parent
40083ad33a
commit
3eb7e5be41
|
@ -19,6 +19,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SevenZip.Compression.LZMA;
|
||||
using dnlib.IO;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
|
@ -171,5 +173,84 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static byte[] SevenZipDecompress(byte[] data) {
|
||||
var reader = new BinaryReader(new MemoryStream(data));
|
||||
var props = reader.ReadBytes(5);
|
||||
var decoder = new Decoder();
|
||||
decoder.SetDecoderProperties(props);
|
||||
long totalSize = reader.ReadInt64();
|
||||
long compressedSize = data.Length - props.Length - 8;
|
||||
var decompressed = new byte[totalSize];
|
||||
decoder.Code(reader.BaseStream, new MemoryStream(decompressed, true), compressedSize, totalSize, null);
|
||||
return decompressed;
|
||||
}
|
||||
|
||||
// Finds the Lzma type by finding an instruction that allocates a new Lzma.Decoder
|
||||
public static TypeDef FindLzmaType(MethodDef method) {
|
||||
if (method == null || method.Body == null)
|
||||
return null;
|
||||
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code != Code.Newobj)
|
||||
continue;
|
||||
var ctor = instr.Operand as MethodDef;
|
||||
if (ctor == null)
|
||||
continue;
|
||||
var ctorType = ctor.DeclaringType;
|
||||
if (ctorType == null)
|
||||
continue;
|
||||
if (!IsLzmaType(ctorType.DeclaringType))
|
||||
continue;
|
||||
|
||||
return ctorType.DeclaringType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool IsLzmaType(TypeDef type) {
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
if (type.NestedTypes.Count != 6)
|
||||
return false;
|
||||
if (!CheckLzmaMethods(type))
|
||||
return false;
|
||||
if (FindLzmaOutWindowType(type.NestedTypes) == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CheckLzmaMethods(TypeDef type) {
|
||||
int methods = 0;
|
||||
foreach (var m in type.Methods) {
|
||||
if (m.IsStaticConstructor)
|
||||
continue;
|
||||
if (m.IsInstanceConstructor) {
|
||||
if (m.MethodSig.GetParamCount() != 0)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
if (!DotNetUtils.IsMethod(m, "System.UInt32", "(System.UInt32)"))
|
||||
return false;
|
||||
methods++;
|
||||
}
|
||||
return methods == 1;
|
||||
}
|
||||
|
||||
static readonly string[] outWindowFields = new string[] {
|
||||
"System.Byte[]",
|
||||
"System.UInt32",
|
||||
"System.IO.Stream",
|
||||
};
|
||||
static TypeDef FindLzmaOutWindowType(IEnumerable<TypeDef> types) {
|
||||
foreach (var type in types) {
|
||||
if (new FieldTypes(type).Exactly(outWindowFields))
|
||||
return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static FieldDef FindDataField(MethodDef method, TypeDef declaringType) {
|
||||
public static FieldDef FindDataField_v18_r75367(MethodDef method, TypeDef declaringType) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var callvirt = instrs[i];
|
||||
|
@ -70,6 +70,31 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Normal ("safe") mode only (not dynamic or native)
|
||||
public static FieldDef FindDataField_v19_r77172(MethodDef method, TypeDef declaringType) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var ldloc = instrs[i];
|
||||
if (!ldloc.IsLdloc())
|
||||
continue;
|
||||
var local = ldloc.GetLocal(method.Body.Variables);
|
||||
if (local == null || local.Type.GetFullName() != "System.Byte[]")
|
||||
continue;
|
||||
|
||||
var stsfld = instrs[i + 1];
|
||||
if (stsfld.OpCode.Code != Code.Stsfld)
|
||||
continue;
|
||||
var field = stsfld.Operand as FieldDef;
|
||||
if (field == null || field.DeclaringType != declaringType)
|
||||
continue;
|
||||
if (field.FieldType.FullName != "System.Byte[]")
|
||||
continue;
|
||||
|
||||
return field;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FieldDef FindStreamField(MethodDef method, TypeDef declaringType) {
|
||||
return FindStreamField(method, declaringType, "System.IO.Stream");
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
MethodDefAndDeclaringTypeDict<DecrypterInfo> decrypters = new MethodDefAndDeclaringTypeDict<DecrypterInfo>();
|
||||
uint key0, key0d;
|
||||
MethodDef nativeMethod;
|
||||
TypeDef lzmaType;
|
||||
EmbeddedResource resource;
|
||||
byte[] constants;
|
||||
ConfuserVersion version = ConfuserVersion.Unknown;
|
||||
|
@ -50,6 +51,9 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
v18_r75369_normal,
|
||||
v18_r75369_dynamic,
|
||||
v18_r75369_native,
|
||||
v19_r77172_normal,
|
||||
v19_r77172_dynamic,
|
||||
v19_r77172_native,
|
||||
}
|
||||
|
||||
public class DecrypterInfo {
|
||||
|
@ -105,6 +109,9 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v18_r75369_normal:
|
||||
case ConfuserVersion.v18_r75369_dynamic:
|
||||
case ConfuserVersion.v18_r75369_native:
|
||||
case ConfuserVersion.v19_r77172_normal:
|
||||
case ConfuserVersion.v19_r77172_dynamic:
|
||||
case ConfuserVersion.v19_r77172_native:
|
||||
return Hash1(key0l * magic);
|
||||
default:
|
||||
throw new ApplicationException("Invalid version");
|
||||
|
@ -151,6 +158,10 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
get { return nativeMethod; }
|
||||
}
|
||||
|
||||
public TypeDef LzmaType {
|
||||
get { return lzmaType; }
|
||||
}
|
||||
|
||||
public EmbeddedResource Resource {
|
||||
get { return resource; }
|
||||
}
|
||||
|
@ -177,7 +188,9 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
|
||||
if ((dictField = ConstantsDecrypterUtils.FindDictField(cctor, cctor.DeclaringType)) == null)
|
||||
return;
|
||||
if ((dataField = ConstantsDecrypterUtils.FindDataField(cctor, cctor.DeclaringType)) == null)
|
||||
|
||||
if ((dataField = ConstantsDecrypterUtils.FindDataField_v18_r75367(cctor, cctor.DeclaringType)) == null &&
|
||||
(dataField = ConstantsDecrypterUtils.FindDataField_v19_r77172(cctor, cctor.DeclaringType)) == null)
|
||||
return;
|
||||
|
||||
nativeMethod = FindNativeMethod(cctor, cctor.DeclaringType);
|
||||
|
@ -189,8 +202,13 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
var info = new DecrypterInfo(this, method, ConfuserVersion.Unknown);
|
||||
if (FindKeys_v18_r75367(info))
|
||||
InitVersion(cctor, ConfuserVersion.v18_r75367_normal, ConfuserVersion.v18_r75367_dynamic, ConfuserVersion.v18_r75367_native);
|
||||
else if (FindKeys_v18_r75369(info))
|
||||
InitVersion(cctor, ConfuserVersion.v18_r75369_normal, ConfuserVersion.v18_r75369_dynamic, ConfuserVersion.v18_r75369_native);
|
||||
else if (FindKeys_v18_r75369(info)) {
|
||||
lzmaType = ConfuserUtils.FindLzmaType(cctor);
|
||||
if (lzmaType == null)
|
||||
InitVersion(cctor, ConfuserVersion.v18_r75369_normal, ConfuserVersion.v18_r75369_dynamic, ConfuserVersion.v18_r75369_native);
|
||||
else
|
||||
InitVersion(cctor, ConfuserVersion.v19_r77172_normal, ConfuserVersion.v19_r77172_dynamic, ConfuserVersion.v19_r77172_native);
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
|
@ -380,6 +398,9 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v18_r75369_normal:
|
||||
case ConfuserVersion.v18_r75369_dynamic:
|
||||
case ConfuserVersion.v18_r75369_native:
|
||||
case ConfuserVersion.v19_r77172_normal:
|
||||
case ConfuserVersion.v19_r77172_dynamic:
|
||||
case ConfuserVersion.v19_r77172_native:
|
||||
return FindKeys_v18_r75369(info);
|
||||
default:
|
||||
throw new ApplicationException("Invalid version");
|
||||
|
@ -541,18 +562,27 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return false;
|
||||
}
|
||||
|
||||
byte[] Decompress(byte[] compressed) {
|
||||
if (lzmaType != null)
|
||||
return ConfuserUtils.SevenZipDecompress(compressed);
|
||||
return DeobUtils.Inflate(compressed, true);
|
||||
}
|
||||
|
||||
byte[] DecryptResource(byte[] encrypted) {
|
||||
switch (version) {
|
||||
case ConfuserVersion.v18_r75367_normal:
|
||||
case ConfuserVersion.v18_r75369_normal:
|
||||
case ConfuserVersion.v19_r77172_normal:
|
||||
return DecryptResource_v18_r75367_normal(encrypted);
|
||||
|
||||
case ConfuserVersion.v18_r75367_dynamic:
|
||||
case ConfuserVersion.v18_r75369_dynamic:
|
||||
case ConfuserVersion.v19_r77172_dynamic:
|
||||
return DecryptResource_v18_r75367_dynamic(encrypted);
|
||||
|
||||
case ConfuserVersion.v18_r75367_native:
|
||||
case ConfuserVersion.v18_r75369_native:
|
||||
case ConfuserVersion.v19_r77172_native:
|
||||
return DecryptResource_v18_r75367_native(encrypted);
|
||||
|
||||
default:
|
||||
|
@ -567,7 +597,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
byte[] DecryptResource_v18_r75367_normal(byte[] encrypted) {
|
||||
var key = GetSigKey();
|
||||
var decrypted = ConfuserUtils.Decrypt(BitConverter.ToUInt32(key, 12) * (uint)key0, encrypted);
|
||||
return DeobUtils.Inflate(DeobUtils.AesDecrypt(decrypted, key, DeobUtils.Md5Sum(key)), true);
|
||||
return Decompress(DeobUtils.AesDecrypt(decrypted, key, DeobUtils.Md5Sum(key)));
|
||||
}
|
||||
|
||||
static int GetDynamicStartIndex(IList<Instruction> instrs, int ldlocIndex) {
|
||||
|
@ -645,9 +675,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
byte[] DecryptResource(byte[] encrypted, Func<uint, byte> decryptFunc) {
|
||||
var key = GetSigKey();
|
||||
|
||||
var decrypted = DeobUtils.AesDecrypt(encrypted, key, DeobUtils.Md5Sum(key));
|
||||
decrypted = DeobUtils.Inflate(decrypted, true);
|
||||
|
||||
byte[] decrypted = DecryptAndDecompress(encrypted, key);
|
||||
var reader = MemoryImageStream.Create(decrypted);
|
||||
var result = new MemoryStream();
|
||||
var writer = new BinaryWriter(result);
|
||||
|
@ -659,6 +687,16 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return result.ToArray();
|
||||
}
|
||||
|
||||
byte[] DecryptAndDecompress(byte[] encrypted, byte[] key) {
|
||||
byte[] iv = DeobUtils.Md5Sum(key);
|
||||
try {
|
||||
return Decompress(DeobUtils.AesDecrypt(encrypted, key, iv));
|
||||
}
|
||||
catch {
|
||||
return DeobUtils.AesDecrypt(Decompress(encrypted), key, iv);
|
||||
}
|
||||
}
|
||||
|
||||
static bool VerifyGenericArg(MethodSpec gim, ElementType etype) {
|
||||
if (gim == null)
|
||||
return false;
|
||||
|
@ -729,6 +767,13 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v18_r75369_dynamic:
|
||||
case ConfuserVersion.v18_r75369_native:
|
||||
minRev = 75369;
|
||||
maxRev = 77124;
|
||||
return true;
|
||||
|
||||
case ConfuserVersion.v19_r77172_normal:
|
||||
case ConfuserVersion.v19_r77172_dynamic:
|
||||
case ConfuserVersion.v19_r77172_native:
|
||||
minRev = 77172;
|
||||
maxRev = int.MaxValue;
|
||||
return true;
|
||||
|
||||
|
|
|
@ -461,6 +461,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
AddTypesToBeRemoved(constantsDecrypterV18.Types, "Constants decrypter type");
|
||||
AddFieldsToBeRemoved(constantsDecrypterV18.Fields, "Constants decrypter field");
|
||||
AddMethodToBeRemoved(constantsDecrypterV18.NativeMethod, "Constants decrypter native method");
|
||||
AddTypeToBeRemoved(constantsDecrypterV18.LzmaType, "LZMA type");
|
||||
AddResourceToBeRemoved(constantsDecrypterV18.Resource, "Encrypted constants");
|
||||
}
|
||||
|
||||
|
@ -516,6 +517,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
AddResourceToBeRemoved(rsrc, "Encrypted resources");
|
||||
AddMethodToBeRemoved(resourceDecrypter.Handler, "Resource decrypter handler");
|
||||
AddFieldsToBeRemoved(resourceDecrypter.Fields, "Resource decrypter field");
|
||||
AddTypeToBeRemoved(resourceDecrypter.LzmaType, "LZMA type");
|
||||
}
|
||||
|
||||
void RemoveObfuscatorAttribute() {
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
ISimpleDeobfuscator simpleDeobfuscator;
|
||||
MethodDef handler;
|
||||
MethodDef installMethod;
|
||||
TypeDef lzmaType;
|
||||
EmbeddedResource resource;
|
||||
Dictionary<FieldDef, bool> fields = new Dictionary<FieldDef, bool>();
|
||||
byte key0, key1;
|
||||
|
@ -42,6 +43,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
v17_r73822,
|
||||
v18_r75367,
|
||||
v18_r75369,
|
||||
v19_r77172,
|
||||
}
|
||||
|
||||
public IEnumerable<FieldDef> Fields {
|
||||
|
@ -52,6 +54,10 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
get { return handler; }
|
||||
}
|
||||
|
||||
public TypeDef LzmaType {
|
||||
get { return lzmaType; }
|
||||
}
|
||||
|
||||
public bool Detected {
|
||||
get { return handler != null; }
|
||||
}
|
||||
|
@ -103,8 +109,13 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
tmpVersion = ConfuserVersion.v17_r73822;
|
||||
else if (FindKey0_v18_r75367(tmpHandler, out key0) && FindKey1_v17_r73404(tmpHandler, out key1))
|
||||
tmpVersion = ConfuserVersion.v18_r75367;
|
||||
else if (FindKey0_v18_r75369(tmpHandler, out key0) && FindKey1_v18_r75369(tmpHandler, out key1))
|
||||
tmpVersion = ConfuserVersion.v18_r75369;
|
||||
else if (FindKey0_v18_r75369(tmpHandler, out key0) && FindKey1_v18_r75369(tmpHandler, out key1)) {
|
||||
lzmaType = ConfuserUtils.FindLzmaType(tmpHandler);
|
||||
if (lzmaType == null)
|
||||
tmpVersion = ConfuserVersion.v18_r75369;
|
||||
else
|
||||
tmpVersion = ConfuserVersion.v19_r77172;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -343,6 +354,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v17_r73822: return Decrypt_v17_r73404();
|
||||
case ConfuserVersion.v18_r75367: return Decrypt_v18_r75367();
|
||||
case ConfuserVersion.v18_r75369: return Decrypt_v18_r75367();
|
||||
case ConfuserVersion.v19_r77172: return Decrypt_v19_r77172();
|
||||
default: throw new ApplicationException("Unknown version");
|
||||
}
|
||||
}
|
||||
|
@ -381,6 +393,17 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
return reader.ReadBytes(reader.ReadInt32());
|
||||
}
|
||||
|
||||
byte[] Decrypt_v19_r77172() {
|
||||
var encrypted = resource.GetResourceData();
|
||||
byte k = key0;
|
||||
for (int i = 0; i < encrypted.Length; i++) {
|
||||
encrypted[i] ^= k;
|
||||
k *= key1;
|
||||
}
|
||||
var reader = new BinaryReader(new MemoryStream(ConfuserUtils.SevenZipDecompress(encrypted)));
|
||||
return reader.ReadBytes(reader.ReadInt32());
|
||||
}
|
||||
|
||||
public void Deobfuscate(Blocks blocks) {
|
||||
if (blocks.Method != installMethod)
|
||||
return;
|
||||
|
@ -415,6 +438,11 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
|
||||
case ConfuserVersion.v18_r75369:
|
||||
minRev = 75369;
|
||||
maxRev = 77124;
|
||||
return true;
|
||||
|
||||
case ConfuserVersion.v19_r77172:
|
||||
minRev = 77172;
|
||||
maxRev = int.MaxValue;
|
||||
return true;
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
v17_r75076,
|
||||
v18_r75184,
|
||||
v18_r75367,
|
||||
v19_r77172,
|
||||
}
|
||||
|
||||
public bool Detected {
|
||||
|
@ -170,8 +171,10 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
theVersion = ConfuserVersion.v17_r75076;
|
||||
else if (module.Name == "Stub.exe")
|
||||
theVersion = ConfuserVersion.v18_r75184;
|
||||
else
|
||||
else if (!IsGetLenToPosStateMethodPrivate(type))
|
||||
theVersion = ConfuserVersion.v18_r75367;
|
||||
else
|
||||
theVersion = ConfuserVersion.v19_r77172;
|
||||
}
|
||||
else if (IsDecryptMethod_v17_r73404(decyptMethod))
|
||||
theVersion = ConfuserVersion.v17_r73404;
|
||||
|
@ -201,6 +204,15 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
version = theVersion;
|
||||
}
|
||||
|
||||
static bool IsGetLenToPosStateMethodPrivate(TypeDef type) {
|
||||
foreach (var m in type.Methods) {
|
||||
if (!DotNetUtils.IsMethod(m, "System.UInt32", "(System.UInt32)"))
|
||||
continue;
|
||||
return m.IsPrivate;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FindEntryPointToken(ISimpleDeobfuscator simpleDeobfuscator, MethodDef cctor, MethodDef entryPoint, out uint token) {
|
||||
token = 0;
|
||||
ulong @base;
|
||||
|
@ -474,6 +486,7 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
case ConfuserVersion.v17_r75076: return Decrypt_v17_r75076(data);
|
||||
case ConfuserVersion.v18_r75184: return Decrypt_v17_r75076(data);
|
||||
case ConfuserVersion.v18_r75367: return Decrypt_v17_r75076(data);
|
||||
case ConfuserVersion.v19_r77172: return Decrypt_v17_r75076(data);
|
||||
default: throw new ApplicationException("Unknown version");
|
||||
}
|
||||
}
|
||||
|
@ -535,10 +548,10 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
var reader = new BinaryReader(new MemoryStream(data));
|
||||
byte[] key, iv;
|
||||
data = Decrypt_v15_r60785(reader, out key, out iv);
|
||||
return SevenzipDecompress(DeobUtils.AesDecrypt(data, key, iv));
|
||||
return SevenZipDecompress(DeobUtils.AesDecrypt(data, key, iv));
|
||||
}
|
||||
|
||||
static byte[] SevenzipDecompress(byte[] data) {
|
||||
static byte[] SevenZipDecompress(byte[] data) {
|
||||
var reader = new BinaryReader(new MemoryStream(data));
|
||||
int totalSize = reader.ReadInt32();
|
||||
var props = reader.ReadBytes(5);
|
||||
|
@ -628,6 +641,11 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
|
||||
case ConfuserVersion.v18_r75367:
|
||||
minRev = 75367;
|
||||
maxRev = 77124;
|
||||
return true;
|
||||
|
||||
case ConfuserVersion.v19_r77172:
|
||||
minRev = 77172;
|
||||
maxRev = int.MaxValue;
|
||||
return true;
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ namespace de4dot.code.deobfuscators.Confuser {
|
|||
75306, 75318, 75349, 75367, 75369, 75402, 75459, 75461,
|
||||
75573, 75719, 75720, 75725, 75806, 75807, 75926, 76101,
|
||||
76119, 76163, 76186, 76271, 76360, 76509, 76542, 76548,
|
||||
76558, 76580, 76656,
|
||||
76558, 76580, 76656, 76871, 76923, 76924, 76933, 76934,
|
||||
76972, 76974, 77124, 77172,
|
||||
};
|
||||
|
||||
static Dictionary<int, Version> revToVersion = new Dictionary<int, Version> {
|
||||
|
|
Loading…
Reference in New Issue
Block a user