From ce9add13cb4baff05cb3ff7f146270e4cd77a56e Mon Sep 17 00:00:00 2001 From: de4dot Date: Thu, 15 Mar 2012 22:36:23 +0100 Subject: [PATCH] Support CO obfuscated SL/CF assemblies --- .../CryptoObfuscator/ResourceDecrypter.cs | 163 ++++++++++++++---- .../CryptoObfuscator/StringDecrypter.cs | 4 +- .../CryptoObfuscator/TamperDetection.cs | 108 ++++++++++-- 3 files changed, 222 insertions(+), 53 deletions(-) diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs b/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs index 926caee9..d692b62b 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs @@ -36,19 +36,45 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { byte desEncryptedFlag; byte deflatedFlag; byte bitwiseNotEncryptedFlag; + DotNetRuntimeType rtType; public ResourceDecrypter(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator) { this.module = module; + rtType = DotNetUtils.getDotNetRuntimeType(module); find(simpleDeobfuscator); } void find(ISimpleDeobfuscator simpleDeobfuscator) { - var requiredTypes = new string[] { - "System.IO.MemoryStream", - "System.Object", - "System.Int32", - }; + switch (rtType) { + case DotNetRuntimeType.Desktop: + if (module.Runtime >= TargetRuntime.Net_2_0) + findDesktopOrCompactFramework(); + else + findDesktopOrCompactFrameworkV1(); + break; + case DotNetRuntimeType.Silverlight: + findSilverlight(); + break; + + case DotNetRuntimeType.CompactFramework: + if (module.Runtime >= TargetRuntime.Net_2_0) { + if (findDesktopOrCompactFramework()) + break; + } + findDesktopOrCompactFrameworkV1(); + break; + } + + initializeDecrypterFlags(simpleDeobfuscator); + } + + static string[] requiredTypes = new string[] { + "System.IO.MemoryStream", + "System.Object", + "System.Int32", + }; + bool findDesktopOrCompactFramework() { resourceDecrypterType = null; foreach (var type in module.Types) { if (type.Fields.Count != 5) @@ -64,10 +90,9 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { continue; resourceDecrypterType = type; - break; + return true; } - - initializeDecrypterFlags(simpleDeobfuscator); + return false; } bool checkCctor(MethodDefinition cctor) { @@ -85,8 +110,65 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { return stsfldCount >= cctor.DeclaringType.Fields.Count; } + static string[] requiredLocals_v1 = new string[] { + "System.Boolean", + "System.Byte", + "System.Byte[]", + "System.Int32", + "System.Security.Cryptography.DESCryptoServiceProvider", + }; + bool findDesktopOrCompactFrameworkV1() { + resourceDecrypterType = null; + foreach (var type in module.Types) { + if (type.Fields.Count != 0) + continue; + + var method = getDecrypterMethod(type); + if (method == null) + continue; + if (!new LocalTypes(method).exactly(requiredLocals_v1)) + continue; + if (!DotNetUtils.callsMethod(method, "System.Int64", "()")) + continue; + if (!DotNetUtils.callsMethod(method, "System.Int32", "(System.Byte[],System.Int32,System.Int32)")) + continue; + if (!DotNetUtils.callsMethod(method, "System.Void", "(System.Array,System.Int32,System.Array,System.Int32,System.Int32)")) + continue; + if (!DotNetUtils.callsMethod(method, "System.Security.Cryptography.ICryptoTransform", "()")) + continue; + if (!DotNetUtils.callsMethod(method, "System.Byte[]", "(System.Byte[],System.Int32,System.Int32)")) + continue; + + resourceDecrypterType = type; + return true; + } + return false; + } + + static string[] requiredLocals_sl = new string[] { + "System.Byte", + "System.Byte[]", + "System.Int32", + }; + void findSilverlight() { + foreach (var type in module.Types) { + if (type.Fields.Count > 0) + continue; + if (type.HasNestedTypes || type.HasGenericParameters) + continue; + var method = getDecrypterMethod(type); + if (method == null) + continue; + if (!new LocalTypes(method).exactly(requiredLocals_sl)) + continue; + + resourceDecrypterType = type; + break; + } + } + void initializeDecrypterFlags(ISimpleDeobfuscator simpleDeobfuscator) { - if (resourceDecrypterType != null && getPublicKeyTokenMethod() != null) { + if (resourceDecrypterType != null) { if (updateFlags(getDecrypterMethod(), simpleDeobfuscator)) return; } @@ -122,10 +204,36 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { constants.Add(flagValue); } - if (constants.Count == 2) { - desEncryptedFlag = (byte)constants[0]; - deflatedFlag = (byte)constants[1]; - return true; + switch (rtType) { + case DotNetRuntimeType.Desktop: + if (module.Runtime >= TargetRuntime.Net_2_0) { + if (constants.Count == 2) { + desEncryptedFlag = (byte)constants[0]; + deflatedFlag = (byte)constants[1]; + return true; + } + } + else { + if (constants.Count == 1) { + desEncryptedFlag = (byte)constants[0]; + return true; + } + } + break; + + case DotNetRuntimeType.Silverlight: + if (constants.Count == 1) { + bitwiseNotEncryptedFlag = (byte)constants[0]; + return true; + } + break; + + case DotNetRuntimeType.CompactFramework: + if (constants.Count == 1) { + desEncryptedFlag = (byte)constants[0]; + return true; + } + break; } return false; @@ -139,39 +247,18 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { return false; } - MethodDefinition getPublicKeyTokenMethod() { - foreach (var method in resourceDecrypterType.Methods) { - if (isPublicKeyTokenMethod(method)) - return method; - } - return null; + MethodDefinition getDecrypterMethod() { + return getDecrypterMethod(resourceDecrypterType); } - MethodDefinition getDecrypterMethod() { - foreach (var method in resourceDecrypterType.Methods) { + static MethodDefinition getDecrypterMethod(TypeDefinition type) { + foreach (var method in type.Methods) { if (DotNetUtils.isMethod(method, "System.Byte[]", "(System.IO.Stream)")) return method; } return null; } - bool isPublicKeyTokenMethod(MethodDefinition method) { - if (!method.IsStatic) - return false; - if (method.Body == null) - return false; - if (method.Body.ExceptionHandlers.Count < 1) - return false; - if (!DotNetUtils.isMethod(method, "System.Byte[]", "(System.Reflection.Assembly)")) - return false; - - foreach (var s in DotNetUtils.getCodeStrings(method)) { - if (s.ToLowerInvariant() == "publickeytoken=") - return true; - } - return false; - } - public byte[] decrypt(Stream resourceStream) { byte flags = (byte)resourceStream.ReadByte(); Stream sourceStream = resourceStream; diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs b/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs index ceb79bff..a2fbfa0f 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/StringDecrypter.cs @@ -81,6 +81,8 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { return defaultName; foreach (var s in DotNetUtils.getCodeStrings(cctor)) { + if (DotNetUtils.getResource(module, s) != null) + return s; try { return Encoding.UTF8.GetString(Convert.FromBase64String(s)); } @@ -107,7 +109,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { continue; if (DotNetUtils.findFieldType(type, "System.Byte[]", true) == null) continue; - if (type.Methods.Count != 3) + if (type.Methods.Count != 2 && type.Methods.Count != 3) continue; if (type.NestedTypes.Count > 0) continue; diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs b/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs index 6a439f01..34879e12 100644 --- a/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs +++ b/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs @@ -25,6 +25,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { ModuleDefinition module; TypeDefinition tamperType; MethodDefinition tamperMethod; + DotNetRuntimeType rtType; public bool Detected { get { return tamperMethod != null; } @@ -40,6 +41,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { public TamperDetection(ModuleDefinition module) { this.module = module; + rtType = DotNetUtils.getDotNetRuntimeType(module); } public void find() { @@ -54,30 +56,108 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator { return false; foreach (var info in DotNetUtils.getCalledMethods(module, methodToCheck)) { - var type = info.Item1; var method = info.Item2; - if (!method.IsStatic || !DotNetUtils.isMethod(method, "System.Void", "()")) - continue; - if (type.Methods.Count < 3 || type.Methods.Count > 6) - continue; - if (DotNetUtils.getPInvokeMethod(type, "mscoree", "StrongNameSignatureVerificationEx") != null) { + bool result = false; + switch (rtType) { + case DotNetRuntimeType.Desktop: + result = findDesktop(method); + break; + case DotNetRuntimeType.Silverlight: + result = findSilverlight(method); + break; + case DotNetRuntimeType.CompactFramework: + result = findCompactFramework(method); + break; } - else if (DotNetUtils.getPInvokeMethod(type, "mscoree", "CLRCreateInstance") != null) { - if (type.NestedTypes.Count != 3) - continue; - if (!type.NestedTypes[0].IsInterface || !type.NestedTypes[1].IsInterface || !type.NestedTypes[2].IsInterface) - continue; - } - else + if (!result) continue; - tamperType = type; + tamperType = method.DeclaringType; tamperMethod = method; return true; } return false; } + + bool findDesktop(MethodDefinition method) { + var type = method.DeclaringType; + + if (!method.IsStatic || !DotNetUtils.isMethod(method, "System.Void", "()")) + return false; + if (type.Methods.Count < 3 || type.Methods.Count > 6) + return false; + if (DotNetUtils.getPInvokeMethod(type, "mscoree", "StrongNameSignatureVerificationEx") != null) { + } + else if (DotNetUtils.getPInvokeMethod(type, "mscoree", "CLRCreateInstance") != null) { + if (type.NestedTypes.Count != 3) + return false; + if (!type.NestedTypes[0].IsInterface || !type.NestedTypes[1].IsInterface || !type.NestedTypes[2].IsInterface) + return false; + } + else + return false; + + return true; + } + + static string[] requiredLocals_sl = new string[] { + "System.Boolean", + "System.Byte[]", + "System.Int32", + "System.Reflection.AssemblyName", + "System.String", + }; + bool findSilverlight(MethodDefinition method) { + if (!new LocalTypes(method).exactly(requiredLocals_sl)) + return false; + if (!DotNetUtils.callsMethod(method, "System.Int32 System.String::get_Length()")) + return false; + if (!DotNetUtils.callsMethod(method, "System.Byte[] System.Convert::FromBase64String(System.String)")) + return false; + if (!DotNetUtils.callsMethod(method, "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()")) + return false; + if (!DotNetUtils.callsMethod(method, "System.String System.Reflection.Assembly::get_FullName()")) + return false; + if (!DotNetUtils.callsMethod(method, "System.Byte[] System.Reflection.AssemblyName::GetPublicKeyToken()")) + return false; + if (DotNetUtils.callsMethod(method, "System.String", "(System.Reflection.Assembly)")) { + } + else if (DotNetUtils.callsMethod(method, "System.String System.Reflection.AssemblyName::get_Name()")) { + } + else + return false; + + return true; + } + + static string[] requiredLocals_cf = new string[] { + "System.Boolean", + "System.Byte[]", + "System.Int32", + "System.String", + }; + bool findCompactFramework(MethodDefinition method) { + if (!new LocalTypes(method).exactly(requiredLocals_cf)) + return false; + if (!DotNetUtils.callsMethod(method, "System.Int32 System.String::get_Length()")) + return false; + if (!DotNetUtils.callsMethod(method, "System.Byte[] System.Convert::FromBase64String(System.String)")) + return false; + if (!DotNetUtils.callsMethod(method, "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()")) + return false; + + if (DotNetUtils.callsMethod(method, "System.Byte[]", "(System.Reflection.Assembly)") && + DotNetUtils.callsMethod(method, "System.String", "(System.Reflection.Assembly)")) { + } + else if (DotNetUtils.callsMethod(method, "System.Reflection.AssemblyName System.Reflection.Assembly::GetName()") && + DotNetUtils.callsMethod(method, "System.Byte[] System.Reflection.AssemblyName::GetPublicKeyToken()")) { + } + else + return false; + + return true; + } } }