Decrypt methods encrypted with the new methods encrypter
This commit is contained in:
parent
a94d1406db
commit
7617d92b3b
|
@ -136,8 +136,10 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
byte[] fileData = DeobUtils.readModule(module);
|
||||
var peImage = new PE.PeImage(fileData);
|
||||
|
||||
if (!new MethodsDecrypter().decrypt(peImage, ref dumpedMethods))
|
||||
if (!new MethodsDecrypter().decrypt(peImage, ref dumpedMethods)) {
|
||||
Log.v("Methods aren't encrypted or invalid signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
newFileData = fileData;
|
||||
return true;
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
public byte[] decryptionKey;
|
||||
public uint totalCodeSize;
|
||||
public uint numMethods;
|
||||
public uint methodDefTableOffset;
|
||||
public uint methodDefTableOffset; // Relative to start of metadata
|
||||
public uint methodDefElemSize;
|
||||
}
|
||||
|
||||
|
@ -47,22 +47,127 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
}
|
||||
|
||||
class MethodsDecrypter {
|
||||
static byte[] SIGNATURE = new byte[16] { 0x08, 0x44, 0x65, 0xE1, 0x8C, 0x82, 0x13, 0x4C, 0x9C, 0x85, 0xB4, 0x17, 0xDA, 0x51, 0xAD, 0x25 };
|
||||
static byte[] normalSignature = new byte[16] { 0x08, 0x44, 0x65, 0xE1, 0x8C, 0x82, 0x13, 0x4C, 0x9C, 0x85, 0xB4, 0x17, 0xDA, 0x51, 0xAD, 0x25 };
|
||||
static byte[] proSignature = new byte[16] { 0x68, 0xA0, 0xBB, 0x60, 0x13, 0x65, 0x5F, 0x41, 0xAE, 0x42, 0xAB, 0x42, 0x9B, 0x6B, 0x4E, 0xC1 };
|
||||
|
||||
PE.PeImage peImage;
|
||||
CodeHeader codeHeader = new CodeHeader();
|
||||
uint endOfMetadata;
|
||||
IDecrypter decrypter;
|
||||
|
||||
interface IDecrypter {
|
||||
byte[] decrypt(MethodInfo methodInfo);
|
||||
}
|
||||
|
||||
abstract class DecrypterBase : IDecrypter {
|
||||
protected PE.PeImage peImage;
|
||||
protected CodeHeader codeHeader;
|
||||
protected uint endOfMetadata;
|
||||
|
||||
public DecrypterBase(PE.PeImage peImage, CodeHeader codeHeader) {
|
||||
this.peImage = peImage;
|
||||
this.codeHeader = codeHeader;
|
||||
endOfMetadata = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
|
||||
}
|
||||
|
||||
public abstract byte[] decrypt(MethodInfo methodInfo);
|
||||
|
||||
protected static byte[] getCodeBytes(byte[] methodBody) {
|
||||
int codeOffset, codeSize;
|
||||
if ((methodBody[0] & 3) == 2) {
|
||||
codeOffset = 1;
|
||||
codeSize = methodBody[0] >> 2;
|
||||
}
|
||||
else {
|
||||
codeOffset = 4 * (methodBody[1] >> 4);
|
||||
codeSize = BitConverter.ToInt32(methodBody, 4);
|
||||
}
|
||||
|
||||
var code = new byte[codeSize];
|
||||
Array.Copy(methodBody, codeOffset, code, 0, codeSize);
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
class NormalDecrypter : DecrypterBase {
|
||||
public NormalDecrypter(PE.PeImage peImage, CodeHeader codeHeader)
|
||||
: base(peImage, codeHeader) {
|
||||
}
|
||||
|
||||
public override byte[] decrypt(MethodInfo methodInfo) {
|
||||
byte[] data = peImage.offsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
|
||||
for (int i = 0; i < data.Length; i++) {
|
||||
byte b = data[i];
|
||||
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x30 + i) % 16];
|
||||
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x30 + i + 7) % 16];
|
||||
data[i] = b;
|
||||
}
|
||||
return getCodeBytes(data);
|
||||
}
|
||||
}
|
||||
|
||||
// Used when the anti-debugger protection is enabled
|
||||
class ProDecrypter : DecrypterBase {
|
||||
uint[] key = new uint[4];
|
||||
|
||||
public ProDecrypter(PE.PeImage peImage, CodeHeader codeHeader)
|
||||
: base(peImage, codeHeader) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
key[i] = be_readUint32(codeHeader.decryptionKey, i * 4);
|
||||
}
|
||||
|
||||
public override byte[] decrypt(MethodInfo methodInfo) {
|
||||
byte[] data = peImage.offsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
|
||||
|
||||
uint[] qword = new uint[2];
|
||||
int numQwords = (int)(methodInfo.codeSize / 8);
|
||||
for (int i = 0; i < numQwords; i++) {
|
||||
int offset = i * 8;
|
||||
uint q0 = be_readUint32(data, offset);
|
||||
uint q1 = be_readUint32(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;
|
||||
}
|
||||
|
||||
be_writeUint32(data, offset, q0);
|
||||
be_writeUint32(data, offset + 4, q1);
|
||||
}
|
||||
|
||||
return getCodeBytes(data);
|
||||
}
|
||||
|
||||
static uint be_readUint32(byte[] data, int offset) {
|
||||
return (uint)((data[offset] << 24) +
|
||||
(data[offset + 1] << 16) +
|
||||
(data[offset + 2] << 8) +
|
||||
data[offset + 3]);
|
||||
}
|
||||
|
||||
static void be_writeUint32(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;
|
||||
}
|
||||
}
|
||||
|
||||
public bool decrypt(PE.PeImage peImage, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
|
||||
this.peImage = peImage;
|
||||
|
||||
endOfMetadata = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
|
||||
uint offset = endOfMetadata;
|
||||
uint offset = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
|
||||
if (!readCodeHeader(offset))
|
||||
return false;
|
||||
|
||||
var methodInfos = getMethodInfos(offset + 0x30 + codeHeader.totalCodeSize);
|
||||
var metadataTables = peImage.Cor20Header.createMetadataTables();
|
||||
var methodDefTable = metadataTables.getMetadataType(PE.MetadataIndex.iMethodDef);
|
||||
if (methodDefTable.totalSize != codeHeader.methodDefElemSize)
|
||||
return false;
|
||||
|
||||
var methodInfos = getMethodInfos(offset + 0x30 + codeHeader.totalCodeSize);
|
||||
|
||||
offset = methodDefTable.fileOffset - methodDefTable.totalSize;
|
||||
foreach (var methodInfo in methodInfos) {
|
||||
|
@ -91,7 +196,7 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
dm.mdSignature = peImage.offsetRead(offset + (uint)methodDefTable.fields[4].offset, methodDefTable.fields[4].size);
|
||||
dm.mdParamList = peImage.offsetRead(offset + (uint)methodDefTable.fields[5].offset, methodDefTable.fields[5].size);
|
||||
|
||||
dm.code = getDecryptedCode(methodInfo);
|
||||
dm.code = decrypter.decrypt(methodInfo);
|
||||
|
||||
if ((peImage.readByte(rva) & 3) == 2) {
|
||||
dm.mhFlags = 2;
|
||||
|
@ -112,44 +217,25 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
return true;
|
||||
}
|
||||
|
||||
byte[] getDecryptedCode(MethodInfo methodInfo) {
|
||||
byte[] data = peImage.offsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
|
||||
for (int i = 0; i < data.Length; i++) {
|
||||
byte b = data[i];
|
||||
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x30 + i) % 16];
|
||||
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x30 + i + 7) % 16];
|
||||
data[i] = b;
|
||||
}
|
||||
|
||||
int codeOffset, codeSize;
|
||||
if ((data[0] & 3) == 2) {
|
||||
codeOffset = 1;
|
||||
codeSize = data[0] >> 2;
|
||||
}
|
||||
else {
|
||||
codeOffset = 4 * (data[1] >> 4);
|
||||
codeSize = BitConverter.ToInt32(data, 4);
|
||||
}
|
||||
|
||||
var code = new byte[codeSize];
|
||||
Array.Copy(data, codeOffset, code, 0, codeSize);
|
||||
return code;
|
||||
}
|
||||
|
||||
bool readCodeHeader(uint offset) {
|
||||
codeHeader.signature = peImage.offsetReadBytes(offset, 16);
|
||||
if (!Utils.compare(SIGNATURE, codeHeader.signature))
|
||||
return false;
|
||||
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);
|
||||
|
||||
if (Utils.compare(codeHeader.signature, normalSignature))
|
||||
decrypter = new NormalDecrypter(peImage, codeHeader);
|
||||
else if (Utils.compare(codeHeader.signature, proSignature))
|
||||
decrypter = new ProDecrypter(peImage, codeHeader);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (codeHeader.totalCodeSize > 0x10000000)
|
||||
throw new ApplicationException("Invalid total code size");
|
||||
return false;
|
||||
if (codeHeader.numMethods > 512*1024)
|
||||
throw new ApplicationException("Invalid num methods");
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user