de4dot-cex/de4dot.code/deobfuscators/Agile_NET/MethodsDecrypter.cs

627 lines
21 KiB
C#
Raw Normal View History

/*
2015-10-30 05:45:26 +08:00
Copyright (C) 2011-2015 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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
2012-04-22 20:16:33 +08:00
using System.IO;
using dnlib.IO;
using dnlib.PE;
using dnlib.DotNet;
using dnlib.DotNet.MD;
2012-04-28 14:50:37 +08:00
using de4dot.blocks;
using de4dot.code.AssemblyClient;
2012-11-06 23:38:39 +08:00
namespace de4dot.code.deobfuscators.Agile_NET {
class CodeHeader {
public byte[] signature;
public byte[] decryptionKey;
public uint totalCodeSize;
public uint numMethods;
public uint methodDefTableOffset; // Relative to start of metadata
public uint methodDefElemSize;
}
struct MethodInfo {
public uint codeOffs, codeSize, flags, localVarSigTok;
public MethodInfo(uint codeOffs, uint codeSize, uint flags, uint localVarSigTok) {
this.codeOffs = codeOffs;
this.codeSize = codeSize;
this.flags = flags;
this.localVarSigTok = localVarSigTok;
}
public override string ToString() {
return string.Format("{0:X8} {1:X8} {2:X8} {3:X8}", codeOffs, codeSize, flags, localVarSigTok);
}
}
class MethodsDecrypter {
2012-04-28 14:50:37 +08:00
static readonly byte[] oldSignature = new byte[16] { 0x1F, 0x68, 0x9D, 0x2B, 0x07, 0x4A, 0xA6, 0x4A, 0x92, 0xBB, 0x31, 0x7E, 0x60, 0x7F, 0xD7, 0xCD };
2012-04-23 21:00:42 +08:00
static readonly byte[] normalSignature = new byte[16] { 0x08, 0x44, 0x65, 0xE1, 0x8C, 0x82, 0x13, 0x4C, 0x9C, 0x85, 0xB4, 0x17, 0xDA, 0x51, 0xAD, 0x25 };
static readonly byte[] proSignature = new byte[16] { 0x68, 0xA0, 0xBB, 0x60, 0x13, 0x65, 0x5F, 0x41, 0xAE, 0x42, 0xAB, 0x42, 0x9B, 0x6B, 0x4E, 0xC1 };
2012-04-23 02:35:01 +08:00
enum SigType {
Unknown,
2012-04-28 14:50:37 +08:00
Old,
2012-04-23 02:35:01 +08:00
Normal,
Pro,
}
MyPEImage peImage;
2012-11-07 12:17:45 +08:00
ModuleDefMD module;
2012-04-23 03:03:06 +08:00
CliSecureRtType csRtType;
CodeHeader codeHeader = new CodeHeader();
IDecrypter decrypter;
2012-04-28 14:50:37 +08:00
SigType sigType;
interface IDecrypter {
2013-01-19 20:03:57 +08:00
MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections);
2012-04-22 20:16:33 +08:00
}
abstract class DecrypterBase : IDecrypter {
protected readonly MyPEImage peImage;
2012-04-23 21:00:42 +08:00
protected readonly CodeHeader codeHeader;
protected readonly uint endOfMetadata;
public DecrypterBase(MyPEImage peImage, CodeHeader codeHeader) {
this.peImage = peImage;
this.codeHeader = codeHeader;
var mdDir = peImage.Cor20Header.MetaData;
2013-01-19 20:03:57 +08:00
endOfMetadata = peImage.RvaToOffset((uint)mdDir.VirtualAddress + mdDir.Size);
}
2013-01-19 20:03:57 +08:00
public abstract MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections);
2012-04-23 02:35:01 +08:00
2013-01-19 20:03:57 +08:00
protected MethodBodyHeader GetCodeBytes(byte[] methodBody, out byte[] code, out byte[] extraSections) {
return MethodBodyParser.ParseMethodBody(MemoryImageStream.Create(methodBody), out code, out extraSections);
2012-04-23 02:35:01 +08:00
}
}
2012-04-28 14:50:37 +08:00
// CS 1.1 (could be other versions too)
class Decrypter10 {
MyPEImage peImage;
2012-04-28 14:50:37 +08:00
CsBlowfish blowfish;
public Decrypter10(MyPEImage peImage, byte[] key) {
2012-04-28 14:50:37 +08:00
this.peImage = peImage;
this.blowfish = new CsBlowfish(key);
}
2013-01-19 20:03:57 +08:00
public MethodBodyHeader Decrypt(uint bodyOffset, out byte[] code, out byte[] extraSections) {
peImage.Reader.Position = bodyOffset;
2013-01-19 20:03:57 +08:00
var mbHeader = MethodBodyParser.ParseMethodBody(peImage.Reader, out code, out extraSections);
blowfish.Decrypt(code);
2012-04-28 14:50:37 +08:00
return mbHeader;
}
}
2012-04-25 19:32:14 +08:00
// CS 3.0 (could be other versions too)
class Decrypter30 : DecrypterBase {
public Decrypter30(MyPEImage peImage, CodeHeader codeHeader)
2012-04-25 19:32:14 +08:00
: base(peImage, codeHeader) {
}
2013-01-19 20:03:57 +08:00
public override MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
peImage.Reader.Position = peImage.RvaToOffset(methodInfo.codeOffs);
return MethodBodyParser.ParseMethodBody(peImage.Reader, out code, out extraSections);
2012-04-25 19:32:14 +08:00
}
}
// CS 4.0 (could be other versions too)
2012-04-23 03:24:32 +08:00
class Decrypter40 : DecrypterBase {
public Decrypter40(MyPEImage peImage, CodeHeader codeHeader)
2012-04-23 03:24:32 +08:00
: base(peImage, codeHeader) {
}
2013-01-19 20:03:57 +08:00
public override MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
peImage.Reader.Position = endOfMetadata + methodInfo.codeOffs;
2013-01-19 20:03:57 +08:00
return MethodBodyParser.ParseMethodBody(peImage.Reader, out code, out extraSections);
2012-04-23 03:24:32 +08:00
}
}
2012-04-25 19:32:14 +08:00
// CS 4.5 (could be other versions too)
2012-04-23 02:35:01 +08:00
class Decrypter45 : DecrypterBase {
public Decrypter45(MyPEImage peImage, CodeHeader codeHeader)
2012-04-23 02:35:01 +08:00
: base(peImage, codeHeader) {
}
2013-01-19 20:03:57 +08:00
public override MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
var data = peImage.OffsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
2012-04-23 02:35:01 +08:00
for (int i = 0; i < data.Length; i++) {
byte b = data[i];
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x28 + i) % 16];
data[i] = b;
}
2013-01-19 20:03:57 +08:00
return GetCodeBytes(data, out code, out extraSections);
}
}
2012-04-23 21:02:15 +08:00
// CS 5.0+
class Decrypter5 : DecrypterBase {
2012-04-23 21:00:42 +08:00
readonly uint codeHeaderSize;
2012-04-23 03:03:06 +08:00
public Decrypter5(MyPEImage peImage, CodeHeader codeHeader, uint codeHeaderSize)
: base(peImage, codeHeader) {
2012-11-07 12:17:45 +08:00
this.codeHeaderSize = codeHeaderSize;
}
2013-01-19 20:03:57 +08:00
public override MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
byte[] data = peImage.OffsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
for (int i = 0; i < data.Length; i++) {
byte b = data[i];
2012-04-23 03:03:06 +08:00
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - codeHeaderSize + i) % 16];
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - codeHeaderSize + i + 7) % 16];
data[i] = b;
}
2013-01-19 20:03:57 +08:00
return GetCodeBytes(data, out code, out extraSections);
}
}
2012-04-23 21:02:15 +08:00
// CS 5.4+. Used when the anti-debugger protection is enabled
class ProDecrypter : DecrypterBase {
2012-04-23 21:00:42 +08:00
readonly uint[] key = new uint[4];
public ProDecrypter(MyPEImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) {
for (int i = 0; i < 4; i++)
2013-01-19 20:03:57 +08:00
key[i] = ReadUInt32_be(codeHeader.decryptionKey, i * 4);
}
2013-01-19 20:03:57 +08:00
public override MethodBodyHeader Decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
byte[] data = peImage.OffsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
int numQwords = (int)(methodInfo.codeSize / 8);
for (int i = 0; i < numQwords; i++) {
int offset = i * 8;
2013-01-19 20:03:57 +08:00
uint q0 = ReadUInt32_be(data, offset);
uint q1 = ReadUInt32_be(data, offset + 4);
const uint magic = 0x9E3779B8;
uint val = 0xC6EF3700; // magic * 0x20
for (int j = 0; j < 32; j++) {
q1 -= ((q0 << 4) + key[2]) ^ (val + q0) ^ ((q0 >> 5) + key[3]);
q0 -= ((q1 << 4) + key[0]) ^ (val + q1) ^ ((q1 >> 5) + key[1]);
val -= magic;
}
2013-01-19 20:03:57 +08:00
WriteUInt32_be(data, offset, q0);
WriteUInt32_be(data, offset + 4, q1);
}
2013-01-19 20:03:57 +08:00
return GetCodeBytes(data, out code, out extraSections);
}
2013-01-19 20:03:57 +08:00
static uint ReadUInt32_be(byte[] data, int offset) {
return (uint)((data[offset] << 24) +
(data[offset + 1] << 16) +
(data[offset + 2] << 8) +
data[offset + 3]);
}
2013-01-19 20:03:57 +08:00
static void WriteUInt32_be(byte[] data, int offset, uint value) {
data[offset] = (byte)(value >> 24);
data[offset + 1] = (byte)(value >> 16);
data[offset + 2] = (byte)(value >> 8);
data[offset + 3] = (byte)value;
}
}
2012-04-22 20:16:33 +08:00
interface ICsHeader {
2013-01-19 20:03:57 +08:00
IDecrypter CreateDecrypter();
List<MethodInfo> GetMethodInfos(uint codeHeaderOffset);
void PatchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos);
2012-04-22 20:16:33 +08:00
}
2012-04-23 03:03:06 +08:00
abstract class CsHeaderBase : ICsHeader {
protected readonly MethodsDecrypter methodsDecrypter;
protected readonly uint codeHeaderSize;
2012-04-22 20:16:33 +08:00
2012-04-23 03:03:06 +08:00
public CsHeaderBase(MethodsDecrypter methodsDecrypter, uint codeHeaderSize) {
2012-04-22 20:16:33 +08:00
this.methodsDecrypter = methodsDecrypter;
2012-04-23 03:03:06 +08:00
this.codeHeaderSize = codeHeaderSize;
2012-04-22 20:16:33 +08:00
}
2013-01-19 20:03:57 +08:00
public abstract IDecrypter CreateDecrypter();
2012-04-23 03:03:06 +08:00
2013-01-19 20:03:57 +08:00
public virtual void PatchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos) {
2012-04-23 02:35:01 +08:00
}
2013-01-19 20:03:57 +08:00
public abstract List<MethodInfo> GetMethodInfos(uint codeHeaderOffset);
2012-04-23 03:03:06 +08:00
2013-01-19 20:03:57 +08:00
protected List<MethodInfo> GetMethodInfos1(uint codeHeaderOffset) {
2012-04-23 03:03:06 +08:00
uint offset = codeHeaderOffset + methodsDecrypter.codeHeader.totalCodeSize + codeHeaderSize;
2012-04-22 20:16:33 +08:00
var methodInfos = new List<MethodInfo>((int)methodsDecrypter.codeHeader.numMethods);
2012-04-23 02:35:01 +08:00
for (int i = 0; i < (int)methodsDecrypter.codeHeader.numMethods; i++, offset += 4) {
2013-01-19 20:03:57 +08:00
uint codeOffs = methodsDecrypter.peImage.OffsetReadUInt32(offset);
2012-04-23 02:35:01 +08:00
methodInfos.Add(new MethodInfo(codeOffs, 0, 0, 0));
2012-04-22 20:16:33 +08:00
}
return methodInfos;
}
2013-01-19 20:03:57 +08:00
protected List<MethodInfo> GetMethodInfos2(uint codeHeaderOffset) {
2012-04-23 03:03:06 +08:00
uint offset = codeHeaderOffset + methodsDecrypter.codeHeader.totalCodeSize + codeHeaderSize;
2012-04-22 20:16:33 +08:00
var methodInfos = new List<MethodInfo>((int)methodsDecrypter.codeHeader.numMethods);
2012-04-23 02:35:01 +08:00
for (int i = 0; i < (int)methodsDecrypter.codeHeader.numMethods; i++, offset += 8) {
2013-01-19 20:03:57 +08:00
uint codeOffs = methodsDecrypter.peImage.OffsetReadUInt32(offset);
uint codeSize = methodsDecrypter.peImage.OffsetReadUInt32(offset + 4);
2012-04-23 02:35:01 +08:00
methodInfos.Add(new MethodInfo(codeOffs, codeSize, 0, 0));
2012-04-22 20:16:33 +08:00
}
return methodInfos;
}
2013-01-19 20:03:57 +08:00
protected List<MethodInfo> GetMethodInfos4(uint codeHeaderOffset) {
2012-04-23 03:03:06 +08:00
uint offset = codeHeaderOffset + methodsDecrypter.codeHeader.totalCodeSize + codeHeaderSize;
var methodInfos = new List<MethodInfo>((int)methodsDecrypter.codeHeader.numMethods);
for (int i = 0; i < (int)methodsDecrypter.codeHeader.numMethods; i++, offset += 16) {
2013-01-19 20:03:57 +08:00
uint codeOffs = methodsDecrypter.peImage.OffsetReadUInt32(offset);
uint codeSize = methodsDecrypter.peImage.OffsetReadUInt32(offset + 4);
uint flags = methodsDecrypter.peImage.OffsetReadUInt32(offset + 8);
uint localVarSigTok = methodsDecrypter.peImage.OffsetReadUInt32(offset + 12);
2012-04-23 03:03:06 +08:00
methodInfos.Add(new MethodInfo(codeOffs, codeSize, flags, localVarSigTok));
}
return methodInfos;
}
}
2012-04-25 19:32:14 +08:00
// CS 3.0 (could be other versions too)
class CsHeader30 : CsHeaderBase {
public CsHeader30(MethodsDecrypter methodsDecrypter)
: base(methodsDecrypter, 0x28) {
}
2013-01-19 20:03:57 +08:00
public override IDecrypter CreateDecrypter() {
2012-04-25 19:32:14 +08:00
return new Decrypter30(methodsDecrypter.peImage, methodsDecrypter.codeHeader);
}
2013-01-19 20:03:57 +08:00
public override List<MethodInfo> GetMethodInfos(uint codeHeaderOffset) {
return GetMethodInfos1(codeHeaderOffset);
2012-04-25 19:32:14 +08:00
}
}
// CS 4.0 (could be other versions too)
2012-04-23 03:03:06 +08:00
class CsHeader40 : CsHeaderBase {
public CsHeader40(MethodsDecrypter methodsDecrypter)
: base(methodsDecrypter, 0x28) {
}
2013-01-19 20:03:57 +08:00
public override IDecrypter CreateDecrypter() {
2012-04-23 03:24:32 +08:00
return new Decrypter40(methodsDecrypter.peImage, methodsDecrypter.codeHeader);
2012-04-23 03:03:06 +08:00
}
2013-01-19 20:03:57 +08:00
public override List<MethodInfo> GetMethodInfos(uint codeHeaderOffset) {
return GetMethodInfos1(codeHeaderOffset);
2012-04-22 20:16:33 +08:00
}
2012-04-23 02:35:01 +08:00
}
2012-04-25 19:32:14 +08:00
// CS 4.5 (could be other versions too)
2012-04-23 03:03:06 +08:00
class CsHeader45 : CsHeaderBase {
public CsHeader45(MethodsDecrypter methodsDecrypter)
: base(methodsDecrypter, 0x28) {
}
2012-04-22 20:16:33 +08:00
2013-01-19 20:03:57 +08:00
public override IDecrypter CreateDecrypter() {
2012-04-23 03:03:06 +08:00
return new Decrypter45(methodsDecrypter.peImage, methodsDecrypter.codeHeader);
}
2013-01-19 20:03:57 +08:00
public override List<MethodInfo> GetMethodInfos(uint codeHeaderOffset) {
return GetMethodInfos2(codeHeaderOffset);
2012-04-23 03:03:06 +08:00
}
}
// CS 5.0+
class CsHeader5 : CsHeaderBase {
public CsHeader5(MethodsDecrypter methodsDecrypter, uint codeHeaderSize)
: base(methodsDecrypter, codeHeaderSize) {
2012-04-23 02:35:01 +08:00
}
2013-01-19 20:03:57 +08:00
public override IDecrypter CreateDecrypter() {
switch (GetSigType(methodsDecrypter.codeHeader.signature)) {
2012-04-23 02:35:01 +08:00
case SigType.Normal:
2012-04-23 21:02:15 +08:00
return new Decrypter5(methodsDecrypter.peImage, methodsDecrypter.codeHeader, codeHeaderSize);
2012-04-23 02:35:01 +08:00
case SigType.Pro:
return new ProDecrypter(methodsDecrypter.peImage, methodsDecrypter.codeHeader);
case SigType.Unknown:
default:
throw new ArgumentException("sig");
}
}
2013-01-19 20:03:57 +08:00
public override List<MethodInfo> GetMethodInfos(uint codeHeaderOffset) {
2012-04-23 03:03:06 +08:00
if (codeHeaderSize == 0x28)
2013-01-19 20:03:57 +08:00
return GetMethodInfos2(codeHeaderOffset);
return GetMethodInfos4(codeHeaderOffset);
2012-04-23 02:35:01 +08:00
}
2013-01-19 20:03:57 +08:00
public override void PatchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos) {
uint offset = (uint)methodDefTable.StartOffset - methodDefTable.RowSize;
2012-04-23 02:35:01 +08:00
foreach (var methodInfo in methodInfos) {
offset += methodDefTable.RowSize;
2012-04-23 02:35:01 +08:00
if (methodInfo.flags == 0 || methodInfo.codeOffs == 0)
continue;
2013-01-19 20:03:57 +08:00
uint rva = methodsDecrypter.peImage.OffsetReadUInt32(offset);
methodsDecrypter.peImage.WriteUInt16(rva, (ushort)methodInfo.flags);
methodsDecrypter.peImage.WriteUInt32(rva + 8, methodInfo.localVarSigTok);
2012-04-23 02:35:01 +08:00
}
2012-04-22 20:16:33 +08:00
}
}
2012-04-23 02:35:01 +08:00
enum CsHeaderVersion {
Unknown,
2012-04-28 14:50:37 +08:00
V10,
2012-04-25 19:32:14 +08:00
V30,
2012-04-23 02:35:01 +08:00
V40,
V45,
2012-04-23 03:03:06 +08:00
V50, // 5.0, possibly also 5.1
V52, // 5.2+ (or maybe 5.1+)
2012-04-23 02:35:01 +08:00
}
2013-01-19 20:03:57 +08:00
List<CsHeaderVersion> GetCsHeaderVersions(uint codeHeaderOffset, MDTable methodDefTable) {
2012-04-28 14:50:37 +08:00
if (sigType == SigType.Old)
return new List<CsHeaderVersion> { CsHeaderVersion.V10 };
2013-01-19 20:03:57 +08:00
if (!IsOldHeader(methodDefTable))
2012-04-25 19:32:14 +08:00
return new List<CsHeaderVersion> { CsHeaderVersion.V52 };
2013-01-19 20:03:57 +08:00
if (csRtType.IsAtLeastVersion50())
2012-04-25 19:32:14 +08:00
return new List<CsHeaderVersion> { CsHeaderVersion.V50 };
2013-01-19 20:03:57 +08:00
if (IsCsHeader40(codeHeaderOffset)) {
2012-04-25 19:32:14 +08:00
return new List<CsHeaderVersion> {
CsHeaderVersion.V40,
CsHeaderVersion.V30,
};
}
return new List<CsHeaderVersion> {
CsHeaderVersion.V45,
CsHeaderVersion.V50,
};
2012-04-23 02:35:01 +08:00
}
2013-01-19 20:03:57 +08:00
bool IsCsHeader40(uint codeHeaderOffset) {
2012-04-23 02:35:01 +08:00
try {
uint offset = codeHeaderOffset + codeHeader.totalCodeSize + 0x28;
uint prevCodeOffs = 0;
for (int i = 0; i < (int)codeHeader.numMethods; i++, offset += 4) {
2013-01-19 20:03:57 +08:00
uint codeOffs = peImage.OffsetReadUInt32(offset);
2012-04-23 02:35:01 +08:00
if (prevCodeOffs != 0 && codeOffs != 0 && codeOffs < prevCodeOffs)
return false;
if (codeOffs != 0)
prevCodeOffs = codeOffs;
}
return true;
}
catch (IOException) {
return false;
}
}
2013-01-19 20:03:57 +08:00
bool IsOldHeader(MDTable methodDefTable) {
if (methodDefTable.RowSize != codeHeader.methodDefElemSize)
2012-04-22 20:16:33 +08:00
return true;
2013-01-19 20:03:57 +08:00
if ((uint)methodDefTable.StartOffset - peImage.RvaToOffset((uint)peImage.Cor20Header.MetaData.VirtualAddress) != codeHeader.methodDefTableOffset)
2012-04-22 20:16:33 +08:00
return true;
return false;
}
2013-01-19 20:03:57 +08:00
ICsHeader CreateCsHeader(CsHeaderVersion version) {
2012-04-25 19:32:14 +08:00
switch (version) {
case CsHeaderVersion.V30: return new CsHeader30(this);
2012-04-23 02:35:01 +08:00
case CsHeaderVersion.V40: return new CsHeader40(this);
case CsHeaderVersion.V45: return new CsHeader45(this);
2012-04-23 03:03:06 +08:00
case CsHeaderVersion.V50: return new CsHeader5(this, 0x28);
case CsHeaderVersion.V52: return new CsHeader5(this, 0x30);
2012-04-23 02:35:01 +08:00
default: throw new ApplicationException("Unknown CS header");
2012-04-22 20:16:33 +08:00
}
}
2012-04-26 07:48:59 +08:00
enum DecryptResult {
NotEncrypted,
Decrypted,
Error,
}
2013-01-19 20:03:57 +08:00
public bool Decrypt(MyPEImage peImage, ModuleDefMD module, CliSecureRtType csRtType, ref DumpedMethods dumpedMethods) {
2012-04-25 19:32:14 +08:00
this.peImage = peImage;
this.csRtType = csRtType;
2012-04-28 14:50:37 +08:00
this.module = module;
2012-04-26 07:48:59 +08:00
2013-01-19 20:03:57 +08:00
switch (Decrypt2(ref dumpedMethods)) {
2012-04-26 07:48:59 +08:00
case DecryptResult.Decrypted: return true;
case DecryptResult.NotEncrypted: return false;
case DecryptResult.Error:
2012-11-22 12:50:05 +08:00
Logger.n("Using dynamic method decryption");
2013-01-19 20:03:57 +08:00
byte[] moduleCctorBytes = GetModuleCctorBytes(csRtType);
dumpedMethods = de4dot.code.deobfuscators.MethodsDecrypter.Decrypt(module, moduleCctorBytes);
2012-04-25 19:32:14 +08:00
return true;
2012-04-26 07:48:59 +08:00
default:
throw new ApplicationException("Invalid DecryptResult");
}
2012-04-25 19:32:14 +08:00
}
2013-01-19 20:03:57 +08:00
static byte[] GetModuleCctorBytes(CliSecureRtType csRtType) {
2012-04-25 19:32:14 +08:00
var initMethod = csRtType.InitializeMethod;
if (initMethod == null)
return null;
uint initToken = initMethod.MDToken.ToUInt32();
2012-04-25 19:32:14 +08:00
var moduleCctorBytes = new byte[6];
moduleCctorBytes[0] = 0x28; // call
moduleCctorBytes[1] = (byte)initToken;
moduleCctorBytes[2] = (byte)(initToken >> 8);
moduleCctorBytes[3] = (byte)(initToken >> 16);
moduleCctorBytes[4] = (byte)(initToken >> 24);
moduleCctorBytes[5] = 0x2A; // ret
return moduleCctorBytes;
}
2013-01-19 20:03:57 +08:00
static uint GetCodeHeaderOffset(MyPEImage peImage) {
return peImage.RvaToOffset((uint)peImage.Cor20Header.MetaData.VirtualAddress + peImage.Cor20Header.MetaData.Size);
}
2012-04-28 14:50:37 +08:00
static string[] sections = new string[] {
".text", ".rsrc", ".data", ".rdata",
};
2013-01-19 20:03:57 +08:00
static uint GetOldCodeHeaderOffset(MyPEImage peImage) {
var sect = GetLastOf(peImage, sections);
if (sect == null || sect.VirtualSize < 0x100)
2012-04-28 14:50:37 +08:00
return 0;
2013-01-19 20:03:57 +08:00
return peImage.RvaToOffset((uint)sect.VirtualAddress + sect.VirtualSize - 0x100);
2012-04-28 14:50:37 +08:00
}
2013-01-19 20:03:57 +08:00
static ImageSectionHeader GetLastOf(MyPEImage peImage, string[] sections) {
ImageSectionHeader sect = null;
2012-04-28 14:50:37 +08:00
foreach (var name in sections) {
2013-01-19 20:03:57 +08:00
var sect2 = peImage.FindSection(name);
2012-04-28 14:50:37 +08:00
if (sect2 == null)
continue;
if (sect == null || sect2.VirtualAddress > sect.VirtualAddress)
2012-04-28 14:50:37 +08:00
sect = sect2;
}
return sect;
}
2013-01-19 20:03:57 +08:00
DecryptResult Decrypt2(ref DumpedMethods dumpedMethods) {
uint codeHeaderOffset = InitializeCodeHeader();
2012-04-28 14:50:37 +08:00
if (sigType == SigType.Unknown)
2012-04-26 07:48:59 +08:00
return DecryptResult.NotEncrypted;
var methodDefTable = peImage.MetaData.TablesStream.MethodTable;
2013-01-19 20:03:57 +08:00
foreach (var version in GetCsHeaderVersions(codeHeaderOffset, methodDefTable)) {
2012-04-25 19:32:14 +08:00
try {
2012-04-28 14:50:37 +08:00
if (version == CsHeaderVersion.V10)
2013-01-19 20:03:57 +08:00
DecryptMethodsOld(methodDefTable, ref dumpedMethods);
2012-04-28 14:50:37 +08:00
else
2013-01-19 20:03:57 +08:00
DecryptMethods(codeHeaderOffset, methodDefTable, CreateCsHeader(version), ref dumpedMethods);
2012-04-26 07:48:59 +08:00
return DecryptResult.Decrypted;
2012-04-25 19:32:14 +08:00
}
catch {
}
}
2012-04-26 07:48:59 +08:00
return DecryptResult.Error;
2012-04-25 19:32:14 +08:00
}
2013-01-19 20:03:57 +08:00
uint InitializeCodeHeader() {
uint codeHeaderOffset = GetCodeHeaderOffset(peImage);
ReadCodeHeader(codeHeaderOffset);
sigType = GetSigType(codeHeader.signature);
2012-04-28 14:50:37 +08:00
if (sigType == SigType.Unknown) {
2013-01-19 20:03:57 +08:00
codeHeaderOffset = GetOldCodeHeaderOffset(peImage);
2012-04-28 14:50:37 +08:00
if (codeHeaderOffset != 0) {
2013-01-19 20:03:57 +08:00
ReadCodeHeader(codeHeaderOffset);
sigType = GetSigType(codeHeader.signature);
2012-04-28 14:50:37 +08:00
}
}
return codeHeaderOffset;
}
2013-01-19 20:03:57 +08:00
void DecryptMethodsOld(MDTable methodDefTable, ref DumpedMethods dumpedMethods) {
2012-04-28 14:50:37 +08:00
dumpedMethods = new DumpedMethods();
var decrypter = new Decrypter10(peImage, codeHeader.decryptionKey);
for (uint rid = 1; rid <= methodDefTable.Rows; rid++) {
2012-04-28 14:50:37 +08:00
var dm = new DumpedMethod();
var method = (MethodDef)module.ResolveMethod(rid);
if (method == null || method.DeclaringType == module.GlobalType)
2012-04-28 14:50:37 +08:00
continue;
2013-01-19 20:03:57 +08:00
peImage.ReadMethodTableRowTo(dm, rid);
if (dm.mdRVA == 0)
2012-04-28 14:50:37 +08:00
continue;
2013-01-19 20:03:57 +08:00
uint bodyOffset = peImage.RvaToOffset(dm.mdRVA);
2012-04-28 14:50:37 +08:00
2013-01-19 20:03:57 +08:00
var mbHeader = decrypter.Decrypt(bodyOffset, out dm.code, out dm.extraSections);
peImage.UpdateMethodHeaderInfo(dm, mbHeader);
2012-04-28 14:50:37 +08:00
2013-01-19 20:03:57 +08:00
dumpedMethods.Add(dm);
2012-04-28 14:50:37 +08:00
}
}
2013-01-19 20:03:57 +08:00
void DecryptMethods(uint codeHeaderOffset, MDTable methodDefTable, ICsHeader csHeader, ref DumpedMethods dumpedMethods) {
var methodInfos = csHeader.GetMethodInfos(codeHeaderOffset);
csHeader.PatchMethodTable(methodDefTable, methodInfos);
2012-02-25 13:14:19 +08:00
dumpedMethods = new DumpedMethods();
2013-01-19 20:03:57 +08:00
decrypter = csHeader.CreateDecrypter();
for (uint rid = 1; rid <= (uint)methodInfos.Count; rid++) {
var methodInfo = methodInfos[(int)rid - 1];
if (methodInfo.codeOffs == 0)
continue;
var dm = new DumpedMethod();
2013-01-19 20:03:57 +08:00
peImage.ReadMethodTableRowTo(dm, rid);
2013-01-19 20:03:57 +08:00
var mbHeader = decrypter.Decrypt(methodInfo, out dm.code, out dm.extraSections);
peImage.UpdateMethodHeaderInfo(dm, mbHeader);
2013-01-19 20:03:57 +08:00
dumpedMethods.Add(dm);
}
}
2013-01-19 20:03:57 +08:00
void ReadCodeHeader(uint offset) {
codeHeader.signature = peImage.OffsetReadBytes(offset, 16);
codeHeader.decryptionKey = peImage.OffsetReadBytes(offset + 0x10, 16);
codeHeader.totalCodeSize = peImage.OffsetReadUInt32(offset + 0x20);
codeHeader.numMethods = peImage.OffsetReadUInt32(offset + 0x24);
codeHeader.methodDefTableOffset = peImage.OffsetReadUInt32(offset + 0x28);
codeHeader.methodDefElemSize = peImage.OffsetReadUInt32(offset + 0x2C);
}
2013-01-19 20:03:57 +08:00
static SigType GetSigType(byte[] sig) {
if (Utils.Compare(sig, normalSignature))
2012-04-23 02:35:01 +08:00
return SigType.Normal;
2013-01-19 20:03:57 +08:00
else if (Utils.Compare(sig, proSignature))
2012-04-23 02:35:01 +08:00
return SigType.Pro;
2013-01-19 20:03:57 +08:00
else if (Utils.Compare(sig, oldSignature))
2012-04-28 14:50:37 +08:00
return SigType.Old;
2012-04-23 02:35:01 +08:00
return SigType.Unknown;
}
2013-01-19 20:03:57 +08:00
static bool IsValidSignature(byte[] signature) {
return GetSigType(signature) != SigType.Unknown;
2012-04-23 02:35:01 +08:00
}
2013-01-19 20:03:57 +08:00
public static bool Detect(MyPEImage peImage) {
try {
2013-01-19 20:03:57 +08:00
uint codeHeaderOffset = GetCodeHeaderOffset(peImage);
if (IsValidSignature(peImage.OffsetReadBytes(codeHeaderOffset, 16)))
2012-04-28 14:50:37 +08:00
return true;
}
catch {
}
2012-04-28 14:50:37 +08:00
try {
2013-01-19 20:03:57 +08:00
uint codeHeaderOffset = GetOldCodeHeaderOffset(peImage);
if (codeHeaderOffset != 0 && IsValidSignature(peImage.OffsetReadBytes(codeHeaderOffset, 16)))
2012-04-28 14:50:37 +08:00
return true;
}
catch {
}
return false;
}
}
}