diff --git a/blocks/PE/PeImage.cs b/blocks/PE/PeImage.cs index 360e7c55..b0e88ff3 100644 --- a/blocks/PE/PeImage.cs +++ b/blocks/PE/PeImage.cs @@ -71,6 +71,14 @@ namespace de4dot.PE { init(); } + public SectionHeader findSection(string displayName) { + foreach (var section in sectionHeaders) { + if (section.displayName == displayName) + return section; + } + return null; + } + void seek(uint position) { reader.BaseStream.Position = position; } diff --git a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs index 6073dfd5..738af998 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/FileDecrypter.cs @@ -36,17 +36,17 @@ namespace de4dot.code.deobfuscators.MaxtoCode { class PeHeader { const int XOR_KEY = 0x7ABF931; + EncryptionVersion version; byte[] headerData; - uint rvaDispl1; - uint rvaDispl2; + + public EncryptionVersion EncryptionVersion { + get { return version; } + } public PeHeader(MainType mainType, PeImage peImage) { - headerData = getPeHeaderData(peImage); - - if (!mainType.IsOld && peImage.readUInt32(0x2008) != 0x48) { - rvaDispl1 = readUInt32(0x0FB0) ^ XOR_KEY; - rvaDispl2 = readUInt32(0x0FB4) ^ XOR_KEY; - } + uint headerOffset; + version = getHeaderOffsetAndVersion(peImage, out headerOffset); + headerData = peImage.offsetReadBytes(headerOffset, 0x1000); } public uint getMcKeyRva() { @@ -54,39 +54,50 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } public uint getRva1(int offset, uint xorKey) { - return (readUInt32(offset) ^ xorKey) - rvaDispl1; + return (readUInt32(offset) ^ xorKey); } public uint getRva2(int offset, uint xorKey) { - return (readUInt32(offset) ^ xorKey) - rvaDispl2; + return (readUInt32(offset) ^ xorKey); } public uint readUInt32(int offset) { return BitConverter.ToUInt32(headerData, offset); } - static byte[] getPeHeaderData(PeImage peImage) { - var data = new byte[0x1000]; + static EncryptionVersion getHeaderOffsetAndVersion(PeImage peImage, out uint headerOffset) { + headerOffset = 0; - var firstSection = peImage.Sections[0]; - readTo(peImage, data, 0, 0, firstSection.pointerToRawData); + var version = getVersion(peImage, headerOffset); + if (version != EncryptionVersion.Unknown) + return version; - 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); + var section = peImage.findSection(".rsrc"); + if (section == null) + return EncryptionVersion.Unknown; + + headerOffset = section.pointerToRawData; + uint end = section.pointerToRawData + section.sizeOfRawData - 0x1000 + 1; + while (headerOffset < end) { + version = getVersion(peImage, headerOffset); + if (version != EncryptionVersion.Unknown) + return version; + headerOffset++; } - return data; + return EncryptionVersion.Unknown; } - 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); + static EncryptionVersion getVersion(PeImage peImage, uint headerOffset) { + uint m1lo = peImage.offsetReadUInt32(headerOffset + 0x900); + uint m1hi = peImage.offsetReadUInt32(headerOffset + 0x904); + + foreach (var info in encryptionInfos_Rva900h) { + if (info.MagicLo == m1lo && info.MagicHi == m1hi) + return info.Version; + } + + return EncryptionVersion.Unknown; } } @@ -118,6 +129,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { V2, V3, V4, + V5, } class EncryptionInfo { @@ -126,7 +138,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { public EncryptionVersion Version { get; set; } } - static EncryptionInfo[] encryptionInfos_Rva900h = new EncryptionInfo[] { + static readonly EncryptionInfo[] encryptionInfos_Rva900h = new EncryptionInfo[] { // PE header timestamp // 462FA2D2 = Wed, 25 Apr 2007 18:49:54 (3.20) new EncryptionInfo { @@ -176,9 +188,15 @@ namespace de4dot.code.deobfuscators.MaxtoCode { MagicHi = 0xF28EE0A3, Version = EncryptionVersion.V4, }, + // 4F8E262C = Wed, 18 Apr 2012 02:25:48 + new EncryptionInfo { + MagicLo = 0xBA983B87, + MagicHi = 0xF28EDDA3, + Version = EncryptionVersion.V5, + }, }; - static EncryptionInfo[] encryptionInfos_McKey8C0h = new EncryptionInfo[] { + static readonly EncryptionInfo[] encryptionInfos_McKey8C0h = new EncryptionInfo[] { // 462FA2D2 = Wed, 25 Apr 2007 18:49:54 (3.20) new EncryptionInfo { MagicLo = 0x6AA13B13, @@ -217,6 +235,12 @@ namespace de4dot.code.deobfuscators.MaxtoCode { MagicHi = 0xD72B8A1F, Version = EncryptionVersion.V4, }, + // 4F8E262C = Wed, 18 Apr 2012 02:25:48 + new EncryptionInfo { + MagicLo = 0xAA731B13, + MagicHi = 0xD723891F, + Version = EncryptionVersion.V5, + }, }; class MethodInfos { @@ -268,8 +292,9 @@ namespace de4dot.code.deobfuscators.MaxtoCode { } EncryptionVersion getVersion() { - uint m1lo = peHeader.readUInt32(0x900); - uint m1hi = peHeader.readUInt32(0x904); + if (peHeader.EncryptionVersion != EncryptionVersion.Unknown) + return peHeader.EncryptionVersion; + uint m2lo = mcKey.readUInt32(0x8C0); uint m2hi = mcKey.readUInt32(0x8C4); @@ -278,12 +303,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode { 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); + Log.w("Could not detect MC version. Magic2: {0:X8} {1:X8}", m2lo, m2hi); return EncryptionVersion.Unknown; } @@ -354,12 +374,14 @@ namespace de4dot.code.deobfuscators.MaxtoCode { static readonly int[] typeToTypesV2 = new int[] { -1, 3, 2, 1, 4, 5, 6, 7 }; static readonly int[] typeToTypesV3 = new int[] { -1, 1, 2, 3, 4, 5, 6, 7 }; static readonly int[] typeToTypesV4 = new int[] { -1, 2, 1, 3, 4, 5, 6, 7 }; + static readonly int[] typeToTypesV5 = new int[] { -1, 4, 2, 3, 1, 5, 6, 7 }; void initializeDecrypter() { switch (getVersion()) { case EncryptionVersion.V1: decrypter = new Decrypter(this, typeToTypesV1); break; case EncryptionVersion.V2: decrypter = new Decrypter(this, typeToTypesV2); break; case EncryptionVersion.V3: decrypter = new Decrypter(this, typeToTypesV3); break; case EncryptionVersion.V4: decrypter = new Decrypter(this, typeToTypesV4); break; + case EncryptionVersion.V5: decrypter = new Decrypter(this, typeToTypesV5); break; case EncryptionVersion.Unknown: default: @@ -375,15 +397,14 @@ namespace de4dot.code.deobfuscators.MaxtoCode { throw new ApplicationException("Invalid number of encrypted methods"); xorKey = (uint)numMethods; - uint rvaDispl = !mainType.IsOld && 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 methodBodyRva = readEncryptedUInt32(offset); uint totalSize = readEncryptedUInt32(offset + 4); - uint methodInstructionRva = readEncryptedUInt32(offset + 8) - rvaDispl; + uint methodInstructionRva = readEncryptedUInt32(offset + 8); var decryptedData = new byte[totalSize];