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/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
|
@ -27,6 +28,15 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
ModuleDefinition module;
|
||||
ExceptionLoggerRemover exceptionLoggerRemover = new ExceptionLoggerRemover();
|
||||
TypeDefinition automatedErrorReportingType;
|
||||
int constantArgs;
|
||||
AerVersion aerVersion;
|
||||
|
||||
enum AerVersion {
|
||||
V0,
|
||||
V1,
|
||||
V2,
|
||||
V3,
|
||||
}
|
||||
|
||||
public ExceptionLoggerRemover ExceptionLoggerRemover {
|
||||
get { return exceptionLoggerRemover; }
|
||||
|
@ -57,6 +67,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
|
||||
const int MIN_HELPER_METHODS = 6;
|
||||
|
||||
constantArgs = 0;
|
||||
var methods = new List<MethodDefinition>();
|
||||
MethodDefinition mainMethod = null;
|
||||
foreach (var method in type.Methods) {
|
||||
|
@ -64,30 +75,118 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
methods.Add(method);
|
||||
else if (isAutomatedErrorReportingMethod(method))
|
||||
mainMethod = method;
|
||||
else
|
||||
continue;
|
||||
initializeConstantArgs(method);
|
||||
}
|
||||
if (mainMethod == null || methods.Count < MIN_HELPER_METHODS)
|
||||
if (mainMethod == null)
|
||||
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));
|
||||
for (int i = 0; i < methods.Count; i++) {
|
||||
var method = methods[i];
|
||||
if (method.Parameters.Count != i + 1)
|
||||
if (method.Parameters.Count != i + constantArgs)
|
||||
return false;
|
||||
var methodCalls = DotNetUtils.getMethodCallCounts(method);
|
||||
if (methodCalls.count(mainMethod.FullName) != 1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
exceptionLoggerRemover.add(mainMethod);
|
||||
foreach (var method in methods)
|
||||
exceptionLoggerRemover.add(method);
|
||||
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();
|
||||
|
||||
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) {
|
||||
if (!method.HasBody || !method.IsStatic || method.Name == ".ctor")
|
||||
return false;
|
||||
|
@ -95,9 +194,9 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
return false;
|
||||
if (method.Parameters.Count == 0)
|
||||
return false;
|
||||
if (method.Parameters[0].ParameterType.FullName != "System.Exception")
|
||||
if (!isV1(method) && !isV2(method) && method.Parameters[0].ParameterType.FullName != "System.Exception")
|
||||
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")
|
||||
return false;
|
||||
}
|
||||
|
@ -108,7 +207,11 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
if (!method.HasBody || !method.IsStatic || method.Name == ".ctor")
|
||||
return false;
|
||||
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() {
|
||||
|
@ -141,14 +244,39 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
if (method == null || !method.IsStatic)
|
||||
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)
|
||||
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;
|
||||
if (method.Parameters[0].ParameterType.ToString() != "System.Exception")
|
||||
return null;
|
||||
if (method.Parameters[method.Parameters.Count - 1].ParameterType.ToString() != "System.Object[]")
|
||||
return null;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ApplicationException("Invalid AER version");
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
|
|
@ -318,7 +318,9 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
resourceResolverInfo.findTypes();
|
||||
|
||||
addModuleCctorInitCallToBeRemoved(assemblyResolverInfo.CallResolverMethod);
|
||||
addCallToBeRemoved(module.EntryPoint, assemblyResolverInfo.CallResolverMethod);
|
||||
addModuleCctorInitCallToBeRemoved(resourceResolverInfo.CallResolverMethod);
|
||||
addCallToBeRemoved(module.EntryPoint, resourceResolverInfo.CallResolverMethod);
|
||||
|
||||
resourceDecrypterInfo.setSimpleZipType(getGlobalSimpleZipType(), DeobfuscatedFile);
|
||||
|
||||
|
|
|
@ -53,11 +53,18 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
if (resolverType != null)
|
||||
return true;
|
||||
|
||||
var cctor = DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor");
|
||||
if (cctor == null)
|
||||
return false;
|
||||
if (findTypes(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor")))
|
||||
return true;
|
||||
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;
|
||||
if (method.Name == ".cctor" || method.Name == ".ctor")
|
||||
continue;
|
||||
|
@ -98,16 +105,50 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
resolverType = null;
|
||||
if (!initMethod.HasBody)
|
||||
return false;
|
||||
if (type.Properties.Count > 1 || type.Events.Count > 0)
|
||||
return false;
|
||||
if (!checkResolverType(type))
|
||||
if (!checkResolverType2(type))
|
||||
return false;
|
||||
|
||||
deobfuscate(initMethod);
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
class StringDecrypter {
|
||||
int stringOffset;
|
||||
byte[] decryptedData;
|
||||
StringDecrypterVersion stringDecrypterVersion;
|
||||
|
||||
public bool CanDecrypt {
|
||||
get { return decryptedData != null; }
|
||||
|
@ -43,6 +44,8 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
stringOffset = stringDecrypterInfo.StringOffset;
|
||||
decryptedData = stringDecrypterInfo.decrypt();
|
||||
}
|
||||
|
||||
stringDecrypterVersion = StringDecrypterInfo.DecrypterVersion;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +68,20 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
decryptedData[index++];
|
||||
}
|
||||
|
||||
var decodedData = Convert.FromBase64String(Encoding.UTF8.GetString(decryptedData, index, len));
|
||||
return Encoding.UTF8.GetString(decodedData, 0, decodedData.Length);
|
||||
switch (StringDecrypterInfo.DecrypterVersion) {
|
||||
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;
|
||||
|
||||
namespace de4dot.code.deobfuscators.SmartAssembly {
|
||||
enum StringDecrypterVersion {
|
||||
V1,
|
||||
V2,
|
||||
V3,
|
||||
V4,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
class StringDecrypterInfo {
|
||||
ModuleDefinition module;
|
||||
ResourceDecrypter resourceDecrypter;
|
||||
|
@ -32,6 +40,11 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
int stringOffset;
|
||||
TypeDefinition simpleZipType;
|
||||
MethodDefinition stringDecrypterMethod;
|
||||
StringDecrypterVersion decrypterVersion;
|
||||
|
||||
public StringDecrypterVersion DecrypterVersion {
|
||||
get { return decrypterVersion; }
|
||||
}
|
||||
|
||||
public TypeDefinition GetStringDelegate { get; set; }
|
||||
public TypeDefinition StringsType { get; set; }
|
||||
|
@ -70,35 +83,100 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
this.stringsEncodingClass = stringsEncodingClass;
|
||||
}
|
||||
|
||||
public bool init(IDeobfuscator deob, ISimpleDeobfuscator simpleDeobfuscator) {
|
||||
var cctor = DotNetUtils.getMethod(stringsEncodingClass, ".cctor");
|
||||
static string[] fields2x = new string[] {
|
||||
"System.IO.Stream",
|
||||
"System.Int32",
|
||||
};
|
||||
static string[] fields3x = new string[] {
|
||||
"System.Byte[]",
|
||||
"System.Int32",
|
||||
};
|
||||
StringDecrypterVersion guessVersion(MethodDefinition cctor) {
|
||||
if (cctor == null)
|
||||
throw new ApplicationException("Could not find .cctor");
|
||||
simpleDeobfuscator.deobfuscate(cctor);
|
||||
|
||||
stringsResource = findStringResource(cctor);
|
||||
if (stringsResource == null) {
|
||||
simpleDeobfuscator.decryptStrings(cctor, deob);
|
||||
stringsResource = findStringResource(cctor);
|
||||
if (stringsResource == null)
|
||||
return false;
|
||||
return StringDecrypterVersion.V1;
|
||||
var fieldTypes = new FieldTypes(stringsEncodingClass);
|
||||
if (fieldTypes.exactly(fields2x))
|
||||
return StringDecrypterVersion.V2;
|
||||
if (fieldTypes.exactly(fields3x))
|
||||
return StringDecrypterVersion.V3;
|
||||
return StringDecrypterVersion.Unknown;
|
||||
}
|
||||
|
||||
var offsetVal = findOffsetValue(cctor);
|
||||
if (offsetVal == null)
|
||||
throw new ApplicationException("Could not find string offset");
|
||||
stringOffset = offsetVal.Value;
|
||||
public bool init(IDeobfuscator deob, ISimpleDeobfuscator simpleDeobfuscator) {
|
||||
var cctor = DotNetUtils.getMethod(stringsEncodingClass, ".cctor");
|
||||
if (cctor != null)
|
||||
simpleDeobfuscator.deobfuscate(cctor);
|
||||
|
||||
decrypterVersion = guessVersion(cctor);
|
||||
|
||||
if (!findDecrypterMethod())
|
||||
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)
|
||||
resourceDecrypter = new ResourceDecrypter(new ResourceDecrypterInfo(module, simpleZipType, simpleDeobfuscator));
|
||||
|
||||
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() {
|
||||
if (!CanDecrypt)
|
||||
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
|
||||
EmbeddedResource findStringResource(MethodDefinition method) {
|
||||
foreach (var ldstr in method.Body.Instructions) {
|
||||
if (ldstr.OpCode.Code != Code.Ldstr)
|
||||
continue;
|
||||
var s = ldstr.Operand as string;
|
||||
foreach (var s in DotNetUtils.getCodeStrings(method)) {
|
||||
if (s == null)
|
||||
continue;
|
||||
var resource = DotNetUtils.getResource(module, s) as EmbeddedResource;
|
||||
|
@ -181,6 +256,9 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
|
|||
}
|
||||
|
||||
bool findDecrypterMethod() {
|
||||
if (stringDecrypterMethod != null)
|
||||
return true;
|
||||
|
||||
var methods = new List<MethodDefinition>(DotNetUtils.findMethods(stringsEncodingClass.Methods, "System.String", new string[] { "System.Int32" }));
|
||||
if (methods.Count != 1)
|
||||
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) {
|
||||
if (DotNetUtils.findFieldType(type, "System.Collections.Hashtable", true) == null &&
|
||||
DotNetUtils.findFieldType(type, "System.Collections.Generic.Dictionary`2<System.Int32,System.String>", true) == null) {
|
||||
var fields = new FieldTypes(type);
|
||||
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;
|
||||
}
|
||||
if (DotNetUtils.getMethod(type, ".cctor") == null)
|
||||
else if (fields.exactly(fields1x)) {
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
var methods = new List<MethodDefinition>(DotNetUtils.getNormalMethods(type));
|
||||
|
|
Loading…
Reference in New Issue
Block a user