From fb47689f5888361946447ce31094a806ccf2de4c Mon Sep 17 00:00:00 2001 From: de4dot Date: Sun, 29 Jul 2012 20:04:35 +0200 Subject: [PATCH] Decrypt Confuser encrypted methods (memory) --- de4dot.code/de4dot.code.csproj | 1 + .../deobfuscators/Confuser/Deobfuscator.cs | 31 ++- .../Confuser/MemoryMethodsDecrypter.cs | 184 ++++++++++++++++++ 3 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 de4dot.code/deobfuscators/Confuser/MemoryMethodsDecrypter.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index f03252cd..e26ce48c 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -75,6 +75,7 @@ + diff --git a/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs b/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs index dc92a0fe..7076b8d5 100644 --- a/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Confuser/Deobfuscator.cs @@ -67,6 +67,7 @@ namespace de4dot.code.deobfuscators.Confuser { string obfuscatorName = DeobfuscatorInfo.THE_NAME; JitMethodsDecrypter jitMethodsDecrypter; + MemoryMethodsDecrypter memoryMethodsDecrypter; ProxyCallFixer proxyCallFixer; AntiDebugger antiDebugger; AntiDumping antiDumping; @@ -119,6 +120,7 @@ namespace de4dot.code.deobfuscators.Confuser { int val = 0; int sum = toInt32(jitMethodsDecrypter != null ? jitMethodsDecrypter.Detected : false) + + toInt32(memoryMethodsDecrypter != null ? memoryMethodsDecrypter.Detected : false) + toInt32(proxyCallFixer != null ? proxyCallFixer.Detected : false) + toInt32(antiDebugger != null ? antiDebugger.Detected : false) + toInt32(antiDumping != null ? antiDumping.Detected : false) + @@ -132,9 +134,17 @@ namespace de4dot.code.deobfuscators.Confuser { protected override void scanForObfuscator() { jitMethodsDecrypter = new JitMethodsDecrypter(module, DeobfuscatedFile); - jitMethodsDecrypter.find(); + try { + jitMethodsDecrypter.find(); + } + catch { + } if (jitMethodsDecrypter.Detected) return; + memoryMethodsDecrypter = new MemoryMethodsDecrypter(module, DeobfuscatedFile); + memoryMethodsDecrypter.find(); + if (memoryMethodsDecrypter.Detected) + return; initTheRest(); } @@ -160,13 +170,13 @@ namespace de4dot.code.deobfuscators.Confuser { } public override bool getDecryptedModule(int count, ref byte[] newFileData, ref DumpedMethods dumpedMethods) { - if (count != 0 || !jitMethodsDecrypter.Detected) + if (count != 0 || (!jitMethodsDecrypter.Detected && !memoryMethodsDecrypter.Detected)) return false; byte[] fileData = getFileData(); var peImage = new PeImage(fileData); - if (jitMethodsDecrypter.Detected) { + if (jitMethodsDecrypter != null && jitMethodsDecrypter.Detected) { jitMethodsDecrypter.initialize(); if (!jitMethodsDecrypter.decrypt(peImage, fileData, ref dumpedMethods)) return false; @@ -175,6 +185,15 @@ namespace de4dot.code.deobfuscators.Confuser { return true; } + if (memoryMethodsDecrypter != null && memoryMethodsDecrypter.Detected) { + memoryMethodsDecrypter.initialize(); + if (!memoryMethodsDecrypter.decrypt(peImage, fileData, ref dumpedMethods)) + return false; + + newFileData = fileData; + return true; + } + return false; } @@ -185,6 +204,7 @@ namespace de4dot.code.deobfuscators.Confuser { newOne.ModuleBytes = ModuleBytes; newOne.setModule(module); newOne.jitMethodsDecrypter = new JitMethodsDecrypter(module, jitMethodsDecrypter); + newOne.memoryMethodsDecrypter = new MemoryMethodsDecrypter(module, memoryMethodsDecrypter); newOne.initTheRest(); return newOne; } @@ -200,6 +220,11 @@ namespace de4dot.code.deobfuscators.Confuser { addTypeToBeRemoved(jitMethodsDecrypter.Type, "Method decrypter (JIT) type"); } + if (memoryMethodsDecrypter != null) { + addModuleCctorInitCallToBeRemoved(memoryMethodsDecrypter.InitMethod); + addTypeToBeRemoved(memoryMethodsDecrypter.Type, "Method decrypter (memory) type"); + } + if (options.RemoveAntiDebug) { addModuleCctorInitCallToBeRemoved(antiDebugger.InitMethod); addTypeToBeRemoved(antiDebugger.Type, "Anti debugger type"); diff --git a/de4dot.code/deobfuscators/Confuser/MemoryMethodsDecrypter.cs b/de4dot.code/deobfuscators/Confuser/MemoryMethodsDecrypter.cs new file mode 100644 index 00000000..c360ca67 --- /dev/null +++ b/de4dot.code/deobfuscators/Confuser/MemoryMethodsDecrypter.cs @@ -0,0 +1,184 @@ +/* + 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.IO; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.MyStuff; +using de4dot.blocks; +using de4dot.PE; + +namespace de4dot.code.deobfuscators.Confuser { + class MemoryMethodsDecrypter : MethodsDecrypterBase { + public MemoryMethodsDecrypter(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator) + : base(module, simpleDeobfuscator) { + } + + public MemoryMethodsDecrypter(ModuleDefinition module, MemoryMethodsDecrypter other) + : base(module, other) { + } + + protected override bool checkType(TypeDefinition type, MethodDefinition initMethod) { + if (type == null) + return false; + if (type.Methods.Count != 3) + return false; + if (DotNetUtils.getPInvokeMethod(type, "kernel32", "VirtualProtect") == null) + return false; + if (!DotNetUtils.hasString(initMethod, "Module error")) + return false; + if (!DotNetUtils.hasString(initMethod, "Broken file")) + return false; + + if ((decryptMethod = findDecryptMethod(type)) == null) + return false; + + return true; + } + + public void initialize() { + if (initMethod == null) + return; + if (!initializeKeys()) + throw new ApplicationException("Could not find all decryption keys"); + } + + bool initializeKeys() { + simpleDeobfuscator.deobfuscate(initMethod); + if (!findLKey0(initMethod, out lkey0)) + return false; + if (!findKey0(initMethod, out key0)) + return false; + if (!findKey1(initMethod, out key1)) + return false; + if (!findKey2Key3(initMethod, out key2, out key3)) + return false; + if (!findKey4(initMethod, out key4)) + return false; + if (!findKey5(initMethod, out key5)) + return false; + + simpleDeobfuscator.deobfuscate(decryptMethod); + if (!findKey6(decryptMethod, out key6)) + return false; + + return true; + } + + static bool findKey4(MethodDefinition method, out uint key) { + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count; i++) { + i = findCallvirtReadUInt32(instrs, i); + if (i < 0) + break; + if (i >= 2) { + if (instrs[i-2].OpCode.Code == Code.Pop) + continue; + } + if (i + 4 >= instrs.Count) + break; + + var ldci4 = instrs[i + 1]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + if (instrs[i + 2].OpCode.Code != Code.Xor) + continue; + var stloc = instrs[i + 3]; + if (!DotNetUtils.isStloc(stloc)) + continue; + var ldloc = instrs[i + 4]; + if (!DotNetUtils.isLdloc(ldloc)) + continue; + if (DotNetUtils.getLocalVar(method.Body.Variables, ldloc) != DotNetUtils.getLocalVar(method.Body.Variables, stloc)) + continue; + + key = (uint)DotNetUtils.getLdcI4Value(ldci4); + return true; + } + + key = 0; + return false; + } + + static bool findKey5(MethodDefinition method, out uint key) { + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count; i++) { + i = findCallvirtReadUInt32(instrs, i); + if (i < 0) + break; + int index2 = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Int32 System.IO.BinaryReader::ReadInt32()"); + if (index2 < 0) + break; + if (index2 - i != 6) + continue; + + var ldci4 = instrs[i + 1]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + if (instrs[i + 2].OpCode.Code != Code.Xor) + continue; + var stloc = instrs[i + 3]; + if (!DotNetUtils.isStloc(stloc)) + continue; + var ldloc = instrs[i + 4]; + if (!DotNetUtils.isLdloc(ldloc)) + continue; + if (DotNetUtils.getLocalVar(method.Body.Variables, ldloc) == DotNetUtils.getLocalVar(method.Body.Variables, stloc)) + continue; + if (!DotNetUtils.isLdloc(instrs[i + 5])) + continue; + + key = (uint)DotNetUtils.getLdcI4Value(ldci4); + return true; + } + + key = 0; + return false; + } + + public bool decrypt(PeImage peImage, byte[] fileData, ref DumpedMethods dumpedMethods) { + if (initMethod == null) + return false; + if (peImage.OptionalHeader.checkSum == 0) + return false; + + methodsData = decryptMethodsData(peImage); + return decrypt(peImage, fileData); + } + + bool decrypt(PeImage peImage, byte[] fileData) { + var reader = new BinaryReader(new MemoryStream(methodsData)); + reader.ReadInt16(); // sig + int numInfos = reader.ReadInt32(); + for (int i = 0; i < numInfos; i++) { + uint offs = reader.ReadUInt32() ^ key4; + if (offs == 0) + continue; + uint rva = reader.ReadUInt32() ^ key5; + if (peImage.rvaToOffset(rva) != offs) + throw new ApplicationException("Invalid offs & rva"); + int len = reader.ReadInt32(); + for (int j = 0; j < len; j++) + fileData[offs + j] = reader.ReadByte(); + } + return true; + } + } +}