From 64b48ec3152c83c3984349f11c70dc18aba11844 Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 7 Aug 2012 15:26:16 +0200 Subject: [PATCH] Support Confuser 1.7 r74788 constants encrypter --- .../deobfuscators/Confuser/ConfuserUtils.cs | 7 +- .../Confuser/ConstantsDecrypterBase.cs | 58 +++++++++++-- .../Confuser/ConstantsDecrypterV17.cs | 85 +++++++++++++++++-- 3 files changed, 134 insertions(+), 16 deletions(-) diff --git a/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs b/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs index 9a7d8d95..825a3c99 100644 --- a/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs +++ b/de4dot.code/deobfuscators/Confuser/ConfuserUtils.cs @@ -115,13 +115,18 @@ namespace de4dot.code.deobfuscators.Confuser { return decrypted; } + static readonly byte[] defaultDecryptKey = new byte[8]; public static byte[] decrypt(uint seed, byte[] encrypted) { + return decrypt(seed, encrypted, defaultDecryptKey); + } + + public static byte[] decrypt(uint seed, byte[] encrypted, byte[] key) { var decrypted = new byte[encrypted.Length]; ushort _m = (ushort)(seed >> 16); 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)); + decrypted[i] = (byte)(encrypted[i] ^ (seed * m + c) ^ key[i & 7]); 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 454c7993..a7ec3caa 100644 --- a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterBase.cs +++ b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterBase.cs @@ -350,6 +350,41 @@ namespace de4dot.code.deobfuscators.Confuser { return -1; } + static int getDynamicEndIndex_v17_r74788(MethodDefinition method, VariableDefinition local) { + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count - 11; 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; + if (!DotNetUtils.isLdloc(instrs[i + 3])) + continue; + if (!DotNetUtils.isLdloc(instrs[i + 4])) + continue; + if (!DotNetUtils.isLdloc(instrs[i + 5])) + continue; + var ldci4 = instrs[i + 6]; + if (!DotNetUtils.isLdcI4(ldci4) || DotNetUtils.getLdcI4Value(ldci4) != 8) + continue; + if (instrs[i + 7].OpCode.Code != Code.Rem) + continue; + if (instrs[i + 8].OpCode.Code != Code.Ldelem_U1) + continue; + if (instrs[i + 9].OpCode.Code != Code.Xor) + continue; + if (instrs[i + 10].OpCode.Code != Code.Conv_U1) + continue; + if (instrs[i + 11].OpCode.Code != Code.Stelem_I1) + continue; + + return i; + } + return -1; + } + static int getDynamicStartIndex_v17_r73740(MethodDefinition method, int endIndex) { if (endIndex < 0) return -1; @@ -365,37 +400,48 @@ namespace de4dot.code.deobfuscators.Confuser { return -1; } + static readonly byte[] defaultDecryptKey_v17 = new byte[8]; protected byte[] decryptConstant_v17_r73740_dynamic(DecrypterInfo info, byte[] encrypted, uint offs, uint key) { + return decryptConstant_v17_r73740_dynamic(info, encrypted, offs, key, defaultDecryptKey_v17); + } + + protected byte[] decryptConstant_v17_r73740_dynamic(DecrypterInfo info, byte[] encrypted, uint offs, uint key1, byte[] key2) { 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); + if (endIndex < 0) + endIndex = getDynamicEndIndex_v17_r74788(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 => { + return decrypt(encrypted, key1, (magic, i) => { 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; + return (byte)(result ^ key2[i & 7]); }); } 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)); + return decryptConstant_v17_r73764_native(info, encrypted, offs, key, defaultDecryptKey_v17); } - static byte[] decrypt(byte[] encrypted, uint key, Func decryptFunc) { + protected byte[] decryptConstant_v17_r73764_native(DecrypterInfo info, byte[] encrypted, uint offs, uint key1, byte[] key2) { + var x86Emu = new x86Emulator(new PeImage(fileData)); + return decrypt(encrypted, key1, (magic, i) => (byte)(x86Emu.emulate((uint)nativeMethod.RVA, magic) ^ key2[i & 7])); + } + + 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); + decrypted[i] = decryptFunc(magic, i); } return decrypted; diff --git a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs index ee240bbd..2910cd78 100644 --- a/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs +++ b/de4dot.code/deobfuscators/Confuser/ConstantsDecrypterV17.cs @@ -34,11 +34,14 @@ namespace de4dot.code.deobfuscators.Confuser { v17_r74708_normal, v17_r74708_dynamic, v17_r74708_native, + v17_r74788_normal, + v17_r74788_dynamic, + v17_r74788_native, } class DecrypterInfoV17 : DecrypterInfo { public readonly ConfuserVersion version = ConfuserVersion.Unknown; - public uint key4; + public uint key4, key5; public DecrypterInfoV17(ConfuserVersion version, MethodDefinition decryptMethod) { this.version = version; @@ -54,6 +57,8 @@ namespace de4dot.code.deobfuscators.Confuser { return false; if (!findKey4(decryptMethod, out key4)) return false; + if (!findKey5(decryptMethod, out key5)) + return false; return true; } @@ -86,9 +91,14 @@ namespace de4dot.code.deobfuscators.Confuser { 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); + case ConfuserVersion.v17_r74708_normal: + case ConfuserVersion.v17_r74788_normal: + return findKey4_normal(method, out key); + case ConfuserVersion.v17_r74708_dynamic: + case ConfuserVersion.v17_r74708_native: + case ConfuserVersion.v17_r74788_dynamic: + case ConfuserVersion.v17_r74788_native: + return findKey4_other(method, out key); default: throw new ApplicationException("Invalid version"); } @@ -136,6 +146,37 @@ namespace de4dot.code.deobfuscators.Confuser { key = 0; return false; } + + bool findKey5(MethodDefinition method, out uint key) { + switch (version) { + case ConfuserVersion.v17_r74788_normal: + case ConfuserVersion.v17_r74788_dynamic: + case ConfuserVersion.v17_r74788_native: + return findKey5_v17_r74788(method, out key); + default: + key = 0; + return true; + } + } + + static bool findKey5_v17_r74788(MethodDefinition method, out uint key) { + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count; i++) { + i = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Reflection.Module System.Reflection.Assembly::GetModule(System.String)"); + if (i < 0) + break; + if (i + 1 >= instrs.Count) + break; + var ldci4 = instrs[i + 1]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + + key = (uint)DotNetUtils.getLdcI4Value(ldci4); + return true; + } + key = 0; + return false; + } } public override bool Detected { @@ -168,16 +209,23 @@ namespace de4dot.code.deobfuscators.Confuser { var method = getDecryptMethod(); if (method == null) return; + if (DotNetUtils.callsMethod(method, "System.Reflection.Module System.Reflection.Assembly::GetModule(System.String)")) + initVersion(method, ConfuserVersion.v17_r74788_normal, ConfuserVersion.v17_r74788_dynamic, ConfuserVersion.v17_r74788_native); + else + initVersion(method, ConfuserVersion.v17_r74708_normal, ConfuserVersion.v17_r74708_dynamic, ConfuserVersion.v17_r74708_native); + + initMethod = cctor; + } + + void initVersion(MethodDefinition method, ConfuserVersion normal, ConfuserVersion dynamic, ConfuserVersion native) { if (DeobUtils.hasInteger(method, 0x100) && DeobUtils.hasInteger(method, 0x10000) && DeobUtils.hasInteger(method, 0xFFFF)) - version = ConfuserVersion.v17_r74708_normal; + version = normal; else if ((nativeMethod = findNativeMethod(method)) == null) - version = ConfuserVersion.v17_r74708_dynamic; + version = dynamic; else - version = ConfuserVersion.v17_r74708_native; - - initMethod = cctor; + version = native; } MethodDefinition getDecryptMethod() { @@ -215,6 +263,9 @@ namespace de4dot.code.deobfuscators.Confuser { case ConfuserVersion.v17_r74708_normal: return decryptConstant_v17_r74708_normal(info, encrypted, offs, typeCode); case ConfuserVersion.v17_r74708_dynamic: return decryptConstant_v17_r74708_dynamic(info, encrypted, offs, typeCode); case ConfuserVersion.v17_r74708_native: return decryptConstant_v17_r74708_native(info, encrypted, offs, typeCode); + case ConfuserVersion.v17_r74788_normal: return decryptConstant_v17_r74788_normal(info, encrypted, offs, typeCode); + case ConfuserVersion.v17_r74788_dynamic: return decryptConstant_v17_r74788_dynamic(info, encrypted, offs, typeCode); + case ConfuserVersion.v17_r74788_native: return decryptConstant_v17_r74788_native(info, encrypted, offs, typeCode); default: throw new ApplicationException("Invalid version"); } @@ -232,6 +283,22 @@ namespace de4dot.code.deobfuscators.Confuser { return decryptConstant_v17_r73764_native(info, encrypted, offs, info.key4); } + byte[] decryptConstant_v17_r74788_normal(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) { + return ConfuserUtils.decrypt(info.key4 * (offs + typeCode), encrypted, getKey_v17_r74788(info)); + } + + byte[] decryptConstant_v17_r74788_dynamic(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) { + return decryptConstant_v17_r73740_dynamic(info, encrypted, offs, info.key4, getKey_v17_r74788(info)); + } + + byte[] decryptConstant_v17_r74788_native(DecrypterInfoV17 info, byte[] encrypted, uint offs, byte typeCode) { + return decryptConstant_v17_r73764_native(info, encrypted, offs, info.key4, getKey_v17_r74788(info)); + } + + byte[] getKey_v17_r74788(DecrypterInfoV17 info) { + return module.GetSignatureBlob(info.decryptMethod.MetadataToken.ToUInt32() ^ info.key5); + } + public override void initialize() { if ((resource = findResource(initMethod)) == null) throw new ApplicationException("Could not find encrypted consts resource");