From a2798908b016ce0218512b4fcf1d472bc642039a Mon Sep 17 00:00:00 2001 From: de4dot Date: Wed, 8 Aug 2012 17:38:38 +0200 Subject: [PATCH] Merge other proxy method class with the V10 one --- .../deobfuscators/Confuser/Deobfuscator.cs | 16 +- .../deobfuscators/Confuser/ProxyCallFixer.cs | 274 ------------------ .../Confuser/ProxyCallFixerV10.cs | 134 ++++++++- 3 files changed, 134 insertions(+), 290 deletions(-) delete mode 100644 de4dot.code/deobfuscators/Confuser/ProxyCallFixer.cs diff --git a/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs b/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs index 77152284..a368d2d9 100644 --- a/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs @@ -73,7 +73,6 @@ namespace de4dot.code.deobfuscators.Confuser { List embeddedAssemblyInfos = new List(); JitMethodsDecrypter jitMethodsDecrypter; MemoryMethodsDecrypter memoryMethodsDecrypter; - ProxyCallFixer proxyCallFixer; ProxyCallFixerV10 proxyCallFixerV10; AntiDebugger antiDebugger; AntiDumping antiDumping; @@ -134,7 +133,6 @@ namespace de4dot.code.deobfuscators.Confuser { int sum = toInt32(jitMethodsDecrypter != null ? jitMethodsDecrypter.Detected : false) + toInt32(memoryMethodsDecrypter != null ? memoryMethodsDecrypter.Detected : false) + - toInt32(proxyCallFixer != null ? proxyCallFixer.Detected : false) + toInt32(proxyCallFixerV10 != null ? proxyCallFixerV10.Detected : false) + toInt32(antiDebugger != null ? antiDebugger.Detected : false) + toInt32(antiDumping != null ? antiDumping.Detected : false) + @@ -191,12 +189,8 @@ namespace de4dot.code.deobfuscators.Confuser { } } while (false); - proxyCallFixer = new ProxyCallFixer(module, getFileData(), DeobfuscatedFile); - proxyCallFixer.findDelegateCreator(); - if (!proxyCallFixer.Detected) { - proxyCallFixerV10 = new ProxyCallFixerV10(module, getFileData()); - proxyCallFixerV10.findDelegateCreator(DeobfuscatedFile); - } + proxyCallFixerV10 = new ProxyCallFixerV10(module, getFileData()); + proxyCallFixerV10.findDelegateCreator(DeobfuscatedFile); antiDebugger = new AntiDebugger(module); antiDebugger.find(); antiDumping = new AntiDumping(module); @@ -346,8 +340,6 @@ namespace de4dot.code.deobfuscators.Confuser { addTypeToBeRemoved(antiDumping.Type, "Anti dumping type"); } - if (proxyCallFixer != null) - proxyCallFixer.find(); if (proxyCallFixerV10 != null) proxyCallFixerV10.find(); @@ -503,8 +495,6 @@ namespace de4dot.code.deobfuscators.Confuser { } public override void deobfuscateMethodEnd(Blocks blocks) { - if (proxyCallFixer != null) - proxyCallFixer.deobfuscate(blocks); if (proxyCallFixerV10 != null) proxyCallFixerV10.deobfuscate(blocks); resourceDecrypter.deobfuscate(blocks); @@ -519,8 +509,6 @@ namespace de4dot.code.deobfuscators.Confuser { } public override void deobfuscateEnd() { - if (proxyCallFixer != null) - removeProxyDelegates(proxyCallFixer); if (proxyCallFixerV10 != null) { if (removeProxyDelegates(proxyCallFixerV10)) addFieldsToBeRemoved(proxyCallFixerV10.Fields, "Proxy delegate instance field"); diff --git a/de4dot.code/deobfuscators/Confuser/ProxyCallFixer.cs b/de4dot.code/deobfuscators/Confuser/ProxyCallFixer.cs deleted file mode 100644 index b6ef888c..00000000 --- a/de4dot.code/deobfuscators/Confuser/ProxyCallFixer.cs +++ /dev/null @@ -1,274 +0,0 @@ -/* - 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; -using de4dot.PE; - -namespace de4dot.code.deobfuscators.Confuser { - // Since 1.8 r75367 - class ProxyCallFixer : ProxyCallFixer2 { - byte[] fileData; - ISimpleDeobfuscator simpleDeobfuscator; - MethodDefinitionAndDeclaringTypeDict methodToInfo = new MethodDefinitionAndDeclaringTypeDict(); - FieldDefinitionAndDeclaringTypeDict fieldToMethod = new FieldDefinitionAndDeclaringTypeDict(); - x86Emulator x86emu; - - enum ProxyCreatorType { - None, - CallOrCallvirt, - Newobj, - } - - class ProxyCreatorInfo { - public readonly MethodDefinition creatorMethod; - public readonly ProxyCreatorType proxyCreatorType; - public uint? key; - public MethodDefinition nativeMethod; - public ushort callvirtChar; - - public ProxyCreatorInfo(MethodDefinition creatorMethod, ProxyCreatorType proxyCreatorType) { - this.creatorMethod = creatorMethod; - this.proxyCreatorType = proxyCreatorType; - } - } - - protected override bool ProxyCallIsObfuscated { - get { return true; } - } - - public override IEnumerable> OtherMethods { - get { - var list = new List>(); - foreach (var info in methodToInfo.getValues()) { - list.Add(new Tuple { - Item1 = info.creatorMethod, - Item2 = "Delegate creator method", - }); - list.Add(new Tuple { - Item1 = info.nativeMethod, - Item2 = "Calculate RID native method", - }); - } - return list; - } - } - - public ProxyCallFixer(ModuleDefinition module, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator) - : base(module) { - this.fileData = fileData; - this.simpleDeobfuscator = simpleDeobfuscator; - } - - protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) { - var instrs = cctor.Body.Instructions; - object retVal = null; - for (int i = 0; i < instrs.Count - 1; i++) { - var ldtoken = instrs[i]; - if (ldtoken.OpCode.Code != Code.Ldtoken) - continue; - var field = ldtoken.Operand as FieldDefinition; - if (field == null) - continue; - - var call = instrs[i + 1]; - if (call.OpCode.Code != Code.Call) - continue; - var calledMethod = call.Operand as MethodDefinition; - if (!isDelegateCreatorMethod(calledMethod)) - continue; - - fieldToMethod.add(field, calledMethod); - retVal = this; - } - return retVal; - } - - protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) { - var info = getProxyCreatorInfo(field); - var sig = module.GetSignatureBlob(field); - int len = sig.Length; - uint magic = (uint)((sig[len - 2] << 24) | (sig[len - 3] << 16) | (sig[len - 5] << 8) | sig[len - 6]); - uint rid = getRid(info, magic); - int token = (sig[len - 7] << 24) | (int)rid; - calledMethod = module.LookupToken(token) as MethodReference; - callOpcode = getCallOpCode(info, field); - } - - OpCode getCallOpCode(ProxyCreatorInfo info, FieldDefinition field) { - switch (info.proxyCreatorType) { - case ProxyCreatorType.CallOrCallvirt: - if (field.Name.Length > 0 && field.Name[0] == info.callvirtChar) - return OpCodes.Callvirt; - return OpCodes.Call; - - case ProxyCreatorType.Newobj: - return OpCodes.Newobj; - - default: throw new NotSupportedException(); - } - } - - ProxyCreatorInfo getProxyCreatorInfo(FieldReference field) { - return methodToInfo.find(fieldToMethod.find(field)); - } - - uint getRid(ProxyCreatorInfo info, uint magic) { - if (info.key != null) - return magic ^ info.key.Value; - - if (info.nativeMethod != null) { - if (x86emu == null) - x86emu = new x86Emulator(new PeImage(fileData)); - return x86emu.emulate((uint)info.nativeMethod.RVA, magic); - } - - throw new NotImplementedException(); - } - - public void findDelegateCreator() { - var type = DotNetUtils.getModuleType(module); - if (type == null) - return; - foreach (var method in type.Methods) { - if (!method.IsStatic || method.Body == null) - continue; - if (!DotNetUtils.isMethod(method, "System.Void", "(System.RuntimeFieldHandle)")) - continue; - var creatorType = getProxyCreatorType(method); - if (creatorType == ProxyCreatorType.None) - continue; - if (!DotNetUtils.callsMethod(method, "System.Byte[] System.Reflection.Module::ResolveSignature(System.Int32)")) - continue; - if (!DotNetUtils.callsMethod(method, "System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)")) - continue; - - methodToInfo.add(method, createProxyCreatorInfo(method, creatorType)); - setDelegateCreatorMethod(method); - } - } - - static ProxyCreatorType getProxyCreatorType(MethodDefinition method) { - foreach (var instr in method.Body.Instructions) { - var field = instr.Operand as FieldReference; - if (field == null) - continue; - switch (field.FullName) { - case "System.Reflection.Emit.OpCode System.Reflection.Emit.OpCodes::Call": - case "System.Reflection.Emit.OpCode System.Reflection.Emit.OpCodes::Callvirt": - return ProxyCreatorType.CallOrCallvirt; - - case "System.Reflection.Emit.OpCode System.Reflection.Emit.OpCodes::Newobj": - return ProxyCreatorType.Newobj; - } - } - return ProxyCreatorType.None; - } - - ProxyCreatorInfo createProxyCreatorInfo(MethodDefinition creatorMethod, ProxyCreatorType proxyCreatorType) { - simpleDeobfuscator.deobfuscate(creatorMethod, true); - var info = new ProxyCreatorInfo(creatorMethod, proxyCreatorType); - - if (!initializeKey(info)) - throw new NotSupportedException("Couldn't find decryption key"); - - if (info.proxyCreatorType == ProxyCreatorType.CallOrCallvirt) { - if (!initializeCallvirtChar(info)) - throw new ApplicationException("Couldn't find callvirt char"); - } - - return info; - } - - bool initializeKey(ProxyCreatorInfo info) { - var instrs = info.creatorMethod.Body.Instructions; - for (int index = 0; index < instrs.Count; index++) { - index = ConfuserUtils.findCallMethod(instrs, index, Code.Callvirt, "System.Reflection.Module System.Reflection.MemberInfo::get_Module()"); - if (index < 0) - break; - - uint key; - if (getKey(instrs, index + 1, out key)) { - info.key = key; - return true; - } - - var nativeMethod = getNativeMethod(instrs, index + 1); - if (nativeMethod != null) { - info.nativeMethod = nativeMethod; - return true; - } - } - return false; - } - - static bool getKey(IList instrs, int index, out uint key) { - key = 0; - if (index + 2 >= instrs.Count) - return false; - if (!DotNetUtils.isLdloc(instrs[index++])) - return false; - var ldci4 = instrs[index++]; - if (!DotNetUtils.isLdcI4(ldci4)) - return false; - if (instrs[index++].OpCode.Code != Code.Xor) - return false; - - key = (uint)DotNetUtils.getLdcI4Value(ldci4); - return true; - } - - static MethodDefinition getNativeMethod(IList instrs, int index) { - if (index + 1 >= instrs.Count) - return null; - if (!DotNetUtils.isLdloc(instrs[index++])) - return null; - var call = instrs[index++]; - if (call.OpCode.Code != Code.Call) - return null; - var calledMethod = call.Operand as MethodDefinition; - if (calledMethod == null || calledMethod.Body != null || !calledMethod.IsNative) - return null; - return calledMethod; - } - - bool initializeCallvirtChar(ProxyCreatorInfo info) { - var instrs = info.creatorMethod.Body.Instructions; - for (int index = 0; index < instrs.Count; index++) { - index = ConfuserUtils.findCallMethod(instrs, index, Code.Callvirt, "System.Char System.String::get_Chars(System.Int32)"); - if (index < 0) - break; - - index++; - if (index >= instrs.Count) - break; - - var ldci4 = instrs[index]; - if (!DotNetUtils.isLdcI4(ldci4)) - continue; - info.callvirtChar = (ushort)DotNetUtils.getLdcI4Value(ldci4); - return true; - } - return false; - } - } -} diff --git a/de4dot.code/deobfuscators/Confuser/ProxyCallFixerV10.cs b/de4dot.code/deobfuscators/Confuser/ProxyCallFixerV10.cs index 31111de4..17ab8207 100644 --- a/de4dot.code/deobfuscators/Confuser/ProxyCallFixerV10.cs +++ b/de4dot.code/deobfuscators/Confuser/ProxyCallFixerV10.cs @@ -34,6 +34,7 @@ namespace de4dot.code.deobfuscators.Confuser { ConfuserVersion version = ConfuserVersion.Unknown; byte[] fileData; x86Emulator x86emu; + ushort callvirtChar; enum ConfuserVersion { Unknown, @@ -45,6 +46,8 @@ namespace de4dot.code.deobfuscators.Confuser { v17_r73740_native, v17_r74708_normal, v17_r74708_native, + v18_r75367_normal, + v18_r75367_native, } enum ProxyCreatorType { @@ -59,13 +62,15 @@ namespace de4dot.code.deobfuscators.Confuser { public readonly ConfuserVersion version; public readonly uint magic; public readonly MethodDefinition nativeMethod; + public readonly ushort callvirtChar; - public ProxyCreatorInfo(MethodDefinition creatorMethod, ProxyCreatorType proxyCreatorType, ConfuserVersion version, uint magic, MethodDefinition nativeMethod) { + public ProxyCreatorInfo(MethodDefinition creatorMethod, ProxyCreatorType proxyCreatorType, ConfuserVersion version, uint magic, MethodDefinition nativeMethod, ushort callvirtChar) { this.creatorMethod = creatorMethod; this.proxyCreatorType = proxyCreatorType; this.version = version; this.magic = magic; this.nativeMethod = nativeMethod; + this.callvirtChar = callvirtChar; } } @@ -206,6 +211,14 @@ namespace de4dot.code.deobfuscators.Confuser { getCallInfo_v17_r73740_native(info, creatorInfo, out calledMethod, out callOpcode); break; + case ConfuserVersion.v18_r75367_normal: + getCallInfo_v18_r75367_normal(info, creatorInfo, out calledMethod, out callOpcode); + break; + + case ConfuserVersion.v18_r75367_native: + getCallInfo_v18_r75367_native(info, creatorInfo, out calledMethod, out callOpcode); + break; + default: throw new ApplicationException("Unknown version"); } @@ -366,6 +379,45 @@ namespace de4dot.code.deobfuscators.Confuser { callOpcode = getCallOpCode(creatorInfo, isCallvirt); } + void getCallInfo_v18_r75367_normal(DelegateInitInfo info, ProxyCreatorInfo creatorInfo, out MethodReference calledMethod, out OpCode callOpcode) { + getCallInfo_v18_r75367(info, creatorInfo, out calledMethod, out callOpcode, (creatorInfo2, magic) => creatorInfo2.magic ^ magic); + } + + void getCallInfo_v18_r75367_native(DelegateInitInfo info, ProxyCreatorInfo creatorInfo, out MethodReference calledMethod, out OpCode callOpcode) { + getCallInfo_v18_r75367(info, creatorInfo, out calledMethod, out callOpcode, (creatorInfo2, magic) => { + if (x86emu == null) + x86emu = new x86Emulator(new PeImage(fileData)); + return x86emu.emulate((uint)creatorInfo2.nativeMethod.RVA, magic); + }); + } + + void getCallInfo_v18_r75367(DelegateInitInfo info, ProxyCreatorInfo creatorInfo, out MethodReference calledMethod, out OpCode callOpcode, Func getRid) { + var sig = module.GetSignatureBlob(info.field); + int len = sig.Length; + uint magic = (uint)((sig[len - 2] << 24) | (sig[len - 3] << 16) | (sig[len - 5] << 8) | sig[len - 6]); + uint rid = getRid(creatorInfo, magic); + int token = (sig[len - 7] << 24) | (int)rid; + uint table = (uint)token >> 24; + if (table != 6 && table != 0x0A && table != 0x2B) + throw new ApplicationException("Invalid method token"); + calledMethod = module.LookupToken(token) as MethodReference; + callOpcode = getCallOpCode(creatorInfo, info.field); + } + + static OpCode getCallOpCode(ProxyCreatorInfo info, FieldDefinition field) { + switch (info.proxyCreatorType) { + case ProxyCreatorType.CallOrCallvirt: + if (field.Name.Length > 0 && field.Name[0] == info.callvirtChar) + return OpCodes.Callvirt; + return OpCodes.Call; + + case ProxyCreatorType.Newobj: + return OpCodes.Newobj; + + default: throw new NotSupportedException(); + } + } + // A method token is not a stable value so this method can fail to return the correct method! // There's nothing I can do about that. It's an obfuscator bug. It was fixed in 1.3 r55346. MethodReference createMethodReference(AssemblyNameReference asmRef, uint methodToken) { @@ -413,6 +465,8 @@ namespace de4dot.code.deobfuscators.Confuser { public void findDelegateCreator(ISimpleDeobfuscator simpleDeobfuscator) { var type = DotNetUtils.getModuleType(module); + if (type == null) + return; foreach (var method in type.Methods) { if (method.Body == null || !method.IsStatic || !method.IsAssembly) continue; @@ -438,6 +492,17 @@ namespace de4dot.code.deobfuscators.Confuser { else theVersion = ConfuserVersion.v14_r58857; } + else if (!DotNetUtils.callsMethod(method, "System.Byte[] System.Convert::FromBase64String(System.String)") && + DotNetUtils.callsMethod(method, "System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)")) { + if (proxyType == ProxyCreatorType.CallOrCallvirt && !findCallvirtChar(method, out callvirtChar)) + continue; + if ((nativeMethod = findNativeMethod_v18_r75367(method)) != null) + theVersion = ConfuserVersion.v18_r75367_native; + else if (findMagic_v18_r75367(method, out magic)) + theVersion = ConfuserVersion.v18_r75367_normal; + else + continue; + } else if (is_v17_r73740(method)) { if (DotNetUtils.callsMethod(method, "System.Boolean System.Type::get_IsArray()")) { if ((nativeMethod = findNativeMethod_v17_r73740(method)) != null) @@ -458,11 +523,55 @@ namespace de4dot.code.deobfuscators.Confuser { } setDelegateCreatorMethod(method); - methodToInfo.add(method, new ProxyCreatorInfo(method, proxyType, theVersion, magic, nativeMethod)); + methodToInfo.add(method, new ProxyCreatorInfo(method, proxyType, theVersion, magic, nativeMethod, callvirtChar)); version = theVersion; } } + static bool findMagic_v18_r75367(MethodDefinition method, out uint magic) { + 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.MemberInfo::get_Module()"); + if (i < 0 || i + 3 >= instrs.Count) + break; + + if (!DotNetUtils.isLdloc(instrs[i + 1])) + continue; + var ldci4 = instrs[i + 2]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + if (instrs[i+3].OpCode.Code != Code.Xor) + continue; + + magic = (uint)DotNetUtils.getLdcI4Value(ldci4); + return true; + } + magic = 0; + return false; + } + + static MethodDefinition findNativeMethod_v18_r75367(MethodDefinition method) { + 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.MemberInfo::get_Module()"); + if (i < 0 || i + 2 >= instrs.Count) + break; + + if (!DotNetUtils.isLdloc(instrs[i + 1])) + continue; + + var call = instrs[i + 2]; + if (call.OpCode.Code != Code.Call) + continue; + var calledMethod = call.Operand as MethodDefinition; + if (calledMethod == null || calledMethod.Body != null || !calledMethod.IsNative) + continue; + + return calledMethod; + } + return null; + } + static bool findMagic_v17_r73740(MethodDefinition method, out uint magic) { var instrs = method.Body.Instructions; for (int i = 0; i < instrs.Count; i++) { @@ -743,6 +852,27 @@ namespace de4dot.code.deobfuscators.Confuser { return foundInvoke ? field : null; } + static bool findCallvirtChar(MethodDefinition method, out ushort callvirtChar) { + var instrs = method.Body.Instructions; + for (int index = 0; index < instrs.Count; index++) { + index = ConfuserUtils.findCallMethod(instrs, index, Code.Callvirt, "System.Char System.String::get_Chars(System.Int32)"); + if (index < 0) + break; + + index++; + if (index >= instrs.Count) + break; + + var ldci4 = instrs[index]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + callvirtChar = (ushort)DotNetUtils.getLdcI4Value(ldci4); + return true; + } + callvirtChar = 0; + return false; + } + public void cleanUp() { if (!Detected) return;