diff --git a/Editor/ObfusPasses/CallObfus/CallObfusPass.cs b/Editor/ObfusPasses/CallObfus/CallObfusPass.cs index 62f48b1..5527337 100644 --- a/Editor/ObfusPasses/CallObfus/CallObfusPass.cs +++ b/Editor/ObfusPasses/CallObfus/CallObfusPass.cs @@ -12,12 +12,14 @@ namespace Obfuz.ObfusPasses.CallObfus private readonly CallObfuscationSettingsFacade _settings; private IObfuscator _dynamicProxyObfuscator; private IObfuscationPolicy _dynamicProxyPolicy; + private readonly CachedDictionary _specialwhiteListMethodCache; public override ObfuscationPassType Type => ObfuscationPassType.CallObfus; public CallObfusPass(CallObfuscationSettingsFacade settings) { _settings = settings; + _specialwhiteListMethodCache = new CachedDictionary(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList); } public override void Stop() @@ -37,6 +39,129 @@ namespace Obfuz.ObfusPasses.CallObfus return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method); } + + private static readonly HashSet _specialTypeFullNames = new HashSet + { + "System.Enum", + "System.Delegate", + "System.MulticastDelegate", + "Obfuz.EncryptionService`1", + }; + + private static readonly HashSet _specialMethodNames = new HashSet + { + "GetEnumerator", // List.Enumerator.GetEnumerator() + ".ctor", // constructor + }; + + private static readonly HashSet _specialMethodFullNames = new HashSet + { + "System.Reflection.MethodBase.GetCurrentMethod", + "System.Reflection.Assembly.GetCallingAssembly", + "System.Reflection.Assembly.GetExecutingAssembly", + "System.Reflection.Assembly.GetEntryAssembly", + }; + + private bool IsSpecialNotObfuscatedMethod(TypeDef typeDef, IMethod method) + { + if (typeDef.IsDelegate || typeDef.IsEnum) + return true; + + string fullName = typeDef.FullName; + if (_specialTypeFullNames.Contains(fullName)) + { + return true; + } + //if (fullName.StartsWith("System.Runtime.CompilerServices.")) + //{ + // return true; + //} + + string methodName = method.Name; + if (_specialMethodNames.Contains(methodName)) + { + return true; + } + + string methodFullName = $"{fullName}.{methodName}"; + if (_specialMethodFullNames.Contains(methodFullName)) + { + return true; + } + return false; + } + + private bool ComputeIsInWhiteList(IMethod calledMethod) + { + // mono has more strict access control, calls non-public method will raise exception. + if (PlatformUtil.IsMonoBackend()) + { + MethodDef calledMethodDef = calledMethod.ResolveMethodDef(); + if (calledMethodDef != null && (!calledMethodDef.IsPublic || !IsTypeSelfAndParentPublic(calledMethodDef.DeclaringType))) + { + return true; + } + } + + ITypeDefOrRef declaringType = calledMethod.DeclaringType; + TypeSig declaringTypeSig = calledMethod.DeclaringType.ToTypeSig(); + declaringTypeSig = declaringTypeSig.RemovePinnedAndModifiers(); + switch (declaringTypeSig.ElementType) + { + case ElementType.ValueType: + case ElementType.Class: + { + break; + } + case ElementType.GenericInst: + { + if (MetaUtil.ContainsContainsGenericParameter(calledMethod)) + { + return true; + } + break; + } + default: return true; + } + + TypeDef typeDef = declaringType.ResolveTypeDef(); + if (typeDef.IsDelegate || typeDef.IsEnum) + return true; + + string fullName = typeDef.FullName; + if (_specialTypeFullNames.Contains(fullName)) + { + return true; + } + //if (fullName.StartsWith("System.Runtime.CompilerServices.")) + //{ + // return true; + //} + + string methodName = calledMethod.Name; + if (_specialMethodNames.Contains(methodName)) + { + return true; + } + + string methodFullName = $"{fullName}.{methodName}"; + if (_specialMethodFullNames.Contains(methodFullName)) + { + return true; + } + return false; + } + + private bool IsTypeSelfAndParentPublic(TypeDef type) + { + if (type.DeclaringType != null && !IsTypeSelfAndParentPublic(type.DeclaringType)) + { + return false; + } + + return type.IsPublic; + } + protected override bool TryObfuscateInstruction(MethodDef callerMethod, Instruction inst, BasicBlock block, int instructionIndex, IList globalInstructions, List outputInstructions, List totalFinalInstructions) { @@ -70,6 +195,13 @@ namespace Obfuz.ObfusPasses.CallObfus default: return false; } + + if (_specialwhiteListMethodCache.GetValue(calledMethod)) + { + return false; + } + + if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir, block.inLoop)) { return false; diff --git a/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs b/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs index 5debfa3..2c27e77 100644 --- a/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs +++ b/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs @@ -86,11 +86,12 @@ namespace Obfuz.ObfusPasses.CallObfus private ObfuscationRule _global; private readonly List _whiteListAssemblies = new List(); - private readonly Dictionary _whiteListMethodCache = new Dictionary(MethodEqualityComparer.CompareDeclaringTypes); + private readonly CachedDictionary _whiteListMethodCache; private readonly Dictionary _methodRuleCache = new Dictionary(); public ConfigurableObfuscationPolicy(List toObfuscatedAssemblyNames, List xmlConfigFiles) { + _whiteListMethodCache = new CachedDictionary(MethodEqualityComparer.CompareDeclaringTypes, this.ComputeIsInWhiteList); _configParser = new XmlAssemblyTypeMethodRuleParser(toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobalElement); LoadConfigs(xmlConfigFiles); @@ -274,54 +275,6 @@ namespace Obfuz.ObfusPasses.CallObfus }; } - - private readonly HashSet _specialTypeFullNames = new HashSet - { - "System.Enum", - "System.Delegate", - "System.MulticastDelegate", - "Obfuz.EncryptionService`1", - }; - - private readonly HashSet _specialMethodNames = new HashSet - { - "GetEnumerator", // List.Enumerator.GetEnumerator() - ".ctor", // constructor - }; - - private readonly HashSet _specialMethodFullNames = new HashSet - { - "System.Reflection.MethodBase.GetCurrentMethod", - "System.Reflection.Assembly.GetCallingAssembly", - "System.Reflection.Assembly.GetExecutingAssembly", - "System.Reflection.Assembly.GetEntryAssembly", - }; - - private bool IsSpecialNotObfuscatedMethod(TypeDef typeDef, IMethod method) - { - if (typeDef.IsDelegate || typeDef.IsEnum) - return true; - - string fullName = typeDef.FullName; - if (_specialTypeFullNames.Contains(fullName)) - { - return true; - } - - string methodName = method.Name; - if (_specialMethodNames.Contains(methodName)) - { - return true; - } - - string methodFullName = $"{fullName}.{methodName}"; - if (_specialMethodFullNames.Contains(methodFullName)) - { - return true; - } - return false; - } - private bool ComputeIsInWhiteList(IMethod calledMethod) { ITypeDefOrRef declaringType = calledMethod.DeclaringType; @@ -347,11 +300,6 @@ namespace Obfuz.ObfusPasses.CallObfus TypeDef typeDef = declaringType.ResolveTypeDef(); - if (IsSpecialNotObfuscatedMethod(typeDef, calledMethod)) - { - return true; - } - string assName = typeDef.Module.Assembly.Name; string typeFullName = typeDef.FullName; string methodName = calledMethod.Name; @@ -381,42 +329,13 @@ namespace Obfuz.ObfusPasses.CallObfus return false; } - private bool IsInWhiteList(IMethod method) - { - if (!_whiteListMethodCache.TryGetValue(method, out var isWhiteList)) - { - isWhiteList = ComputeIsInWhiteList(method); - _whiteListMethodCache.Add(method, isWhiteList); - } - return isWhiteList; - } - - private bool IsTypeSelfAndParentPublic(TypeDef type) - { - if (type.DeclaringType != null && !IsTypeSelfAndParentPublic(type.DeclaringType)) - { - return false; - } - - return type.IsPublic; - } - public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop) { - if (IsInWhiteList(calledMethod)) + if (_whiteListMethodCache.GetValue(calledMethod)) { return false; } - // mono has more strict access control, calls non-public method will raise exception. - if (PlatformUtil.IsMonoBackend()) - { - MethodDef calledMethodDef = calledMethod.ResolveMethodDef(); - if (calledMethodDef != null && (!calledMethodDef.IsPublic || !IsTypeSelfAndParentPublic(calledMethodDef.DeclaringType))) - { - return false; - } - } ObfuscationRule rule = GetMethodObfuscationRule(callerMethod); if (currentInLoop && rule.obfuscateCallInLoop == false) { diff --git a/Editor/Utils/CachedDictionary.cs b/Editor/Utils/CachedDictionary.cs index 04b2c22..1e0f1d0 100644 --- a/Editor/Utils/CachedDictionary.cs +++ b/Editor/Utils/CachedDictionary.cs @@ -6,10 +6,17 @@ namespace Obfuz.Utils public class CachedDictionary { private readonly Func _valueFactory; - private readonly Dictionary _cache = new Dictionary(); + private readonly Dictionary _cache; public CachedDictionary(Func valueFactory) { + _cache = new Dictionary(); + _valueFactory = valueFactory; + } + + public CachedDictionary(IEqualityComparer equalityComparer, Func valueFactory) + { + _cache = new Dictionary(equalityComparer); _valueFactory = valueFactory; }