Support Confuser 1.9 r77172

This commit is contained in:
de4dot 2013-01-20 15:59:30 +01:00
parent 40083ad33a
commit 3eb7e5be41
7 changed files with 214 additions and 14 deletions

View File

@ -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;
}
}
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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;

View File

@ -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> {