Decrypt methods protected with older MC version
This commit is contained in:
parent
eb223537f0
commit
58a94a8420
|
@ -54,7 +54,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return (readUInt32(offset) ^ xorKey) - rvaDispl;
|
return (readUInt32(offset) ^ xorKey) - rvaDispl;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint readUInt32(int offset) {
|
public uint readUInt32(int offset) {
|
||||||
return BitConverter.ToUInt32(headerData, offset);
|
return BitConverter.ToUInt32(headerData, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,16 +109,75 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DecryptedMethodInfo {
|
enum EncryptionVersion {
|
||||||
public uint bodyRva;
|
Unknown,
|
||||||
public byte[] body;
|
V1,
|
||||||
|
V2,
|
||||||
public DecryptedMethodInfo(uint bodyRva, byte[] body) {
|
|
||||||
this.bodyRva = bodyRva;
|
|
||||||
this.body = body;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
class MethodInfos {
|
||||||
PeImage peImage;
|
PeImage peImage;
|
||||||
PeHeader peHeader;
|
PeHeader peHeader;
|
||||||
|
@ -128,17 +187,25 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
uint encryptedDataOffset;
|
uint encryptedDataOffset;
|
||||||
uint xorKey;
|
uint xorKey;
|
||||||
Dictionary<uint, DecryptedMethodInfo> infos = new Dictionary<uint, DecryptedMethodInfo>();
|
Dictionary<uint, DecryptedMethodInfo> infos = new Dictionary<uint, DecryptedMethodInfo>();
|
||||||
|
IDecrypter decrypter;
|
||||||
const int ENCRYPTED_DATA_INFO_SIZE = 0x13;
|
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) {
|
public MethodInfos(PeImage peImage, PeHeader peHeader, McHeader mcHeader) {
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
this.peHeader = peHeader;
|
this.peHeader = peHeader;
|
||||||
this.mcHeader = mcHeader;
|
this.mcHeader = mcHeader;
|
||||||
|
|
||||||
if (mcHeader.hasMagic(0x08C0, 0x6A731B13, 0xD72B891F))
|
structSize = getStructSize(mcHeader);
|
||||||
structSize = 0xC + 6 * ENCRYPTED_DATA_INFO_SIZE;
|
|
||||||
else
|
|
||||||
structSize = 0xC + 3 * ENCRYPTED_DATA_INFO_SIZE;
|
|
||||||
|
|
||||||
uint methodInfosRva = peHeader.getRva(0x0FF8, mcHeader.readUInt32(0x005A));
|
uint methodInfosRva = peHeader.getRva(0x0FF8, mcHeader.readUInt32(0x005A));
|
||||||
uint encryptedDataRva = peHeader.getRva(0x0FF0, mcHeader.readUInt32(0x0046));
|
uint encryptedDataRva = peHeader.getRva(0x0FF0, mcHeader.readUInt32(0x0046));
|
||||||
|
@ -147,6 +214,34 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
encryptedDataOffset = peImage.rvaToOffset(encryptedDataRva);
|
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) {
|
public DecryptedMethodInfo lookup(uint bodyRva) {
|
||||||
DecryptedMethodInfo info;
|
DecryptedMethodInfo info;
|
||||||
infos.TryGetValue(bodyRva, out info);
|
infos.TryGetValue(bodyRva, out info);
|
||||||
|
@ -181,7 +276,71 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return readUInt32(offset) ^ xorKey;
|
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() {
|
public void initializeInfos() {
|
||||||
|
initializeDecrypter();
|
||||||
|
|
||||||
int numMethods = readInt32(0) ^ readInt32(4);
|
int numMethods = readInt32(0) ^ readInt32(4);
|
||||||
if (numMethods < 0)
|
if (numMethods < 0)
|
||||||
throw new ApplicationException("Invalid number of encrypted methods");
|
throw new ApplicationException("Invalid number of encrypted methods");
|
||||||
|
@ -248,18 +407,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
throw new ApplicationException("Invalid realSize");
|
throw new ApplicationException("Invalid realSize");
|
||||||
|
|
||||||
var encrypted = readData(dataOffset, (int)encryptedSize);
|
var encrypted = readData(dataOffset, (int)encryptedSize);
|
||||||
byte[] decrypted;
|
var decrypted = decrypter.decrypt(type, encrypted);
|
||||||
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)
|
if (realSize > decrypted.Length)
|
||||||
throw new ApplicationException("Invalid decrypted length");
|
throw new ApplicationException("Invalid decrypted length");
|
||||||
Array.Resize(ref decrypted, (int)realSize);
|
Array.Resize(ref decrypted, (int)realSize);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user