From fc497b1688b391f0c68a1a1c3c8e801940579be3 Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 20 Feb 2012 03:26:27 +0100 Subject: [PATCH 01/13] Add MaxtoCode files --- de4dot.code/de4dot.code.csproj | 1 + .../deobfuscators/MaxtoCode/Deobfuscator.cs | 71 +++++++++++++++++++ .../deobfuscators/Unknown/Deobfuscator.cs | 2 - de4dot.cui/Program.cs | 1 + 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 1b894119..d94fc868 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -156,6 +156,7 @@ + diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs new file mode 100644 index 00000000..2e844702 --- /dev/null +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -0,0 +1,71 @@ +/* + 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 . +*/ + +namespace de4dot.code.deobfuscators.MaxtoCode { + public class DeobfuscatorInfo : DeobfuscatorInfoBase { + public const string THE_NAME = "MaxtoCode"; + public const string THE_TYPE = "mc"; + public DeobfuscatorInfo() + : base() { + } + + public override string Name { + get { return THE_NAME; } + } + + public override string Type { + get { return THE_TYPE; } + } + + public override IDeobfuscator createDeobfuscator() { + return new Deobfuscator(new Deobfuscator.Options { + RenameResourcesInCode = false, + ValidNameRegex = validNameRegex.get(), + }); + } + } + + class Deobfuscator : DeobfuscatorBase { + internal class Options : OptionsBase { + } + + public override string Type { + get { return DeobfuscatorInfo.THE_TYPE; } + } + + public override string TypeLong { + get { return DeobfuscatorInfo.THE_NAME; } + } + + public override string Name { + get { return DeobfuscatorInfo.THE_NAME; } + } + + internal Deobfuscator(Options options) + : base(options) { + } + + protected override int detectInternal() { + return 0; + } + + protected override void scanForObfuscator() { + } + } +} diff --git a/de4dot.code/deobfuscators/Unknown/Deobfuscator.cs b/de4dot.code/deobfuscators/Unknown/Deobfuscator.cs index a6c1bf73..a7e471ff 100644 --- a/de4dot.code/deobfuscators/Unknown/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/Unknown/Deobfuscator.cs @@ -101,8 +101,6 @@ namespace de4dot.code.deobfuscators.Unknown { return "CodeFort"; if (type.FullName == "ZYXDNGuarder") return "DNGuard HVM"; - if (type.FullName == "InfaceMaxtoCode") - return "MaxtoCode"; if (type.Name.Contains("();\t")) return "Manco .NET Obfuscator"; if (Regex.IsMatch(type.FullName, @"^EMyPID_\d+_$")) diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs index 530fef91..79551516 100644 --- a/de4dot.cui/Program.cs +++ b/de4dot.cui/Program.cs @@ -47,6 +47,7 @@ namespace de4dot.cui { new de4dot.code.deobfuscators.dotNET_Reactor.v4.DeobfuscatorInfo(), new de4dot.code.deobfuscators.Eazfuscator_NET.DeobfuscatorInfo(), new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(), + new de4dot.code.deobfuscators.MaxtoCode.DeobfuscatorInfo(), new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(), new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(), new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(), From 8536e211ddb97a8b0898e325e13a59571bf586a9 Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 20 Feb 2012 04:55:59 +0100 Subject: [PATCH 02/13] Detect MC --- de4dot.code/de4dot.code.csproj | 1 + .../deobfuscators/MaxtoCode/Deobfuscator.cs | 11 +- .../deobfuscators/MaxtoCode/MainType.cs | 119 ++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 de4dot.code/deobfuscators/MaxtoCode/MainType.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index d94fc868..b40ffdc8 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -157,6 +157,7 @@ + diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs index 2e844702..bc3466e9 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -42,6 +42,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } class Deobfuscator : DeobfuscatorBase { + MainType mainType; + internal class Options : OptionsBase { } @@ -62,10 +64,17 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } protected override int detectInternal() { - return 0; + int val = 0; + + if (mainType.Detected) + val = 150; + + return val; } protected override void scanForObfuscator() { + mainType = new MainType(module); + mainType.find(); } } } diff --git a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs new file mode 100644 index 00000000..c472fa3b --- /dev/null +++ b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs @@ -0,0 +1,119 @@ +/* + 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 de4dot.blocks; + +namespace de4dot.code.deobfuscators.MaxtoCode { + class MainType { + ModuleDefinition module; + TypeDefinition mcType; + ModuleReference mcModule1, mcModule2; + + public bool Detected { + get { return mcType != null; } + } + + public MainType(ModuleDefinition module) { + this.module = module; + } + + public void find() { + var cctor = getCctor(); + if (cctor == null) + return; + + foreach (var info in DotNetUtils.getCalledMethods(module, cctor)) { + var method = info.Item2; + if (method.Name != "Startup") + continue; + if (!DotNetUtils.isMethod(method, "System.Void", "()")) + continue; + + ModuleReference module1, module2; + if (!checkType(method.DeclaringType, out module1, out module2)) + return; + + mcType = method.DeclaringType; + mcModule1 = module1; + mcModule2 = module2; + break; + } + } + + MethodDefinition getCctor() { + int checksLeft = 3; + foreach (var type in module.GetTypes()) { + if (type.IsEnum) + continue; + var cctor = DotNetUtils.getMethod(type, ".cctor"); + if (cctor != null) + return cctor; + if (--checksLeft <= 0) + return null; + } + return null; + } + + static bool checkType(TypeDefinition type, out ModuleReference module1, out ModuleReference module2) { + module1 = module2 = null; + + if (DotNetUtils.getMethod(type, "Startup") == null) + return false; + + var pinvokes = getPinvokes(type); + var pinvokeList = getPinvokeList(pinvokes, "CheckRuntime"); + if (pinvokeList == null) + return false; + if (getPinvokeList(pinvokes, "MainDLL") == null) + return false; + if (getPinvokeList(pinvokes, "GetModuleBase") == null) + return false; + + module1 = pinvokeList[0].PInvokeInfo.Module; + module2 = pinvokeList[1].PInvokeInfo.Module; + return true; + } + + static Dictionary> getPinvokes(TypeDefinition type) { + var pinvokes = new Dictionary>(StringComparer.Ordinal); + foreach (var method in type.Methods) { + var info = method.PInvokeInfo; + if (info == null || info.EntryPoint == null) + continue; + List list; + if (!pinvokes.TryGetValue(info.EntryPoint, out list)) + pinvokes[info.EntryPoint] = list = new List(); + list.Add(method); + } + return pinvokes; + } + + static List getPinvokeList(Dictionary> pinvokes, string methodName) { + List list; + if (!pinvokes.TryGetValue(methodName, out list)) + return null; + if (list.Count != 2) + return null; + return list; + } + } +} From 0c3aca32b90ea5255002a649ae92e3619e55d7fd Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 20 Feb 2012 17:17:55 +0100 Subject: [PATCH 03/13] Update code to handle MethodDefPtr table --- de4dot.code/PE/MetadataTables.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/de4dot.code/PE/MetadataTables.cs b/de4dot.code/PE/MetadataTables.cs index 3fd81872..8b5f65c3 100644 --- a/de4dot.code/PE/MetadataTables.cs +++ b/de4dot.code/PE/MetadataTables.cs @@ -43,13 +43,14 @@ namespace de4dot.code.PE { reader.BaseStream.Position = fileOffset; } + // TODO: This table needs to be updated to support the other metadata tables. static MetadataVarType[] metadataVarType = new MetadataVarType[] { MVT.byte2, MVT.stringIndex, MVT.guidIndex, MVT.guidIndex, MVT.guidIndex, MVT.end, // 0 MVT.resolutionScope, MVT.stringIndex, MVT.stringIndex, MVT.end, // 1 MVT.byte4, MVT.stringIndex, MVT.stringIndex, MVT.typeDefOrRef, MVT.fieldIndex, MVT.methodDefIndex, MVT.end, // 2 MVT.end, // 3 MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.end, // 4 - MVT.end, // 5 + MVT.methodDefIndex, MVT.end, // 5 MVT.byte4, MVT.byte2, MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.paramIndex, MVT.end, // 6 MVT.end, // 7 MVT.byte2, MVT.byte2, MVT.stringIndex, MVT.end, // 8 @@ -113,7 +114,7 @@ namespace de4dot.code.PE { }; void init() { - var streamTable = metadata.getStream("#~"); + var streamTable = metadata.getStream("#~") ?? metadata.getStream("#-"); if (streamTable == null) throw new ApplicationException("Could not find #~ stream"); From b422e08fb1af950d13a58764d85d263475314fc3 Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 20 Feb 2012 17:18:22 +0100 Subject: [PATCH 04/13] Add lookup() method for ModuleReferences --- de4dot.code/deobfuscators/DeobUtils.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/de4dot.code/deobfuscators/DeobUtils.cs b/de4dot.code/deobfuscators/DeobUtils.cs index 45d52c5a..f09b1616 100644 --- a/de4dot.code/deobfuscators/DeobUtils.cs +++ b/de4dot.code/deobfuscators/DeobUtils.cs @@ -50,6 +50,16 @@ namespace de4dot.code.deobfuscators { return newDef; } + public static ModuleReference lookup(ModuleDefinition module, ModuleReference other, string errorMessage) { + if (other == null) + return null; + foreach (var modRef in module.ModuleReferences) { + if (modRef.MetadataToken.ToInt32() == other.MetadataToken.ToInt32()) + return modRef; + } + throw new ApplicationException(errorMessage); + } + public static byte[] readModule(ModuleDefinition module) { return Utils.readFile(module.FullyQualifiedName); } From eb223537f0ac246688ec37e44ecd4140ddd7279f Mon Sep 17 00:00:00 2001 From: de4dot Date: Mon, 20 Feb 2012 17:20:29 +0100 Subject: [PATCH 05/13] Decrypt methods (decryption #1-4, not #5-7) --- de4dot.code/de4dot.code.csproj | 1 + .../deobfuscators/MaxtoCode/Deobfuscator.cs | 27 ++ .../deobfuscators/MaxtoCode/FileDecrypter.cs | 432 ++++++++++++++++++ .../deobfuscators/MaxtoCode/MainType.cs | 15 +- 4 files changed, 472 insertions(+), 3 deletions(-) create mode 100644 de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index da5b1849..46dad4c5 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -157,6 +157,7 @@ + diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs index bc3466e9..aacda0be 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -17,6 +17,10 @@ along with de4dot. If not, see . */ +using System.Collections.Generic; +using Mono.Cecil; +using Mono.MyStuff; + namespace de4dot.code.deobfuscators.MaxtoCode { public class DeobfuscatorInfo : DeobfuscatorInfoBase { public const string THE_NAME = "MaxtoCode"; @@ -42,6 +46,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } class Deobfuscator : DeobfuscatorBase { + Options options; MainType mainType; internal class Options : OptionsBase { @@ -61,6 +66,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { internal Deobfuscator(Options options) : base(options) { + this.options = options; } protected override int detectInternal() { @@ -76,5 +82,26 @@ namespace de4dot.code.deobfuscators.MaxtoCode { mainType = new MainType(module); mainType.find(); } + + public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary dumpedMethods) { + if (!mainType.Detected) + return false; + + var fileDecrypter = new FileDecrypter(mainType); + + var fileData = DeobUtils.readModule(module); + if (!fileDecrypter.decrypt(fileData, ref dumpedMethods)) + return false; + + newFileData = fileData; + return true; + } + + public override IDeobfuscator moduleReloaded(ModuleDefinition module) { + var newOne = new Deobfuscator(options); + newOne.setModule(module); + newOne.mainType = new MainType(module, mainType); + return newOne; + } } } diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs new file mode 100644 index 00000000..f06358b2 --- /dev/null +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -0,0 +1,432 @@ +/* + 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 System.Collections.Generic; +using Mono.MyStuff; +using de4dot.code.PE; + +namespace de4dot.code.deobfuscators.MaxtoCode { + class FileDecrypter { + MainType mainType; + + class PeHeader { + const int XOR_KEY = 0x7ABF931; + const int RVA_DISPL_OFFSET = 0x0FB4; + const int MC_HEADER_RVA_OFFSET = 0x0FFC; + + byte[] headerData; + uint rvaDispl; + + public PeHeader(PeImage peImage) { + headerData = getPeHeaderData(peImage); + + if (peImage.readUInt32(0x2008) != 0x48) + rvaDispl = readUInt32(RVA_DISPL_OFFSET) ^ XOR_KEY; + } + + public bool hasMagic(int offset, uint magic1, uint magic2) { + return readUInt32(offset) == magic1 && readUInt32(offset + 4) == magic2; + } + + public uint getMcHeaderRva() { + return getRva(MC_HEADER_RVA_OFFSET, XOR_KEY); + } + + public uint getRva(int offset, uint xorKey) { + return (readUInt32(offset) ^ xorKey) - rvaDispl; + } + + uint readUInt32(int offset) { + return BitConverter.ToUInt32(headerData, offset); + } + + static byte[] getPeHeaderData(PeImage peImage) { + var data = new byte[0x1000]; + + var firstSection = peImage.Sections[0]; + readTo(peImage, data, 0, 0, firstSection.pointerToRawData); + + foreach (var section in peImage.Sections) { + if (section.virtualAddress >= data.Length) + continue; + int offset = (int)section.virtualAddress; + readTo(peImage, data, offset, section.pointerToRawData, section.sizeOfRawData); + } + + return data; + } + + static void readTo(PeImage peImage, byte[] data, int destOffset, uint imageOffset, uint maxLength) { + if (destOffset > data.Length) + return; + int len = Math.Min(data.Length - destOffset, (int)maxLength); + var newData = peImage.offsetReadBytes(imageOffset, len); + Array.Copy(newData, 0, data, destOffset, newData.Length); + } + } + + class McHeader { + PeHeader peHeader; + byte[] data; + + public McHeader(PeImage peImage, PeHeader peHeader) { + this.peHeader = peHeader; + this.data = peImage.readBytes(peHeader.getMcHeaderRva(), 0x2000); + } + + public bool hasMagic(int offset, uint magic1, uint magic2) { + return readUInt32(offset) == magic1 && readUInt32(offset + 4) == magic2; + } + + public byte readByte(int offset) { + return data[offset]; + } + + public void readBytes(int offset, Array dest, int size) { + Buffer.BlockCopy(data, offset, dest, 0, size); + } + + public uint readUInt32(int offset) { + return BitConverter.ToUInt32(data, offset); + } + } + + class DecryptedMethodInfo { + public uint bodyRva; + public byte[] body; + + public DecryptedMethodInfo(uint bodyRva, byte[] body) { + this.bodyRva = bodyRva; + this.body = body; + } + } + + class MethodInfos { + PeImage peImage; + PeHeader peHeader; + McHeader mcHeader; + uint structSize; + uint methodInfosOffset; + uint encryptedDataOffset; + uint xorKey; + Dictionary infos = new Dictionary(); + const int ENCRYPTED_DATA_INFO_SIZE = 0x13; + + public MethodInfos(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { + this.peImage = peImage; + this.peHeader = peHeader; + this.mcHeader = mcHeader; + + if (mcHeader.hasMagic(0x08C0, 0x6A731B13, 0xD72B891F)) + structSize = 0xC + 6 * ENCRYPTED_DATA_INFO_SIZE; + else + structSize = 0xC + 3 * ENCRYPTED_DATA_INFO_SIZE; + + uint methodInfosRva = peHeader.getRva(0x0FF8, mcHeader.readUInt32(0x005A)); + uint encryptedDataRva = peHeader.getRva(0x0FF0, mcHeader.readUInt32(0x0046)); + + methodInfosOffset = peImage.rvaToOffset(methodInfosRva); + encryptedDataOffset = peImage.rvaToOffset(encryptedDataRva); + } + + public DecryptedMethodInfo lookup(uint bodyRva) { + DecryptedMethodInfo info; + infos.TryGetValue(bodyRva, out info); + return info; + } + + byte readByte(uint offset) { + return peImage.offsetReadByte(methodInfosOffset + offset); + } + + short readInt16(uint offset) { + return (short)peImage.offsetReadUInt16(methodInfosOffset + offset); + } + + uint readUInt32(uint offset) { + return peImage.offsetReadUInt32(methodInfosOffset + offset); + } + + int readInt32(uint offset) { + return (int)readUInt32(offset); + } + + short readEncryptedInt16(uint offset) { + return (short)(readInt16(offset) ^ xorKey); + } + + int readEncryptedInt32(uint offset) { + return (int)readEncryptedUInt32(offset); + } + + uint readEncryptedUInt32(uint offset) { + return readUInt32(offset) ^ xorKey; + } + + public void initializeInfos() { + int numMethods = readInt32(0) ^ readInt32(4); + if (numMethods < 0) + throw new ApplicationException("Invalid number of encrypted methods"); + + xorKey = (uint)numMethods; + uint rvaDispl = peImage.readUInt32(0x2008) != 0x48 ? 0x1000U : 0; + int numEncryptedDataInfos = ((int)structSize - 0xC) / ENCRYPTED_DATA_INFO_SIZE; + var encryptedDataInfos = new byte[numEncryptedDataInfos][]; + + uint offset = 8; + for (int i = 0; i < numMethods; i++, offset += structSize) { + uint methodBodyRva = readEncryptedUInt32(offset) - rvaDispl; + uint totalSize = readEncryptedUInt32(offset + 4); + uint methodInstructionRva = readEncryptedUInt32(offset + 8) - rvaDispl; + + var decryptedData = new byte[totalSize]; + + // Read the method body header and method body (instrs + exception handlers). + // The method body header is always in the first one. The instrs + ex handlers + // are always in the last 4, and evenly divided (each byte[] is totalLen / 4). + // The 2nd one is for the exceptions (or padding), but it may be null. + uint offset2 = offset + 0xC; + int exOffset = 0; + for (int j = 0; j < encryptedDataInfos.Length; j++, offset2 += ENCRYPTED_DATA_INFO_SIZE) { + // readByte(offset2); <-- index + int encryptionType = readEncryptedInt16(offset2 + 1); + uint dataOffset = readEncryptedUInt32(offset2 + 3); + uint encryptedSize = readEncryptedUInt32(offset2 + 7); + uint realSize = readEncryptedUInt32(offset2 + 11); + if (j == 1) + exOffset = readEncryptedInt32(offset2 + 15); + if (j == 1 && exOffset == 0) + encryptedDataInfos[j] = null; + else + encryptedDataInfos[j] = decrypt(encryptionType, dataOffset, encryptedSize, realSize); + } + + int copyOffset = 0; + copyOffset = copyData(decryptedData, encryptedDataInfos[0], copyOffset); + for (int j = 2; j < encryptedDataInfos.Length; j++) + copyOffset = copyData(decryptedData, encryptedDataInfos[j], copyOffset); + copyData(decryptedData, encryptedDataInfos[1], exOffset); // Exceptions or padding + + var info = new DecryptedMethodInfo(methodBodyRva, decryptedData); + infos[info.bodyRva] = info; + } + } + + static int copyData(byte[] dest, byte[] source, int offset) { + if (source == null) + return offset; + Array.Copy(source, 0, dest, offset, source.Length); + return offset + source.Length; + } + + byte[] readData(uint offset, int size) { + return peImage.offsetReadBytes(encryptedDataOffset + offset, size); + } + + byte[] decrypt(int type, uint dataOffset, uint encryptedSize, uint realSize) { + if (realSize == 0) + return null; + if (realSize > encryptedSize) + throw new ApplicationException("Invalid realSize"); + + var encrypted = readData(dataOffset, (int)encryptedSize); + byte[] decrypted; + switch (type) { + case 1: decrypted = decrypt1(encrypted); break; + case 2: decrypted = decrypt2(encrypted); break; + case 3: decrypted = decrypt3(encrypted); break; + case 4: decrypted = decrypt4(encrypted); break; + case 5: decrypted = decrypt5(encrypted); break; + case 6: decrypted = decrypt6(encrypted); break; + case 7: decrypted = decrypt7(encrypted); break; + default: throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type)); + } + + if (realSize > decrypted.Length) + throw new ApplicationException("Invalid decrypted length"); + Array.Resize(ref decrypted, (int)realSize); + return decrypted; + } + + byte[] decrypt1(byte[] encrypted) { + var decrypted = new byte[encrypted.Length]; + for (int i = 0; i < decrypted.Length; i++) + decrypted[i] = (byte)(encrypted[i] ^ mcHeader.readByte(i % 0x2000)); + return decrypted; + } + + byte[] decrypt2(byte[] encrypted) { + if ((encrypted.Length & 7) != 0) + throw new ApplicationException("Invalid encryption #2 length"); + const int offset = 0x00FA; + uint key4 = mcHeader.readUInt32(offset + 4 * 4); + uint key5 = mcHeader.readUInt32(offset + 5 * 4); + + byte[] decrypted = new byte[encrypted.Length & ~7]; + var writer = new BinaryWriter(new MemoryStream(decrypted)); + + int loopCount = encrypted.Length / 8; + for (int i = 0; i < loopCount; i++) { + uint val0 = BitConverter.ToUInt32(encrypted, i * 8); + uint val1 = BitConverter.ToUInt32(encrypted, i * 8 + 4); + uint x = (val1 >> 26) + (val0 << 6); + uint y = (val0 >> 26) + (val1 << 6); + + writer.Write(x ^ key4); + writer.Write(y ^ key5); + } + + return decrypted; + } + + static byte[] decrypt3Shifts = new byte[16] { 5, 11, 14, 21, 6, 20, 17, 29, 4, 10, 3, 2, 7, 1, 26, 18 }; + byte[] decrypt3(byte[] encrypted) { + if ((encrypted.Length & 7) != 0) + throw new ApplicationException("Invalid encryption #2 length"); + const int offset = 0x015E; + uint key0 = mcHeader.readUInt32(offset + 0 * 4); + uint key3 = mcHeader.readUInt32(offset + 3 * 4); + + byte[] decrypted = new byte[encrypted.Length & ~7]; + var writer = new BinaryWriter(new MemoryStream(decrypted)); + + int loopCount = encrypted.Length / 8; + for (int i = 0; i < loopCount; i++) { + uint x = BitConverter.ToUInt32(encrypted, i * 8); + uint y = BitConverter.ToUInt32(encrypted, i * 8 + 4); + foreach (var shift in decrypt3Shifts) { + int shift1 = 32 - shift; + uint x1 = (y >> shift1) + (x << shift); + uint y1 = (x >> shift1) + (y << shift); + x = x1; + y = y1; + } + + writer.Write(x ^ key0); + writer.Write(y ^ key3); + } + + return decrypted; + } + + byte[] decrypt4(byte[] encrypted) { + var decrypted = new byte[encrypted.Length / 3 * 2 + 1]; + + int count = encrypted.Length / 3; + int i = 0, j = 0, k = 0; + while (count-- > 0) { + byte k1 = mcHeader.readByte(j + 1); + byte k2 = mcHeader.readByte(j + 2); + byte k3 = mcHeader.readByte(j + 3); + decrypted[k++] = (byte)(((encrypted[i + 1] ^ k2) >> 4) | ((encrypted[i] ^ k1) & 0xF0)); + decrypted[k++] = (byte)(((encrypted[i + 1] ^ k2) << 4) + ((encrypted[i + 2] ^ k3) & 0x0F)); + i += 3; + j = (j + 4) % 0x2000; + } + + if ((encrypted.Length % 3) != 0) + decrypted[k] = (byte)(encrypted[i] ^ mcHeader.readByte(j)); + + return decrypted; + } + + byte[] decrypt5(byte[] encrypted) { + throw new NotImplementedException("Encryption type #5 not implemented yet"); + } + + byte[] decrypt6(byte[] encrypted) { + throw new NotImplementedException("Encryption type #6 not implemented yet"); + } + + byte[] decrypt7(byte[] encrypted) { + throw new NotImplementedException("Encryption type #7 not implemented yet"); + } + } + + public FileDecrypter(MainType mainType) { + this.mainType = mainType; + } + + public bool decrypt(byte[] fileData, ref Dictionary dumpedMethods) { + var peImage = new PeImage(fileData); + var peHeader = new PeHeader(peImage); + var mcHeader = new McHeader(peImage, peHeader); + var methodInfos = new MethodInfos(peImage, peHeader, mcHeader); + methodInfos.initializeInfos(); + + dumpedMethods = new Dictionary(); + + var metadataTables = peImage.Cor20Header.createMetadataTables(); + var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef); + uint methodDefOffset = methodDef.fileOffset; + for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) { + uint bodyRva = peImage.offsetReadUInt32(methodDefOffset); + if (bodyRva == 0) + continue; + + var info = methodInfos.lookup(bodyRva); + if (info == null) + continue; + + uint bodyOffset = peImage.rvaToOffset(bodyRva); + ushort magic = peImage.offsetReadUInt16(bodyOffset); + if (magic != 0xFFF3) + continue; + + var dm = new DumpedMethod(); + dm.token = (uint)(0x06000001 + i); + dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset); + dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset); + dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size); + dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size); + dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size); + + var reader = new BinaryReader(new MemoryStream(info.body)); + byte b = reader.ReadByte(); + if ((b & 3) == 2) { + dm.mhFlags = 2; + dm.mhMaxStack = 8; + dm.mhCodeSize = (uint)(b >> 2); + dm.mhLocalVarSigTok = 0; + } + else { + reader.BaseStream.Position--; + dm.mhFlags = reader.ReadUInt16(); + dm.mhMaxStack = reader.ReadUInt16(); + dm.mhCodeSize = reader.ReadUInt32(); + dm.mhLocalVarSigTok = reader.ReadUInt32(); + uint codeOffset = (uint)(dm.mhFlags >> 12) * 4; + reader.BaseStream.Position += codeOffset - 12; + } + + dm.code = reader.ReadBytes((int)dm.mhCodeSize); + if ((dm.mhFlags & 8) != 0) { + reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3; + dm.extraSections = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)); + } + + dumpedMethods[dm.token] = dm; + } + + return true; + } + } +} diff --git a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs index c472fa3b..11a5fb38 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs @@ -36,6 +36,17 @@ namespace de4dot.code.deobfuscators.MaxtoCode { this.module = module; } + public MainType(ModuleDefinition module, MainType oldOne) { + this.module = module; + this.mcType = lookup(oldOne.mcType, "Could not find main type"); + this.mcModule1 = DeobUtils.lookup(module, mcModule1, "Could not find MC runtime module ref #1"); + this.mcModule2 = DeobUtils.lookup(module, mcModule2, "Could not find MC runtime module ref #2"); + } + + T lookup(T def, string errorMessage) where T : MemberReference { + return DeobUtils.lookup(module, def, errorMessage); + } + public void find() { var cctor = getCctor(); if (cctor == null) @@ -62,12 +73,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode { MethodDefinition getCctor() { int checksLeft = 3; foreach (var type in module.GetTypes()) { - if (type.IsEnum) - continue; var cctor = DotNetUtils.getMethod(type, ".cctor"); if (cctor != null) return cctor; - if (--checksLeft <= 0) + if (!type.IsEnum && --checksLeft <= 0) return null; } return null; From 58a94a842053bee68c3b35827752d7ad20533bdf Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 21 Feb 2012 09:26:05 +0100 Subject: [PATCH 06/13] Decrypt methods protected with older MC version --- .../deobfuscators/MaxtoCode/FileDecrypter.cs | 198 +++++++++++++++--- 1 file changed, 173 insertions(+), 25 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index f06358b2..da1d07b4 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -54,7 +54,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { return (readUInt32(offset) ^ xorKey) - rvaDispl; } - uint readUInt32(int offset) { + public uint readUInt32(int offset) { return BitConverter.ToUInt32(headerData, offset); } @@ -109,16 +109,75 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } } - class DecryptedMethodInfo { - public uint bodyRva; - public byte[] body; - - public DecryptedMethodInfo(uint bodyRva, byte[] body) { - this.bodyRva = bodyRva; - this.body = body; - } + enum EncryptionVersion { + Unknown, + V1, + V2, } + class EncryptionInfo { + public uint MagicLo { get; set; } + public uint MagicHi { get; set; } + public EncryptionVersion Version { get; set; } + } + + static EncryptionInfo[] encryptionInfos_Rva900h = new EncryptionInfo[] { + // PE header timestamp + // 4C622357 = Wed, 11 Aug 2010 04:13:11 + // 4C6220EC = Wed, 11 Aug 2010 04:02:52 + // 4A5EEC64 = Thu, 16 Jul 2009 09:01:24 + new EncryptionInfo { + MagicLo = 0xAA98B387, + MagicHi = 0x128EECA3, + Version = EncryptionVersion.V1, + }, + // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 + // 4DC2FC75 = Thu, 05 May 2011 19:37:25 + // 4D0E220D = Sun, 19 Dec 2010 15:17:33 + // 4C6E4605 = Fri, 20 Aug 2010 09:08:21 + new EncryptionInfo { + MagicLo = 0xAA98B387, + MagicHi = 0xF28EECA3, + Version = EncryptionVersion.V1, + }, + // 4DC2FE0C = Thu, 05 May 2011 19:44:12 + new EncryptionInfo { + MagicLo = 0xAA98B387, + MagicHi = 0xF28EEAA3, + Version = EncryptionVersion.V1, + }, + // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 + // 4ED76740 = Thu, 01 Dec 2011 11:38:40 + new EncryptionInfo { + MagicLo = 0xAA983B87, + MagicHi = 0xF28EECA3, + Version = EncryptionVersion.V2, + }, + }; + + static EncryptionInfo[] encryptionInfos_McHeader8C0h = new EncryptionInfo[] { + // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 + // 4DC2FE0C = Thu, 05 May 2011 19:44:12 + // 4DC2FC75 = Thu, 05 May 2011 19:37:25 + // 4D0E220D = Sun, 19 Dec 2010 15:17:33 + // 4C6E4605 = Fri, 20 Aug 2010 09:08:21 + // 4C622357 = Wed, 11 Aug 2010 04:13:11 + // 4C6220EC = Wed, 11 Aug 2010 04:02:52 + // 4A5EEC64 = Thu, 16 Jul 2009 09:01:24 + new EncryptionInfo { + MagicLo = 0x6A713B13, + MagicHi = 0xD72B891F, + Version = EncryptionVersion.V1, + }, + // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 + // 4ED76740 = Thu, 01 Dec 2011 11:38:40 + new EncryptionInfo { + MagicLo = 0x6A731B13, + MagicHi = 0xD72B891F, + Version = EncryptionVersion.V2, + }, + }; + class MethodInfos { PeImage peImage; PeHeader peHeader; @@ -128,17 +187,25 @@ namespace de4dot.code.deobfuscators.MaxtoCode { uint encryptedDataOffset; uint xorKey; Dictionary infos = new Dictionary(); + IDecrypter decrypter; const int ENCRYPTED_DATA_INFO_SIZE = 0x13; + public class DecryptedMethodInfo { + public uint bodyRva; + public byte[] body; + + public DecryptedMethodInfo(uint bodyRva, byte[] body) { + this.bodyRva = bodyRva; + this.body = body; + } + } + public MethodInfos(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { this.peImage = peImage; this.peHeader = peHeader; this.mcHeader = mcHeader; - if (mcHeader.hasMagic(0x08C0, 0x6A731B13, 0xD72B891F)) - structSize = 0xC + 6 * ENCRYPTED_DATA_INFO_SIZE; - else - structSize = 0xC + 3 * ENCRYPTED_DATA_INFO_SIZE; + structSize = getStructSize(mcHeader); uint methodInfosRva = peHeader.getRva(0x0FF8, mcHeader.readUInt32(0x005A)); uint encryptedDataRva = peHeader.getRva(0x0FF0, mcHeader.readUInt32(0x0046)); @@ -147,6 +214,34 @@ namespace de4dot.code.deobfuscators.MaxtoCode { encryptedDataOffset = peImage.rvaToOffset(encryptedDataRva); } + static uint getStructSize(McHeader mcHeader) { + foreach (var info in encryptionInfos_McHeader8C0h) { + if (mcHeader.hasMagic(0x08C0, info.MagicLo, info.MagicHi)) + return 0xC + 6 * ENCRYPTED_DATA_INFO_SIZE; + } + return 0xC + 3 * ENCRYPTED_DATA_INFO_SIZE; + } + + EncryptionVersion getVersion() { + uint m1lo = peHeader.readUInt32(0x900); + uint m1hi = peHeader.readUInt32(0x904); + uint m2lo = mcHeader.readUInt32(0x8C0); + uint m2hi = mcHeader.readUInt32(0x8C4); + + foreach (var info in encryptionInfos_McHeader8C0h) { + if (info.MagicLo == m2lo && info.MagicHi == m2hi) + return info.Version; + } + + foreach (var info in encryptionInfos_Rva900h) { + if (info.MagicLo == m1lo && info.MagicHi == m1hi) + return info.Version; + } + + Log.w("Could not detect MC version. Magic1: {0:X8} {1:X8}, Magic2: {2:X8} {3:X8}", m1lo, m1hi, m2lo, m2hi); + return EncryptionVersion.Unknown; + } + public DecryptedMethodInfo lookup(uint bodyRva) { DecryptedMethodInfo info; infos.TryGetValue(bodyRva, out info); @@ -181,7 +276,71 @@ namespace de4dot.code.deobfuscators.MaxtoCode { return readUInt32(offset) ^ xorKey; } + interface IDecrypter { + byte[] decrypt(int type, byte[] encrypted); + } + + class DecrypterV1 : IDecrypter { + MethodInfos methodInfos; + + public DecrypterV1(MethodInfos methodInfos) { + this.methodInfos = methodInfos; + } + + public byte[] decrypt(int type, byte[] encrypted) { + switch (type) { + case 1: return methodInfos.decrypt3(encrypted); + case 2: return methodInfos.decrypt2(encrypted); + case 3: return methodInfos.decrypt1(encrypted); + case 4: return methodInfos.decrypt4(encrypted); + case 5: return methodInfos.decrypt5(encrypted); + case 6: return methodInfos.decrypt6(encrypted); + case 7: return methodInfos.decrypt7(encrypted); + default: throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type)); + } + } + } + + class DecrypterV2 : IDecrypter { + MethodInfos methodInfos; + + public DecrypterV2(MethodInfos methodInfos) { + this.methodInfos = methodInfos; + } + + public byte[] decrypt(int type, byte[] encrypted) { + switch (type) { + case 1: return methodInfos.decrypt1(encrypted); + case 2: return methodInfos.decrypt2(encrypted); + case 3: return methodInfos.decrypt3(encrypted); + case 4: return methodInfos.decrypt4(encrypted); + case 5: return methodInfos.decrypt5(encrypted); + case 6: return methodInfos.decrypt6(encrypted); + case 7: return methodInfos.decrypt7(encrypted); + default: throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type)); + } + } + } + + void initializeDecrypter() { + switch (getVersion()) { + case EncryptionVersion.V1: + decrypter = new DecrypterV1(this); + break; + + case EncryptionVersion.V2: + decrypter = new DecrypterV2(this); + break; + + case EncryptionVersion.Unknown: + default: + throw new ApplicationException("Unknown MC version"); + } + } + public void initializeInfos() { + initializeDecrypter(); + int numMethods = readInt32(0) ^ readInt32(4); if (numMethods < 0) throw new ApplicationException("Invalid number of encrypted methods"); @@ -248,18 +407,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { throw new ApplicationException("Invalid realSize"); var encrypted = readData(dataOffset, (int)encryptedSize); - byte[] decrypted; - switch (type) { - case 1: decrypted = decrypt1(encrypted); break; - case 2: decrypted = decrypt2(encrypted); break; - case 3: decrypted = decrypt3(encrypted); break; - case 4: decrypted = decrypt4(encrypted); break; - case 5: decrypted = decrypt5(encrypted); break; - case 6: decrypted = decrypt6(encrypted); break; - case 7: decrypted = decrypt7(encrypted); break; - default: throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type)); - } - + var decrypted = decrypter.decrypt(type, encrypted); if (realSize > decrypted.Length) throw new ApplicationException("Invalid decrypted length"); Array.Resize(ref decrypted, (int)realSize); From 7bc3930df9e611167e1f8d8627cb379464c4fb25 Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 21 Feb 2012 11:51:19 +0100 Subject: [PATCH 07/13] Decrypt resources --- .../deobfuscators/MaxtoCode/FileDecrypter.cs | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index da1d07b4..2e17f180 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -24,34 +24,36 @@ using Mono.MyStuff; using de4dot.code.PE; namespace de4dot.code.deobfuscators.MaxtoCode { + // Decrypts methods and resources class FileDecrypter { MainType mainType; class PeHeader { const int XOR_KEY = 0x7ABF931; - const int RVA_DISPL_OFFSET = 0x0FB4; - const int MC_HEADER_RVA_OFFSET = 0x0FFC; byte[] headerData; - uint rvaDispl; + uint rvaDispl1; + uint rvaDispl2; public PeHeader(PeImage peImage) { headerData = getPeHeaderData(peImage); - if (peImage.readUInt32(0x2008) != 0x48) - rvaDispl = readUInt32(RVA_DISPL_OFFSET) ^ XOR_KEY; - } - - public bool hasMagic(int offset, uint magic1, uint magic2) { - return readUInt32(offset) == magic1 && readUInt32(offset + 4) == magic2; + if (peImage.readUInt32(0x2008) != 0x48) { + rvaDispl1 = readUInt32(0x0FB0) ^ XOR_KEY; + rvaDispl2 = readUInt32(0x0FB4) ^ XOR_KEY; + } } public uint getMcHeaderRva() { - return getRva(MC_HEADER_RVA_OFFSET, XOR_KEY); + return getRva2(0x0FFC, XOR_KEY); } - public uint getRva(int offset, uint xorKey) { - return (readUInt32(offset) ^ xorKey) - rvaDispl; + public uint getRva1(int offset, uint xorKey) { + return (readUInt32(offset) ^ xorKey) - rvaDispl1; + } + + public uint getRva2(int offset, uint xorKey) { + return (readUInt32(offset) ^ xorKey) - rvaDispl2; } public uint readUInt32(int offset) { @@ -87,6 +89,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode { PeHeader peHeader; byte[] data; + public byte this[int index] { + get { return data[index]; } + } + public McHeader(PeImage peImage, PeHeader peHeader) { this.peHeader = peHeader; this.data = peImage.readBytes(peHeader.getMcHeaderRva(), 0x2000); @@ -207,8 +213,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode { structSize = getStructSize(mcHeader); - uint methodInfosRva = peHeader.getRva(0x0FF8, mcHeader.readUInt32(0x005A)); - uint encryptedDataRva = peHeader.getRva(0x0FF0, mcHeader.readUInt32(0x0046)); + uint methodInfosRva = peHeader.getRva2(0x0FF8, mcHeader.readUInt32(0x005A)); + uint encryptedDataRva = peHeader.getRva2(0x0FF0, mcHeader.readUInt32(0x0046)); methodInfosOffset = peImage.rvaToOffset(methodInfosRva); encryptedDataOffset = peImage.rvaToOffset(encryptedDataRva); @@ -448,7 +454,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { static byte[] decrypt3Shifts = new byte[16] { 5, 11, 14, 21, 6, 20, 17, 29, 4, 10, 3, 2, 7, 1, 26, 18 }; byte[] decrypt3(byte[] encrypted) { if ((encrypted.Length & 7) != 0) - throw new ApplicationException("Invalid encryption #2 length"); + throw new ApplicationException("Invalid encryption #3 length"); const int offset = 0x015E; uint key0 = mcHeader.readUInt32(offset + 0 * 4); uint key3 = mcHeader.readUInt32(offset + 3 * 4); @@ -517,11 +523,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode { var peImage = new PeImage(fileData); var peHeader = new PeHeader(peImage); var mcHeader = new McHeader(peImage, peHeader); + + dumpedMethods = decryptMethods(peImage, peHeader, mcHeader); + if (dumpedMethods == null) + return false; + + decryptResources(fileData, peImage, peHeader, mcHeader); + + return true; + } + + Dictionary decryptMethods(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { + var dumpedMethods = new Dictionary(); + var methodInfos = new MethodInfos(peImage, peHeader, mcHeader); methodInfos.initializeInfos(); - dumpedMethods = new Dictionary(); - var metadataTables = peImage.Cor20Header.createMetadataTables(); var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef); uint methodDefOffset = methodDef.fileOffset; @@ -574,7 +591,24 @@ namespace de4dot.code.deobfuscators.MaxtoCode { dumpedMethods[dm.token] = dm; } - return true; + return dumpedMethods; + } + + void decryptResources(byte[] fileData, PeImage peImage, PeHeader peHeader, McHeader mcHeader) { + uint resourceRva = peHeader.getRva1(0x0E10, mcHeader.readUInt32(0x00A0)); + uint resourceSize = peHeader.readUInt32(0x0E14) ^ mcHeader.readUInt32(0x00AA); + if (resourceRva == 0 || resourceSize == 0) + return; + if (resourceRva != peImage.Cor20Header.resources.virtualAddress || + resourceSize != peImage.Cor20Header.resources.size) { + Log.w("Invalid resource RVA and size found"); + } + + Log.v("Decrypting resources @ RVA {0:X8}, {1} bytes", resourceRva, resourceSize); + + int resourceOffset = (int)peImage.rvaToOffset(resourceRva); + for (int i = 0; i < resourceSize; i++) + fileData[resourceOffset + i] ^= mcHeader[i % 0x2000]; } } } From e5145fcca9cb3814a4ff1906e46ae0f170d7b8f8 Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 21 Feb 2012 11:57:47 +0100 Subject: [PATCH 08/13] Remove MC type and module refs --- .../deobfuscators/MaxtoCode/Deobfuscator.cs | 9 ++++++ .../deobfuscators/MaxtoCode/MainType.cs | 32 +++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs index aacda0be..b5c986e2 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -103,5 +103,14 @@ namespace de4dot.code.deobfuscators.MaxtoCode { newOne.mainType = new MainType(module, mainType); return newOne; } + + public override void deobfuscateBegin() { + base.deobfuscateBegin(); + + foreach (var method in mainType.InitMethods) + addCctorInitCallToBeRemoved(method); + addTypeToBeRemoved(mainType.Type, "Obfuscator type"); + addModuleReferencesToBeRemoved(mainType.ModuleReferences, "MC runtime module reference"); + } } } diff --git a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs index 11a5fb38..cde2a78c 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs @@ -28,6 +28,34 @@ namespace de4dot.code.deobfuscators.MaxtoCode { TypeDefinition mcType; ModuleReference mcModule1, mcModule2; + public TypeDefinition Type { + get { return mcType; } + } + + public IEnumerable ModuleReferences { + get { + var list = new List(); + if (mcModule1 != null) + list.Add(mcModule1); + if (mcModule2 != null) + list.Add(mcModule2); + return list; + } + } + + public IEnumerable InitMethods { + get { + var list = new List(); + if (mcType == null) + return list; + foreach (var method in mcType.Methods) { + if (method.IsStatic && DotNetUtils.isMethod(method, "System.Void", "()")) + list.Add(method); + } + return list; + } + } + public bool Detected { get { return mcType != null; } } @@ -39,8 +67,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode { public MainType(ModuleDefinition module, MainType oldOne) { this.module = module; this.mcType = lookup(oldOne.mcType, "Could not find main type"); - this.mcModule1 = DeobUtils.lookup(module, mcModule1, "Could not find MC runtime module ref #1"); - this.mcModule2 = DeobUtils.lookup(module, mcModule2, "Could not find MC runtime module ref #2"); + this.mcModule1 = DeobUtils.lookup(module, oldOne.mcModule1, "Could not find MC runtime module ref #1"); + this.mcModule2 = DeobUtils.lookup(module, oldOne.mcModule2, "Could not find MC runtime module ref #2"); } T lookup(T def, string errorMessage) where T : MemberReference { From 59ee55105dea14fd81b71fad7e157cd9cc150591 Mon Sep 17 00:00:00 2001 From: de4dot Date: Wed, 22 Feb 2012 12:14:15 +0100 Subject: [PATCH 09/13] Support some older MC version --- .../deobfuscators/MaxtoCode/FileDecrypter.cs | 34 +++++++++++++------ .../deobfuscators/MaxtoCode/MainType.cs | 17 +++++++--- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index 2e17f180..6ace5b34 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -35,10 +35,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode { uint rvaDispl1; uint rvaDispl2; - public PeHeader(PeImage peImage) { + public PeHeader(MainType mainType, PeImage peImage) { headerData = getPeHeaderData(peImage); - if (peImage.readUInt32(0x2008) != 0x48) { + if (!mainType.IsOld && peImage.readUInt32(0x2008) != 0x48) { rvaDispl1 = readUInt32(0x0FB0) ^ XOR_KEY; rvaDispl2 = readUInt32(0x0FB4) ^ XOR_KEY; } @@ -98,10 +98,6 @@ namespace de4dot.code.deobfuscators.MaxtoCode { this.data = peImage.readBytes(peHeader.getMcHeaderRva(), 0x2000); } - public bool hasMagic(int offset, uint magic1, uint magic2) { - return readUInt32(offset) == magic1 && readUInt32(offset + 4) == magic2; - } - public byte readByte(int offset) { return data[offset]; } @@ -129,6 +125,12 @@ namespace de4dot.code.deobfuscators.MaxtoCode { static EncryptionInfo[] encryptionInfos_Rva900h = new EncryptionInfo[] { // PE header timestamp + // 482384FB = Thu, 08 May 2008 22:55:55 (3.36) + new EncryptionInfo { + MagicLo = 0xAA98B387, + MagicHi = 0x1E8EECA3, + Version = EncryptionVersion.V1, + }, // 4C622357 = Wed, 11 Aug 2010 04:13:11 // 4C6220EC = Wed, 11 Aug 2010 04:02:52 // 4A5EEC64 = Thu, 16 Jul 2009 09:01:24 @@ -162,6 +164,12 @@ namespace de4dot.code.deobfuscators.MaxtoCode { }; static EncryptionInfo[] encryptionInfos_McHeader8C0h = new EncryptionInfo[] { + // 482384FB = Thu, 08 May 2008 22:55:55 (3.36) + new EncryptionInfo { + MagicLo = 0x6A713B13, + MagicHi = 0xD72B891F, + Version = EncryptionVersion.V1, + }, // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 // 4DC2FE0C = Thu, 05 May 2011 19:44:12 // 4DC2FC75 = Thu, 05 May 2011 19:37:25 @@ -185,6 +193,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { }; class MethodInfos { + MainType mainType; PeImage peImage; PeHeader peHeader; McHeader mcHeader; @@ -206,7 +215,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } } - public MethodInfos(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { + public MethodInfos(MainType mainType, PeImage peImage, PeHeader peHeader, McHeader mcHeader) { + this.mainType = mainType; this.peImage = peImage; this.peHeader = peHeader; this.mcHeader = mcHeader; @@ -221,8 +231,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } static uint getStructSize(McHeader mcHeader) { + uint magicLo = mcHeader.readUInt32(0x8C0); + uint magicHi = mcHeader.readUInt32(0x8C4); foreach (var info in encryptionInfos_McHeader8C0h) { - if (mcHeader.hasMagic(0x08C0, info.MagicLo, info.MagicHi)) + if (magicLo == info.MagicLo && magicHi == info.MagicHi) return 0xC + 6 * ENCRYPTED_DATA_INFO_SIZE; } return 0xC + 3 * ENCRYPTED_DATA_INFO_SIZE; @@ -352,7 +364,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { throw new ApplicationException("Invalid number of encrypted methods"); xorKey = (uint)numMethods; - uint rvaDispl = peImage.readUInt32(0x2008) != 0x48 ? 0x1000U : 0; + uint rvaDispl = !mainType.IsOld && peImage.readUInt32(0x2008) != 0x48 ? 0x1000U : 0; int numEncryptedDataInfos = ((int)structSize - 0xC) / ENCRYPTED_DATA_INFO_SIZE; var encryptedDataInfos = new byte[numEncryptedDataInfos][]; @@ -521,7 +533,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { public bool decrypt(byte[] fileData, ref Dictionary dumpedMethods) { var peImage = new PeImage(fileData); - var peHeader = new PeHeader(peImage); + var peHeader = new PeHeader(mainType, peImage); var mcHeader = new McHeader(peImage, peHeader); dumpedMethods = decryptMethods(peImage, peHeader, mcHeader); @@ -536,7 +548,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { Dictionary decryptMethods(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { var dumpedMethods = new Dictionary(); - var methodInfos = new MethodInfos(peImage, peHeader, mcHeader); + var methodInfos = new MethodInfos(mainType, peImage, peHeader, mcHeader); methodInfos.initializeInfos(); var metadataTables = peImage.Cor20Header.createMetadataTables(); diff --git a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs index cde2a78c..37184301 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/MainType.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/MainType.cs @@ -27,6 +27,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode { ModuleDefinition module; TypeDefinition mcType; ModuleReference mcModule1, mcModule2; + bool isOld; + + public bool IsOld { + get { return isOld; } + } public TypeDefinition Type { get { return mcType; } @@ -88,12 +93,14 @@ namespace de4dot.code.deobfuscators.MaxtoCode { continue; ModuleReference module1, module2; - if (!checkType(method.DeclaringType, out module1, out module2)) + bool isOldTmp; + if (!checkType(method.DeclaringType, out module1, out module2, out isOldTmp)) return; mcType = method.DeclaringType; mcModule1 = module1; mcModule2 = module2; + isOld = isOldTmp; break; } } @@ -110,8 +117,9 @@ namespace de4dot.code.deobfuscators.MaxtoCode { return null; } - static bool checkType(TypeDefinition type, out ModuleReference module1, out ModuleReference module2) { + static bool checkType(TypeDefinition type, out ModuleReference module1, out ModuleReference module2, out bool isOld) { module1 = module2 = null; + isOld = false; if (DotNetUtils.getMethod(type, "Startup") == null) return false; @@ -122,8 +130,9 @@ namespace de4dot.code.deobfuscators.MaxtoCode { return false; if (getPinvokeList(pinvokes, "MainDLL") == null) return false; - if (getPinvokeList(pinvokes, "GetModuleBase") == null) - return false; + + // Newer versions (3.4+ ???) also have GetModuleBase() + isOld = getPinvokeList(pinvokes, "GetModuleBase") == null; module1 = pinvokeList[0].PInvokeInfo.Module; module2 = pinvokeList[1].PInvokeInfo.Module; From 7c4f014da32af9980f8e25b62cd3dc819e8d1d5a Mon Sep 17 00:00:00 2001 From: de4dot Date: Wed, 22 Feb 2012 12:38:02 +0100 Subject: [PATCH 10/13] Support old MC 3.2 --- .../deobfuscators/MaxtoCode/FileDecrypter.cs | 62 +++++++++++++++---- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index 6ace5b34..d06ccdbd 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -115,6 +115,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { Unknown, V1, V2, + V3, } class EncryptionInfo { @@ -125,11 +126,17 @@ namespace de4dot.code.deobfuscators.MaxtoCode { static EncryptionInfo[] encryptionInfos_Rva900h = new EncryptionInfo[] { // PE header timestamp + // 462FA2D2 = Wed, 25 Apr 2007 18:49:54 (3.20) + new EncryptionInfo { + MagicLo = 0xA098B387, + MagicHi = 0x1E8EBCA3, + Version = EncryptionVersion.V1, + }, // 482384FB = Thu, 08 May 2008 22:55:55 (3.36) new EncryptionInfo { MagicLo = 0xAA98B387, MagicHi = 0x1E8EECA3, - Version = EncryptionVersion.V1, + Version = EncryptionVersion.V2, }, // 4C622357 = Wed, 11 Aug 2010 04:13:11 // 4C6220EC = Wed, 11 Aug 2010 04:02:52 @@ -137,7 +144,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { new EncryptionInfo { MagicLo = 0xAA98B387, MagicHi = 0x128EECA3, - Version = EncryptionVersion.V1, + Version = EncryptionVersion.V2, }, // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 // 4DC2FC75 = Thu, 05 May 2011 19:37:25 @@ -146,29 +153,35 @@ namespace de4dot.code.deobfuscators.MaxtoCode { new EncryptionInfo { MagicLo = 0xAA98B387, MagicHi = 0xF28EECA3, - Version = EncryptionVersion.V1, + Version = EncryptionVersion.V2, }, // 4DC2FE0C = Thu, 05 May 2011 19:44:12 new EncryptionInfo { MagicLo = 0xAA98B387, MagicHi = 0xF28EEAA3, - Version = EncryptionVersion.V1, + Version = EncryptionVersion.V2, }, // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 // 4ED76740 = Thu, 01 Dec 2011 11:38:40 new EncryptionInfo { MagicLo = 0xAA983B87, MagicHi = 0xF28EECA3, - Version = EncryptionVersion.V2, + Version = EncryptionVersion.V3, }, }; static EncryptionInfo[] encryptionInfos_McHeader8C0h = new EncryptionInfo[] { + // 462FA2D2 = Wed, 25 Apr 2007 18:49:54 (3.20) + new EncryptionInfo { + MagicLo = 0x6AA13B13, + MagicHi = 0xD72B991F, + Version = EncryptionVersion.V1, + }, // 482384FB = Thu, 08 May 2008 22:55:55 (3.36) new EncryptionInfo { MagicLo = 0x6A713B13, MagicHi = 0xD72B891F, - Version = EncryptionVersion.V1, + Version = EncryptionVersion.V2, }, // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 // 4DC2FE0C = Thu, 05 May 2011 19:44:12 @@ -181,14 +194,14 @@ namespace de4dot.code.deobfuscators.MaxtoCode { new EncryptionInfo { MagicLo = 0x6A713B13, MagicHi = 0xD72B891F, - Version = EncryptionVersion.V1, + Version = EncryptionVersion.V2, }, // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 // 4ED76740 = Thu, 01 Dec 2011 11:38:40 new EncryptionInfo { MagicLo = 0x6A731B13, MagicHi = 0xD72B891F, - Version = EncryptionVersion.V2, + Version = EncryptionVersion.V3, }, }; @@ -307,10 +320,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode { public byte[] decrypt(int type, byte[] encrypted) { switch (type) { - case 1: return methodInfos.decrypt3(encrypted); - case 2: return methodInfos.decrypt2(encrypted); - case 3: return methodInfos.decrypt1(encrypted); - case 4: return methodInfos.decrypt4(encrypted); + case 1: return methodInfos.decrypt1(encrypted); + case 2: return methodInfos.decrypt4(encrypted); + case 3: return methodInfos.decrypt2(encrypted); + case 4: return methodInfos.decrypt3(encrypted); case 5: return methodInfos.decrypt5(encrypted); case 6: return methodInfos.decrypt6(encrypted); case 7: return methodInfos.decrypt7(encrypted); @@ -326,6 +339,27 @@ namespace de4dot.code.deobfuscators.MaxtoCode { this.methodInfos = methodInfos; } + public byte[] decrypt(int type, byte[] encrypted) { + switch (type) { + case 1: return methodInfos.decrypt3(encrypted); + case 2: return methodInfos.decrypt2(encrypted); + case 3: return methodInfos.decrypt1(encrypted); + case 4: return methodInfos.decrypt4(encrypted); + case 5: return methodInfos.decrypt5(encrypted); + case 6: return methodInfos.decrypt6(encrypted); + case 7: return methodInfos.decrypt7(encrypted); + default: throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type)); + } + } + } + + class DecrypterV3 : IDecrypter { + MethodInfos methodInfos; + + public DecrypterV3(MethodInfos methodInfos) { + this.methodInfos = methodInfos; + } + public byte[] decrypt(int type, byte[] encrypted) { switch (type) { case 1: return methodInfos.decrypt1(encrypted); @@ -350,6 +384,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode { decrypter = new DecrypterV2(this); break; + case EncryptionVersion.V3: + decrypter = new DecrypterV3(this); + break; + case EncryptionVersion.Unknown: default: throw new ApplicationException("Unknown MC version"); From 6e8b32df21067d52db47ee9ca142584d20ae81cf Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 23 Feb 2012 10:59:02 +0100 Subject: [PATCH 11/13] Reverse sort comments --- .../deobfuscators/MaxtoCode/FileDecrypter.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index d06ccdbd..f4516b61 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -138,18 +138,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode { MagicHi = 0x1E8EECA3, Version = EncryptionVersion.V2, }, - // 4C622357 = Wed, 11 Aug 2010 04:13:11 - // 4C6220EC = Wed, 11 Aug 2010 04:02:52 // 4A5EEC64 = Thu, 16 Jul 2009 09:01:24 + // 4C6220EC = Wed, 11 Aug 2010 04:02:52 + // 4C622357 = Wed, 11 Aug 2010 04:13:11 new EncryptionInfo { MagicLo = 0xAA98B387, MagicHi = 0x128EECA3, Version = EncryptionVersion.V2, }, - // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 - // 4DC2FC75 = Thu, 05 May 2011 19:37:25 - // 4D0E220D = Sun, 19 Dec 2010 15:17:33 // 4C6E4605 = Fri, 20 Aug 2010 09:08:21 + // 4D0E220D = Sun, 19 Dec 2010 15:17:33 + // 4DC2FC75 = Thu, 05 May 2011 19:37:25 + // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 new EncryptionInfo { MagicLo = 0xAA98B387, MagicHi = 0xF28EECA3, @@ -161,8 +161,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode { MagicHi = 0xF28EEAA3, Version = EncryptionVersion.V2, }, - // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 // 4ED76740 = Thu, 01 Dec 2011 11:38:40 + // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 new EncryptionInfo { MagicLo = 0xAA983B87, MagicHi = 0xF28EECA3, @@ -183,21 +183,21 @@ namespace de4dot.code.deobfuscators.MaxtoCode { MagicHi = 0xD72B891F, Version = EncryptionVersion.V2, }, - // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 - // 4DC2FE0C = Thu, 05 May 2011 19:44:12 - // 4DC2FC75 = Thu, 05 May 2011 19:37:25 - // 4D0E220D = Sun, 19 Dec 2010 15:17:33 - // 4C6E4605 = Fri, 20 Aug 2010 09:08:21 - // 4C622357 = Wed, 11 Aug 2010 04:13:11 - // 4C6220EC = Wed, 11 Aug 2010 04:02:52 // 4A5EEC64 = Thu, 16 Jul 2009 09:01:24 + // 4C6220EC = Wed, 11 Aug 2010 04:02:52 + // 4C622357 = Wed, 11 Aug 2010 04:13:11 + // 4C6E4605 = Fri, 20 Aug 2010 09:08:21 + // 4D0E220D = Sun, 19 Dec 2010 15:17:33 + // 4DC2FC75 = Thu, 05 May 2011 19:37:25 + // 4DC2FE0C = Thu, 05 May 2011 19:44:12 + // 4DFA3D5D = Thu, 16 Jun 2011 17:29:01 new EncryptionInfo { MagicLo = 0x6A713B13, MagicHi = 0xD72B891F, Version = EncryptionVersion.V2, }, - // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 // 4ED76740 = Thu, 01 Dec 2011 11:38:40 + // 4EE1FAD1 = Fri, 09 Dec 2011 12:10:57 new EncryptionInfo { MagicLo = 0x6A731B13, MagicHi = 0xD72B891F, From 4ec4bb1d657b53d15fdd2596f1a71b0ddd2f6cfa Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 23 Feb 2012 11:52:19 +0100 Subject: [PATCH 12/13] MC actually does rename symbols so add an updated regex --- de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs index b5c986e2..cb21c5b5 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -25,8 +25,9 @@ namespace de4dot.code.deobfuscators.MaxtoCode { public class DeobfuscatorInfo : DeobfuscatorInfoBase { public const string THE_NAME = "MaxtoCode"; public const string THE_TYPE = "mc"; + const string DEFAULT_REGEX = @"!^[oO01l]{4,}$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX; public DeobfuscatorInfo() - : base() { + : base(DEFAULT_REGEX) { } public override string Name { From cee04d3bba4b09415160767fb66f030b696fbb3c Mon Sep 17 00:00:00 2001 From: de4dot Date: Sun, 26 Feb 2012 22:57:55 +0100 Subject: [PATCH 13/13] master was updated --- de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs | 6 +++++- de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs index cb21c5b5..d39b46a6 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -84,7 +84,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { mainType.find(); } - public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary dumpedMethods) { + public override bool getDecryptedModule(ref byte[] newFileData, ref DumpedMethods dumpedMethods) { if (!mainType.Detected) return false; @@ -113,5 +113,9 @@ namespace de4dot.code.deobfuscators.MaxtoCode { addTypeToBeRemoved(mainType.Type, "Obfuscator type"); addModuleReferencesToBeRemoved(mainType.ModuleReferences, "MC runtime module reference"); } + + public override IEnumerable getStringDecrypterMethods() { + return new List(); + } } } diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index f4516b61..8102c96c 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -569,7 +569,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { this.mainType = mainType; } - public bool decrypt(byte[] fileData, ref Dictionary dumpedMethods) { + public bool decrypt(byte[] fileData, ref DumpedMethods dumpedMethods) { var peImage = new PeImage(fileData); var peHeader = new PeHeader(mainType, peImage); var mcHeader = new McHeader(peImage, peHeader); @@ -583,8 +583,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode { return true; } - Dictionary decryptMethods(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { - var dumpedMethods = new Dictionary(); + DumpedMethods decryptMethods(PeImage peImage, PeHeader peHeader, McHeader mcHeader) { + var dumpedMethods = new DumpedMethods(); var methodInfos = new MethodInfos(mainType, peImage, peHeader, mcHeader); methodInfos.initializeInfos(); @@ -638,7 +638,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { dm.extraSections = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)); } - dumpedMethods[dm.token] = dm; + dumpedMethods.add(dm); } return dumpedMethods;