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;
|
||||
}
|
||||
|
||||
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<uint, DecryptedMethodInfo> infos = new Dictionary<uint, DecryptedMethodInfo>();
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user