Support SA 1.x-3.x
This commit is contained in:
parent
222132f43b
commit
a38781c1d0
|
@ -17,6 +17,7 @@
|
||||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
using Mono.Cecil.Cil;
|
using Mono.Cecil.Cil;
|
||||||
|
@ -27,6 +28,15 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
ModuleDefinition module;
|
ModuleDefinition module;
|
||||||
ExceptionLoggerRemover exceptionLoggerRemover = new ExceptionLoggerRemover();
|
ExceptionLoggerRemover exceptionLoggerRemover = new ExceptionLoggerRemover();
|
||||||
TypeDefinition automatedErrorReportingType;
|
TypeDefinition automatedErrorReportingType;
|
||||||
|
int constantArgs;
|
||||||
|
AerVersion aerVersion;
|
||||||
|
|
||||||
|
enum AerVersion {
|
||||||
|
V0,
|
||||||
|
V1,
|
||||||
|
V2,
|
||||||
|
V3,
|
||||||
|
}
|
||||||
|
|
||||||
public ExceptionLoggerRemover ExceptionLoggerRemover {
|
public ExceptionLoggerRemover ExceptionLoggerRemover {
|
||||||
get { return exceptionLoggerRemover; }
|
get { return exceptionLoggerRemover; }
|
||||||
|
@ -57,6 +67,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
|
|
||||||
const int MIN_HELPER_METHODS = 6;
|
const int MIN_HELPER_METHODS = 6;
|
||||||
|
|
||||||
|
constantArgs = 0;
|
||||||
var methods = new List<MethodDefinition>();
|
var methods = new List<MethodDefinition>();
|
||||||
MethodDefinition mainMethod = null;
|
MethodDefinition mainMethod = null;
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
|
@ -64,30 +75,118 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
methods.Add(method);
|
methods.Add(method);
|
||||||
else if (isAutomatedErrorReportingMethod(method))
|
else if (isAutomatedErrorReportingMethod(method))
|
||||||
mainMethod = method;
|
mainMethod = method;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
initializeConstantArgs(method);
|
||||||
}
|
}
|
||||||
if (mainMethod == null || methods.Count < MIN_HELPER_METHODS)
|
if (mainMethod == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (isV0(type)) {
|
||||||
|
foreach (var method in type.Methods) {
|
||||||
|
if (method.IsStatic)
|
||||||
|
exceptionLoggerRemover.add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (methods.Count < MIN_HELPER_METHODS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isV1(mainMethod))
|
||||||
|
aerVersion = AerVersion.V1;
|
||||||
|
else if (isV2(mainMethod))
|
||||||
|
aerVersion = AerVersion.V2;
|
||||||
|
else
|
||||||
|
aerVersion = AerVersion.V3;
|
||||||
|
|
||||||
methods.Sort((a, b) => Utils.compareInt32(a.Parameters.Count, b.Parameters.Count));
|
methods.Sort((a, b) => Utils.compareInt32(a.Parameters.Count, b.Parameters.Count));
|
||||||
for (int i = 0; i < methods.Count; i++) {
|
for (int i = 0; i < methods.Count; i++) {
|
||||||
var method = methods[i];
|
var method = methods[i];
|
||||||
if (method.Parameters.Count != i + 1)
|
if (method.Parameters.Count != i + constantArgs)
|
||||||
return false;
|
return false;
|
||||||
var methodCalls = DotNetUtils.getMethodCallCounts(method);
|
var methodCalls = DotNetUtils.getMethodCallCounts(method);
|
||||||
if (methodCalls.count(mainMethod.FullName) != 1)
|
if (methodCalls.count(mainMethod.FullName) != 1)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exceptionLoggerRemover.add(mainMethod);
|
exceptionLoggerRemover.add(mainMethod);
|
||||||
foreach (var method in methods)
|
foreach (var method in methods)
|
||||||
exceptionLoggerRemover.add(method);
|
exceptionLoggerRemover.add(method);
|
||||||
automatedErrorReportingType = type;
|
automatedErrorReportingType = type;
|
||||||
|
|
||||||
|
if (aerVersion == AerVersion.V1) {
|
||||||
|
foreach (var method in type.Methods) {
|
||||||
|
if (DotNetUtils.isMethod(method, "System.Exception", "(System.Int32,System.Object[])"))
|
||||||
|
exceptionLoggerRemover.add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initUnhandledExceptionFilterMethods();
|
initUnhandledExceptionFilterMethods();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initializeConstantArgs(MethodDefinition method) {
|
||||||
|
if (constantArgs > 0)
|
||||||
|
return;
|
||||||
|
constantArgs = getConstantArgs(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getConstantArgs(MethodDefinition method) {
|
||||||
|
if (method.Parameters.Count >= 2) {
|
||||||
|
if (isV1(method) || isV2(method))
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string[] v0Fields = new string[] {
|
||||||
|
"System.Int32",
|
||||||
|
"System.Object[]",
|
||||||
|
};
|
||||||
|
static bool isV0(TypeDefinition type) {
|
||||||
|
if (!new FieldTypes(type).exactly(v0Fields))
|
||||||
|
return false;
|
||||||
|
if (type.Methods.Count != 3)
|
||||||
|
return false;
|
||||||
|
if (type.HasEvents || type.HasProperties)
|
||||||
|
return false;
|
||||||
|
MethodDefinition ctor = null, meth1 = null, meth2 = null;
|
||||||
|
foreach (var method in type.Methods) {
|
||||||
|
if (method.Name == ".ctor") {
|
||||||
|
ctor = method;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!method.IsStatic)
|
||||||
|
return false;
|
||||||
|
if (DotNetUtils.isMethod(method, "System.Exception", "(System.Int32,System.Object[])"))
|
||||||
|
meth1 = method;
|
||||||
|
else if (DotNetUtils.isMethod(method, "System.Exception", "(System.Int32,System.Exception,System.Object[])"))
|
||||||
|
meth2 = method;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctor != null && meth1 != null && meth2 != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isV1(MethodDefinition method) {
|
||||||
|
if (method.Parameters.Count < 2)
|
||||||
|
return false;
|
||||||
|
var p0 = method.Parameters[0].ParameterType.FullName;
|
||||||
|
var p1 = method.Parameters[1].ParameterType.FullName;
|
||||||
|
return p0 == "System.Int32" && p1 == "System.Exception";
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isV2(MethodDefinition method) {
|
||||||
|
if (method.Parameters.Count < 2)
|
||||||
|
return false;
|
||||||
|
var p0 = method.Parameters[0].ParameterType.FullName;
|
||||||
|
var p1 = method.Parameters[1].ParameterType.FullName;
|
||||||
|
return p0 == "System.Exception" && p1 == "System.Int32";
|
||||||
|
}
|
||||||
|
|
||||||
bool isAutomatedErrorReportingMethodHelper(MethodDefinition method) {
|
bool isAutomatedErrorReportingMethodHelper(MethodDefinition method) {
|
||||||
if (!method.HasBody || !method.IsStatic || method.Name == ".ctor")
|
if (!method.HasBody || !method.IsStatic || method.Name == ".ctor")
|
||||||
return false;
|
return false;
|
||||||
|
@ -95,9 +194,9 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
return false;
|
return false;
|
||||||
if (method.Parameters.Count == 0)
|
if (method.Parameters.Count == 0)
|
||||||
return false;
|
return false;
|
||||||
if (method.Parameters[0].ParameterType.FullName != "System.Exception")
|
if (!isV1(method) && !isV2(method) && method.Parameters[0].ParameterType.FullName != "System.Exception")
|
||||||
return false;
|
return false;
|
||||||
for (int i = 1; i < method.Parameters.Count; i++) {
|
for (int i = getConstantArgs(method); i < method.Parameters.Count; i++) {
|
||||||
if (method.Parameters[i].ParameterType.FullName != "System.Object")
|
if (method.Parameters[i].ParameterType.FullName != "System.Object")
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +207,11 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
if (!method.HasBody || !method.IsStatic || method.Name == ".ctor")
|
if (!method.HasBody || !method.IsStatic || method.Name == ".ctor")
|
||||||
return false;
|
return false;
|
||||||
return DotNetUtils.isMethod(method, "System.Void", "(System.Exception,System.Object[])") ||
|
return DotNetUtils.isMethod(method, "System.Void", "(System.Exception,System.Object[])") ||
|
||||||
DotNetUtils.isMethod(method, "System.Exception", "(System.Exception,System.Object[])");
|
DotNetUtils.isMethod(method, "System.Exception", "(System.Exception,System.Object[])") ||
|
||||||
|
// 2.x
|
||||||
|
DotNetUtils.isMethod(method, "System.Exception", "(System.Exception,System.Int32,System.Object[])") ||
|
||||||
|
// 1.x
|
||||||
|
DotNetUtils.isMethod(method, "System.Exception", "(System.Int32,System.Exception,System.Object[])");
|
||||||
}
|
}
|
||||||
|
|
||||||
void initUnhandledExceptionFilterMethods() {
|
void initUnhandledExceptionFilterMethods() {
|
||||||
|
@ -141,14 +244,39 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
if (method == null || !method.IsStatic)
|
if (method == null || !method.IsStatic)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (DotNetUtils.hasReturnValue(method))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (aerVersion) {
|
||||||
|
case AerVersion.V0:
|
||||||
|
case AerVersion.V1:
|
||||||
|
if (!DotNetUtils.isMethod(method, "System.Void", "(System.Int32,System.Object[])"))
|
||||||
|
return null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AerVersion.V2:
|
||||||
if (method.Parameters.Count < 2)
|
if (method.Parameters.Count < 2)
|
||||||
return null;
|
return null;
|
||||||
if (DotNetUtils.hasReturnValue(method))
|
if (method.Parameters[0].ParameterType.ToString() != "System.Exception")
|
||||||
|
return null;
|
||||||
|
if (method.Parameters[1].ParameterType.ToString() != "System.Int32")
|
||||||
|
return null;
|
||||||
|
if (method.Parameters[method.Parameters.Count - 1].ParameterType.ToString() != "System.Object[]")
|
||||||
|
return null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AerVersion.V3:
|
||||||
|
if (method.Parameters.Count < 1)
|
||||||
return null;
|
return null;
|
||||||
if (method.Parameters[0].ParameterType.ToString() != "System.Exception")
|
if (method.Parameters[0].ParameterType.ToString() != "System.Exception")
|
||||||
return null;
|
return null;
|
||||||
if (method.Parameters[method.Parameters.Count - 1].ParameterType.ToString() != "System.Object[]")
|
if (method.Parameters[method.Parameters.Count - 1].ParameterType.ToString() != "System.Object[]")
|
||||||
return null;
|
return null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ApplicationException("Invalid AER version");
|
||||||
|
}
|
||||||
|
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,7 +318,9 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
resourceResolverInfo.findTypes();
|
resourceResolverInfo.findTypes();
|
||||||
|
|
||||||
addModuleCctorInitCallToBeRemoved(assemblyResolverInfo.CallResolverMethod);
|
addModuleCctorInitCallToBeRemoved(assemblyResolverInfo.CallResolverMethod);
|
||||||
|
addCallToBeRemoved(module.EntryPoint, assemblyResolverInfo.CallResolverMethod);
|
||||||
addModuleCctorInitCallToBeRemoved(resourceResolverInfo.CallResolverMethod);
|
addModuleCctorInitCallToBeRemoved(resourceResolverInfo.CallResolverMethod);
|
||||||
|
addCallToBeRemoved(module.EntryPoint, resourceResolverInfo.CallResolverMethod);
|
||||||
|
|
||||||
resourceDecrypterInfo.setSimpleZipType(getGlobalSimpleZipType(), DeobfuscatedFile);
|
resourceDecrypterInfo.setSimpleZipType(getGlobalSimpleZipType(), DeobfuscatedFile);
|
||||||
|
|
||||||
|
|
|
@ -53,11 +53,18 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
if (resolverType != null)
|
if (resolverType != null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var cctor = DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor");
|
if (findTypes(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor")))
|
||||||
if (cctor == null)
|
return true;
|
||||||
return false;
|
if (findTypes(module.EntryPoint))
|
||||||
|
return true;
|
||||||
|
|
||||||
foreach (var tuple in DotNetUtils.getCalledMethods(module, cctor)) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findTypes(MethodDefinition initMethod) {
|
||||||
|
if (initMethod == null)
|
||||||
|
return false;
|
||||||
|
foreach (var tuple in DotNetUtils.getCalledMethods(module, initMethod)) {
|
||||||
var method = tuple.Item2;
|
var method = tuple.Item2;
|
||||||
if (method.Name == ".cctor" || method.Name == ".ctor")
|
if (method.Name == ".cctor" || method.Name == ".ctor")
|
||||||
continue;
|
continue;
|
||||||
|
@ -98,16 +105,50 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasLdftn(attachAppMethod)) {
|
||||||
|
simpleDeobfuscator.deobfuscate(attachAppMethod);
|
||||||
|
foreach (var resolverHandler in getResolverHandlers(type, attachAppMethod)) {
|
||||||
|
if (!resolverHandler.HasBody)
|
||||||
|
continue;
|
||||||
|
if (!checkResolverType2(resolverHandler.DeclaringType))
|
||||||
|
continue;
|
||||||
|
deobfuscate(resolverHandler);
|
||||||
|
if (checkHandlerMethod(resolverHandler)) {
|
||||||
|
callResolverMethod = attachAppMethod;
|
||||||
|
callResolverType = type;
|
||||||
|
resolverType = resolverHandler.DeclaringType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasLdftn(MethodDefinition method) {
|
||||||
|
if (method == null || method.Body == null)
|
||||||
|
return false;
|
||||||
|
foreach (var instr in method.Body.Instructions) {
|
||||||
|
if (instr.OpCode.Code == Code.Ldftn)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkResolverType2(TypeDefinition type) {
|
||||||
|
if (type.Properties.Count > 1 || type.Events.Count > 0)
|
||||||
|
return false;
|
||||||
|
if (!checkResolverType(type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool checkResolverType(TypeDefinition type, MethodDefinition initMethod) {
|
bool checkResolverType(TypeDefinition type, MethodDefinition initMethod) {
|
||||||
resolverType = null;
|
resolverType = null;
|
||||||
if (!initMethod.HasBody)
|
if (!initMethod.HasBody)
|
||||||
return false;
|
return false;
|
||||||
if (type.Properties.Count > 1 || type.Events.Count > 0)
|
if (!checkResolverType2(type))
|
||||||
return false;
|
|
||||||
if (!checkResolverType(type))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
deobfuscate(initMethod);
|
deobfuscate(initMethod);
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
class StringDecrypter {
|
class StringDecrypter {
|
||||||
int stringOffset;
|
int stringOffset;
|
||||||
byte[] decryptedData;
|
byte[] decryptedData;
|
||||||
|
StringDecrypterVersion stringDecrypterVersion;
|
||||||
|
|
||||||
public bool CanDecrypt {
|
public bool CanDecrypt {
|
||||||
get { return decryptedData != null; }
|
get { return decryptedData != null; }
|
||||||
|
@ -43,6 +44,8 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
stringOffset = stringDecrypterInfo.StringOffset;
|
stringOffset = stringDecrypterInfo.StringOffset;
|
||||||
decryptedData = stringDecrypterInfo.decrypt();
|
decryptedData = stringDecrypterInfo.decrypt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stringDecrypterVersion = StringDecrypterInfo.DecrypterVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +68,20 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
decryptedData[index++];
|
decryptedData[index++];
|
||||||
}
|
}
|
||||||
|
|
||||||
var decodedData = Convert.FromBase64String(Encoding.UTF8.GetString(decryptedData, index, len));
|
switch (StringDecrypterInfo.DecrypterVersion) {
|
||||||
return Encoding.UTF8.GetString(decodedData, 0, decodedData.Length);
|
case StringDecrypterVersion.V1:
|
||||||
|
// Some weird problem with 1.x decrypted strings. They all have a \x01 char at the end.
|
||||||
|
var buf = Convert.FromBase64String(Encoding.ASCII.GetString(decryptedData, index, len));
|
||||||
|
if (buf.Length % 2 != 0)
|
||||||
|
Array.Resize(ref buf, buf.Length - 1);
|
||||||
|
return Encoding.Unicode.GetString(buf);
|
||||||
|
|
||||||
|
case StringDecrypterVersion.V2:
|
||||||
|
return Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.ASCII.GetString(decryptedData, index, len)));
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(decryptedData, index, len)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,14 @@ using Mono.Cecil.Cil;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.SmartAssembly {
|
namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
|
enum StringDecrypterVersion {
|
||||||
|
V1,
|
||||||
|
V2,
|
||||||
|
V3,
|
||||||
|
V4,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
class StringDecrypterInfo {
|
class StringDecrypterInfo {
|
||||||
ModuleDefinition module;
|
ModuleDefinition module;
|
||||||
ResourceDecrypter resourceDecrypter;
|
ResourceDecrypter resourceDecrypter;
|
||||||
|
@ -32,6 +40,11 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
int stringOffset;
|
int stringOffset;
|
||||||
TypeDefinition simpleZipType;
|
TypeDefinition simpleZipType;
|
||||||
MethodDefinition stringDecrypterMethod;
|
MethodDefinition stringDecrypterMethod;
|
||||||
|
StringDecrypterVersion decrypterVersion;
|
||||||
|
|
||||||
|
public StringDecrypterVersion DecrypterVersion {
|
||||||
|
get { return decrypterVersion; }
|
||||||
|
}
|
||||||
|
|
||||||
public TypeDefinition GetStringDelegate { get; set; }
|
public TypeDefinition GetStringDelegate { get; set; }
|
||||||
public TypeDefinition StringsType { get; set; }
|
public TypeDefinition StringsType { get; set; }
|
||||||
|
@ -70,35 +83,100 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
this.stringsEncodingClass = stringsEncodingClass;
|
this.stringsEncodingClass = stringsEncodingClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool init(IDeobfuscator deob, ISimpleDeobfuscator simpleDeobfuscator) {
|
static string[] fields2x = new string[] {
|
||||||
var cctor = DotNetUtils.getMethod(stringsEncodingClass, ".cctor");
|
"System.IO.Stream",
|
||||||
|
"System.Int32",
|
||||||
|
};
|
||||||
|
static string[] fields3x = new string[] {
|
||||||
|
"System.Byte[]",
|
||||||
|
"System.Int32",
|
||||||
|
};
|
||||||
|
StringDecrypterVersion guessVersion(MethodDefinition cctor) {
|
||||||
if (cctor == null)
|
if (cctor == null)
|
||||||
throw new ApplicationException("Could not find .cctor");
|
return StringDecrypterVersion.V1;
|
||||||
simpleDeobfuscator.deobfuscate(cctor);
|
var fieldTypes = new FieldTypes(stringsEncodingClass);
|
||||||
|
if (fieldTypes.exactly(fields2x))
|
||||||
stringsResource = findStringResource(cctor);
|
return StringDecrypterVersion.V2;
|
||||||
if (stringsResource == null) {
|
if (fieldTypes.exactly(fields3x))
|
||||||
simpleDeobfuscator.decryptStrings(cctor, deob);
|
return StringDecrypterVersion.V3;
|
||||||
stringsResource = findStringResource(cctor);
|
return StringDecrypterVersion.Unknown;
|
||||||
if (stringsResource == null)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var offsetVal = findOffsetValue(cctor);
|
public bool init(IDeobfuscator deob, ISimpleDeobfuscator simpleDeobfuscator) {
|
||||||
if (offsetVal == null)
|
var cctor = DotNetUtils.getMethod(stringsEncodingClass, ".cctor");
|
||||||
throw new ApplicationException("Could not find string offset");
|
if (cctor != null)
|
||||||
stringOffset = offsetVal.Value;
|
simpleDeobfuscator.deobfuscate(cctor);
|
||||||
|
|
||||||
|
decrypterVersion = guessVersion(cctor);
|
||||||
|
|
||||||
if (!findDecrypterMethod())
|
if (!findDecrypterMethod())
|
||||||
throw new ApplicationException("Could not find string decrypter method");
|
throw new ApplicationException("Could not find string decrypter method");
|
||||||
|
|
||||||
simpleZipType = findSimpleZipType(cctor);
|
if (!findStringsResource(deob, simpleDeobfuscator, cctor ?? stringDecrypterMethod))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (decrypterVersion <= StringDecrypterVersion.V3) {
|
||||||
|
MethodDefinition initMethod;
|
||||||
|
if (decrypterVersion == StringDecrypterVersion.V3)
|
||||||
|
initMethod = cctor;
|
||||||
|
else if (decrypterVersion == StringDecrypterVersion.V2)
|
||||||
|
initMethod = stringDecrypterMethod;
|
||||||
|
else
|
||||||
|
initMethod = stringDecrypterMethod;
|
||||||
|
|
||||||
|
stringOffset = 0;
|
||||||
|
if (decrypterVersion != StringDecrypterVersion.V1) {
|
||||||
|
var pkt = module.Assembly.Name.PublicKeyToken;
|
||||||
|
if (pkt != null) {
|
||||||
|
for (int i = 0; i < pkt.Length - 1; i += 2)
|
||||||
|
stringOffset ^= ((int)pkt[i] << 8) + pkt[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DotNetUtils.findLdcI4Constant(initMethod, 0xFFFFFF) &&
|
||||||
|
DotNetUtils.findLdcI4Constant(initMethod, 0xFFFF)) {
|
||||||
|
stringOffset ^= ((stringDecrypterMethod.MetadataToken.ToInt32() & 0xFFFFFF) - 1) % 0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var offsetVal = findOffsetValue(cctor);
|
||||||
|
if (offsetVal == null)
|
||||||
|
throw new ApplicationException("Could not find string offset");
|
||||||
|
stringOffset = offsetVal.Value;
|
||||||
|
decrypterVersion = StringDecrypterVersion.V4;
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleZipType = cctor == null ? null : findSimpleZipType(cctor);
|
||||||
if (simpleZipType != null)
|
if (simpleZipType != null)
|
||||||
resourceDecrypter = new ResourceDecrypter(new ResourceDecrypterInfo(module, simpleZipType, simpleDeobfuscator));
|
resourceDecrypter = new ResourceDecrypter(new ResourceDecrypterInfo(module, simpleZipType, simpleDeobfuscator));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool findStringsResource(IDeobfuscator deob, ISimpleDeobfuscator simpleDeobfuscator, MethodDefinition initMethod) {
|
||||||
|
if (stringsResource != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (decrypterVersion <= StringDecrypterVersion.V3) {
|
||||||
|
stringsResource = DotNetUtils.getResource(module, module.Mvid.ToString("B")) as EmbeddedResource;
|
||||||
|
if (stringsResource != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initMethod != null) {
|
||||||
|
stringsResource = findStringResource(initMethod);
|
||||||
|
if (stringsResource != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
simpleDeobfuscator.decryptStrings(initMethod, deob);
|
||||||
|
stringsResource = findStringResource(initMethod);
|
||||||
|
if (stringsResource != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] decrypt() {
|
public byte[] decrypt() {
|
||||||
if (!CanDecrypt)
|
if (!CanDecrypt)
|
||||||
throw new ApplicationException("Can't decrypt strings");
|
throw new ApplicationException("Can't decrypt strings");
|
||||||
|
@ -107,10 +185,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
|
|
||||||
// Find the embedded resource where all the strings are encrypted
|
// Find the embedded resource where all the strings are encrypted
|
||||||
EmbeddedResource findStringResource(MethodDefinition method) {
|
EmbeddedResource findStringResource(MethodDefinition method) {
|
||||||
foreach (var ldstr in method.Body.Instructions) {
|
foreach (var s in DotNetUtils.getCodeStrings(method)) {
|
||||||
if (ldstr.OpCode.Code != Code.Ldstr)
|
|
||||||
continue;
|
|
||||||
var s = ldstr.Operand as string;
|
|
||||||
if (s == null)
|
if (s == null)
|
||||||
continue;
|
continue;
|
||||||
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
|
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
|
||||||
|
@ -181,6 +256,9 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findDecrypterMethod() {
|
bool findDecrypterMethod() {
|
||||||
|
if (stringDecrypterMethod != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
var methods = new List<MethodDefinition>(DotNetUtils.findMethods(stringsEncodingClass.Methods, "System.String", new string[] { "System.Int32" }));
|
var methods = new List<MethodDefinition>(DotNetUtils.findMethods(stringsEncodingClass.Methods, "System.String", new string[] { "System.Int32" }));
|
||||||
if (methods.Count != 1)
|
if (methods.Count != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -170,12 +170,29 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string[] fields1x = new string[] {
|
||||||
|
"System.IO.Stream",
|
||||||
|
};
|
||||||
|
static string[] fields2x = new string[] {
|
||||||
|
"System.IO.Stream",
|
||||||
|
"System.Int32",
|
||||||
|
};
|
||||||
|
static string[] fields3x = new string[] {
|
||||||
|
"System.Byte[]",
|
||||||
|
"System.Int32",
|
||||||
|
};
|
||||||
bool couldBeStringDecrypterClass(TypeDefinition type) {
|
bool couldBeStringDecrypterClass(TypeDefinition type) {
|
||||||
if (DotNetUtils.findFieldType(type, "System.Collections.Hashtable", true) == null &&
|
var fields = new FieldTypes(type);
|
||||||
DotNetUtils.findFieldType(type, "System.Collections.Generic.Dictionary`2<System.Int32,System.String>", true) == null) {
|
if (fields.exists("System.Collections.Hashtable") ||
|
||||||
|
fields.exists("System.Collections.Generic.Dictionary`2<System.Int32,System.String>") ||
|
||||||
|
fields.exactly(fields2x) ||
|
||||||
|
fields.exactly(fields3x)) {
|
||||||
|
if (DotNetUtils.getMethod(type, ".cctor") == null)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (DotNetUtils.getMethod(type, ".cctor") == null)
|
else if (fields.exactly(fields1x)) {
|
||||||
|
}
|
||||||
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var methods = new List<MethodDefinition>(DotNetUtils.getNormalMethods(type));
|
var methods = new List<MethodDefinition>(DotNetUtils.getNormalMethods(type));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user