Restore CS 3.0 "encrypted" methods

This commit is contained in:
de4dot 2012-04-25 13:32:14 +02:00
parent 4e89d707dc
commit 903db59827
3 changed files with 102 additions and 57 deletions

View File

@ -130,20 +130,18 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
bool findOld() { bool findOld() {
var methodToCheck = DotNetUtils.getModuleTypeCctor(module); foreach (var cctor in DeobUtils.getInitCctors(module, 3)) {
if (methodToCheck == null) foreach (var calledMethod in DotNetUtils.getCalledMethods(module, cctor)) {
return false; var type = calledMethod.DeclaringType;
if (!hasPinvokeMethod(type, "_Initialize"))
continue;
if (!hasPinvokeMethod(type, "_Initialize64"))
continue;
foreach (var calledMethod in DotNetUtils.getCalledMethods(module, methodToCheck)) { initializeMethod = calledMethod;
var type = calledMethod.DeclaringType; cliSecureRtType = type;
if (!hasPinvokeMethod(type, "_Initialize")) return true;
continue; }
if (!hasPinvokeMethod(type, "_Initialize64"))
continue;
initializeMethod = calledMethod;
cliSecureRtType = type;
return true;
} }
return false; return false;

View File

@ -267,6 +267,8 @@ namespace de4dot.code.deobfuscators.CliSecure {
addModuleReferences("Obfuscator protection files"); addModuleReferences("Obfuscator protection files");
} }
module.Attributes |= ModuleAttributes.ILOnly;
base.deobfuscateEnd(); base.deobfuscateEnd();
} }

View File

@ -85,6 +85,19 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
} }
// CS 3.0 (could be other versions too)
class Decrypter30 : DecrypterBase {
public Decrypter30(PeImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) {
}
public override MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
peImage.Reader.BaseStream.Position = peImage.rvaToOffset(methodInfo.codeOffs);
return MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
}
}
// CS 4.0 (could be other versions too)
class Decrypter40 : DecrypterBase { class Decrypter40 : DecrypterBase {
public Decrypter40(PeImage peImage, CodeHeader codeHeader) public Decrypter40(PeImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) { : base(peImage, codeHeader) {
@ -96,7 +109,7 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
} }
// CS 4.5 // CS 4.5 (could be other versions too)
class Decrypter45 : DecrypterBase { class Decrypter45 : DecrypterBase {
public Decrypter45(PeImage peImage, CodeHeader codeHeader) public Decrypter45(PeImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) { : base(peImage, codeHeader) {
@ -240,7 +253,22 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
} }
// CS 4.0 // CS 3.0 (could be other versions too)
class CsHeader30 : CsHeaderBase {
public CsHeader30(MethodsDecrypter methodsDecrypter)
: base(methodsDecrypter, 0x28) {
}
public override IDecrypter createDecrypter() {
return new Decrypter30(methodsDecrypter.peImage, methodsDecrypter.codeHeader);
}
public override List<MethodInfo> getMethodInfos(uint codeHeaderOffset) {
return getMethodInfos1(codeHeaderOffset);
}
}
// CS 4.0 (could be other versions too)
class CsHeader40 : CsHeaderBase { class CsHeader40 : CsHeaderBase {
public CsHeader40(MethodsDecrypter methodsDecrypter) public CsHeader40(MethodsDecrypter methodsDecrypter)
: base(methodsDecrypter, 0x28) { : base(methodsDecrypter, 0x28) {
@ -255,7 +283,7 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
} }
// CS 4.5 // CS 4.5 (could be other versions too)
class CsHeader45 : CsHeaderBase { class CsHeader45 : CsHeaderBase {
public CsHeader45(MethodsDecrypter methodsDecrypter) public CsHeader45(MethodsDecrypter methodsDecrypter)
: base(methodsDecrypter, 0x28) { : base(methodsDecrypter, 0x28) {
@ -309,51 +337,30 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
} }
public bool decrypt(PeImage peImage, string filename, CliSecureRtType csRtType, ref DumpedMethods dumpedMethods) {
this.peImage = peImage;
this.csRtType = csRtType;
try {
return decrypt2(ref dumpedMethods);
}
catch (InvalidMethodBody) {
Log.w("Using dynamic method decryption");
byte[] moduleCctorBytes = getModuleCctorBytes(csRtType);
dumpedMethods = de4dot.code.deobfuscators.MethodsDecrypter.decrypt(filename, moduleCctorBytes);
return true;
}
}
static byte[] getModuleCctorBytes(CliSecureRtType csRtType) {
var initMethod = csRtType.InitializeMethod;
if (initMethod == null)
return null;
uint initToken = initMethod.MetadataToken.ToUInt32();
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;
}
enum CsHeaderVersion { enum CsHeaderVersion {
Unknown, Unknown,
V30,
V40, V40,
V45, V45,
V50, // 5.0, possibly also 5.1 V50, // 5.0, possibly also 5.1
V52, // 5.2+ (or maybe 5.1+) V52, // 5.2+ (or maybe 5.1+)
} }
CsHeaderVersion getCsHeaderVersion(uint codeHeaderOffset, MetadataType methodDefTable) { List<CsHeaderVersion> getCsHeaderVersions(uint codeHeaderOffset, MetadataType methodDefTable) {
if (!isOldHeader(methodDefTable)) if (!isOldHeader(methodDefTable))
return CsHeaderVersion.V52; return new List<CsHeaderVersion> { CsHeaderVersion.V52 };
if (csRtType.isAtLeastVersion50()) if (csRtType.isAtLeastVersion50())
return CsHeaderVersion.V50; return new List<CsHeaderVersion> { CsHeaderVersion.V50 };
if (isCsHeader40(codeHeaderOffset)) if (isCsHeader40(codeHeaderOffset)) {
return CsHeaderVersion.V40; return new List<CsHeaderVersion> {
return CsHeaderVersion.V45; CsHeaderVersion.V40,
CsHeaderVersion.V30,
};
}
return new List<CsHeaderVersion> {
CsHeaderVersion.V45,
CsHeaderVersion.V50,
};
} }
bool isCsHeader40(uint codeHeaderOffset) { bool isCsHeader40(uint codeHeaderOffset) {
@ -384,8 +391,9 @@ namespace de4dot.code.deobfuscators.CliSecure {
return false; return false;
} }
ICsHeader createCsHeader(uint codeHeaderOffset, MetadataType methodDefTable) { ICsHeader createCsHeader(CsHeaderVersion version) {
switch (getCsHeaderVersion(codeHeaderOffset, methodDefTable)) { switch (version) {
case CsHeaderVersion.V30: return new CsHeader30(this);
case CsHeaderVersion.V40: return new CsHeader40(this); case CsHeaderVersion.V40: return new CsHeader40(this);
case CsHeaderVersion.V45: return new CsHeader45(this); case CsHeaderVersion.V45: return new CsHeader45(this);
case CsHeaderVersion.V50: return new CsHeader5(this, 0x28); case CsHeaderVersion.V50: return new CsHeader5(this, 0x28);
@ -394,11 +402,38 @@ namespace de4dot.code.deobfuscators.CliSecure {
} }
} }
public bool decrypt(PeImage peImage, string filename, CliSecureRtType csRtType, ref DumpedMethods dumpedMethods) {
this.peImage = peImage;
this.csRtType = csRtType;
if (decrypt2(ref dumpedMethods))
return true;
Log.w("Using dynamic method decryption");
byte[] moduleCctorBytes = getModuleCctorBytes(csRtType);
dumpedMethods = de4dot.code.deobfuscators.MethodsDecrypter.decrypt(filename, moduleCctorBytes);
return true;
}
static byte[] getModuleCctorBytes(CliSecureRtType csRtType) {
var initMethod = csRtType.InitializeMethod;
if (initMethod == null)
return null;
uint initToken = initMethod.MetadataToken.ToUInt32();
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;
}
static uint getCodeHeaderOffset(PeImage peImage) { static uint getCodeHeaderOffset(PeImage peImage) {
return peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size); return peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
} }
public bool decrypt2(ref DumpedMethods dumpedMethods) { bool decrypt2(ref DumpedMethods dumpedMethods) {
uint codeHeaderOffset = getCodeHeaderOffset(peImage); uint codeHeaderOffset = getCodeHeaderOffset(peImage);
if (!readCodeHeader(codeHeaderOffset)) if (!readCodeHeader(codeHeaderOffset))
return false; return false;
@ -406,7 +441,19 @@ namespace de4dot.code.deobfuscators.CliSecure {
var metadataTables = peImage.Cor20Header.createMetadataTables(); var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDefTable = metadataTables.getMetadataType(MetadataIndex.iMethodDef); var methodDefTable = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
var csHeader = createCsHeader(codeHeaderOffset, methodDefTable); foreach (var version in getCsHeaderVersions(codeHeaderOffset, methodDefTable)) {
try {
decryptMethods(codeHeaderOffset, methodDefTable, createCsHeader(version), ref dumpedMethods);
return true;
}
catch {
}
}
return false;
}
void decryptMethods(uint codeHeaderOffset, MetadataType methodDefTable, ICsHeader csHeader, ref DumpedMethods dumpedMethods) {
var methodInfos = csHeader.getMethodInfos(codeHeaderOffset); var methodInfos = csHeader.getMethodInfos(codeHeaderOffset);
csHeader.patchMethodDefTable(methodDefTable, methodInfos); csHeader.patchMethodDefTable(methodDefTable, methodInfos);
@ -435,8 +482,6 @@ namespace de4dot.code.deobfuscators.CliSecure {
dumpedMethods.add(dm); dumpedMethods.add(dm);
} }
return true;
} }
bool readCodeHeader(uint offset) { bool readCodeHeader(uint offset) {