using dnlib.DotNet; using Obfuz.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using UnityEngine; namespace Obfuz.ObfusPasses.SymbolObfus.Policies { public class ConfigurableRenamePolicy : ObfuscationPolicyBase { enum ObfuscationType { Name = 1, Namespace = 2, NestType = 3, Method = 4, Field = 5, Property = 6, Event = 7, Param = 8, MethodBody = 9, Getter = 10, Setter = 11, Add = 12, Remove = 13, Fire = 14, } enum RuleType { Assembly = 1, Type = 2, Method = 3, Field = 4, Property = 5, Event = 6, } enum ModifierType { Private = 0, Protected = 1, Public = 2, } interface IRule { } class MethodRuleSpec { public NameMatcher nameMatcher; public ModifierType modifierType; public MethodRule rule; } class MethodRule : IRule { public string ruleName; public bool obfuscateName; public bool obfuscateParam; public bool obfuscateBody; } class FieldRuleSpec { public NameMatcher nameMatcher; public ModifierType modifierType; public FieldRule rule; } class FieldRule : IRule { public string ruleName; public bool obfuscateName; } class PropertyRuleSpec { public NameMatcher nameMatcher; public PropertyRule rule; } class PropertyRule : IRule { public string ruleName; public bool obfuscateName; public MethodRuleSpec getter; public MethodRuleSpec setter; } class EventRuleSpec { public NameMatcher nameMatcher; public EventRule rule; } class EventRule : IRule { public string ruleName; public bool obfuscateName; public MethodRuleSpec add; public MethodRuleSpec remove; public MethodRuleSpec fire; } class TypeRuleSpec { public NameMatcher nameMatcher; public ModifierType modifierType; public TypeRule rule; } class TypeRule : IRule { public string ruleName; public bool obfuscateName; public bool obfuscateNamespace; //public List nestTypeRuleSpecs; public List fieldRuleSpecs; public List methodRuleSpecs; public List propertyRuleSpecs; public List eventRuleSpecs; } class AssemblyRule : IRule { public string ruleName; public bool obfuscateName; public List typeRuleSpecs; } class AssemblyRuleSpec { public string assemblyName; public AssemblyRule rule; } //class DefaultRule : IRule //{ //} //private readonly static IRule _defaultRule = new DefaultRule(); //private readonly static IRule _noneRule = new DefaultRule(); private readonly Dictionary<(string, RuleType), IRule> _rules = new Dictionary<(string, RuleType), IRule>(); private readonly Dictionary<(string, RuleType), XmlElement> _rawRuleElements = new Dictionary<(string, RuleType), XmlElement>(); private readonly Dictionary _assemblyRuleSpecs = new Dictionary(); private static readonly MethodRule s_noneMethodRule = new MethodRule { ruleName = "none", obfuscateName = false, obfuscateParam = false, obfuscateBody = false, }; private static readonly EventRule s_noneEventRule = new EventRule { ruleName = "none", obfuscateName = false, add = new MethodRuleSpec { rule = s_noneMethodRule}, remove = new MethodRuleSpec { rule = s_noneMethodRule }, fire = new MethodRuleSpec { rule = s_noneMethodRule }, }; private static readonly PropertyRule s_nonePropertyRule = new PropertyRule { ruleName = "none", obfuscateName = false, getter = new MethodRuleSpec { rule = s_noneMethodRule }, setter = new MethodRuleSpec { rule = s_noneMethodRule }, }; private static readonly FieldRule s_noneFieldRule = new FieldRule { ruleName = "none", obfuscateName = false, }; private static readonly TypeRule s_noneTypeRule = new TypeRule { ruleName = "none", obfuscateName = false, obfuscateNamespace = false, //nestTypeRuleSpecs = new List(), fieldRuleSpecs = new List { new FieldRuleSpec { rule = s_noneFieldRule} }, methodRuleSpecs = new List { new MethodRuleSpec { rule = s_noneMethodRule} }, propertyRuleSpecs = new List { new PropertyRuleSpec { rule = s_nonePropertyRule} }, eventRuleSpecs = new List { new EventRuleSpec { rule = s_noneEventRule} }, }; private static readonly AssemblyRule s_noneAssemblyRule = new AssemblyRule { ruleName = "none", obfuscateName = false, typeRuleSpecs = new List { new TypeRuleSpec { rule = s_noneTypeRule } }, }; //static ObfuscateRuleConfig() //{ // s_noneTypeRule.nestTypeRuleSpecs.Add(new TypeRuleSpec // { // rule = s_noneTypeRule, // }); //} private IRule GetOrParseRule(string ruleName, RuleType ruleType, XmlElement ele) { IRule rule = null; XmlElement element; if (!string.IsNullOrEmpty(ruleName)) { if (ruleName == "none") { switch (ruleType) { case RuleType.Assembly: return s_noneAssemblyRule; case RuleType.Type: return s_noneTypeRule; case RuleType.Method: return s_noneMethodRule; case RuleType.Field: return s_noneFieldRule; case RuleType.Property: return s_nonePropertyRule; case RuleType.Event: return s_noneEventRule; default: throw new Exception($"Invalid rule type {ruleType}"); } } if (_rules.TryGetValue((ruleName, ruleType), out rule)) { return rule; } if (!_rawRuleElements.TryGetValue((ruleName, ruleType), out element)) { throw new Exception($"Invalid xml file, rule {ruleName} type {ruleType} not found"); } } else { element = ele; } switch (ruleType) { case RuleType.Assembly: rule = ParseAssemblyRule(ruleName, element); break; case RuleType.Type: rule = ParseTypeRule(ruleName, element); break; case RuleType.Method: rule = ParseMethodRule(ruleName, element); break; case RuleType.Field: rule = ParseFieldRule(ruleName, element); break; case RuleType.Property: rule = ParsePropertyRule(ruleName, element); break; case RuleType.Event: rule = ParseEventRule(ruleName, element); break; default: throw new Exception($"Invalid rule type {ruleType}"); } if (!string.IsNullOrEmpty(ruleName)) { _rules.Add((ruleName, ruleType), rule); } return rule; } private static bool ParseBoolNoneOrFalse(string str) { if (string.IsNullOrEmpty(str)) { return true; } switch (str.ToLowerInvariant()) { case "1": case "true": throw new Exception($"Invalid bool value '{str}', only accept '0' or 'false' because default is true"); // true is default case "0": case "false": return false; default: throw new Exception($"Invalid bool value {str}"); } } private AssemblyRule ParseAssemblyRule(string ruleName, XmlElement element) { var rule = new AssemblyRule(); rule.ruleName = ruleName; rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name")); rule.typeRuleSpecs = new List(); foreach (XmlNode node in element.ChildNodes) { if (!(node is XmlElement childElement)) { continue; } if (childElement.Name != "type") { throw new Exception($"Invalid xml file, unknown node {childElement.Name}"); } var typeRuleSpec = new TypeRuleSpec(); typeRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); typeRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); typeRuleSpec.rule = (TypeRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Type, childElement); rule.typeRuleSpecs.Add(typeRuleSpec); } return rule; } private TypeRule ParseTypeRule(string ruleName, XmlElement element) { var rule = new TypeRule(); rule.ruleName = ruleName; rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name")); rule.obfuscateNamespace = ParseBoolNoneOrFalse(element.GetAttribute("ob-namespace")); //rule.nestTypeRuleSpecs = new List(); rule.fieldRuleSpecs = new List(); rule.methodRuleSpecs = new List(); rule.propertyRuleSpecs = new List(); rule.eventRuleSpecs = new List(); foreach (XmlNode node in element.ChildNodes) { if (!(node is XmlElement childElement)) { continue; } switch (childElement.Name) { //case "nesttype": //{ // var typeRuleSpec = new TypeRuleSpec(); // typeRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); // typeRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); // typeRuleSpec.rule = (TypeRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Type, childElement); // rule.nestTypeRuleSpecs.Add(typeRuleSpec); // break; //} case "field": { var fieldRuleSpec = new FieldRuleSpec(); fieldRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); fieldRuleSpec.modifierType = ParseModifierType(childElement.GetAttribute("modifier")); fieldRuleSpec.rule = (FieldRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Field, childElement); rule.fieldRuleSpecs.Add(fieldRuleSpec); break; } case "method": { rule.methodRuleSpecs.Add(ParseMethodRuleSpec(childElement)); break; } case "property": { var propertyRulerSpec = new PropertyRuleSpec(); propertyRulerSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); propertyRulerSpec.rule = (PropertyRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Property, childElement); rule.propertyRuleSpecs.Add(propertyRulerSpec); break; } case "event": { var eventRuleSpec = new EventRuleSpec(); eventRuleSpec.nameMatcher = new NameMatcher(childElement.GetAttribute("name")); eventRuleSpec.rule = (EventRule)GetOrParseRule(childElement.GetAttribute("rule"), RuleType.Event, childElement); rule.eventRuleSpecs.Add(eventRuleSpec); break; } default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in type rule {ruleName}"); } } return rule; } private MethodRuleSpec ParseMethodRuleSpec(XmlElement el) { var methodRuleSpec = new MethodRuleSpec(); methodRuleSpec.nameMatcher = new NameMatcher(el.GetAttribute("name")); methodRuleSpec.modifierType = ParseModifierType(el.GetAttribute("modifier")); methodRuleSpec.rule = (MethodRule)GetOrParseRule(el.GetAttribute("rule"), RuleType.Method, el); return methodRuleSpec; } private MethodRule ParseMethodRule(string ruleName, XmlElement element) { var rule = new MethodRule(); rule.ruleName = ruleName; rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name")); rule.obfuscateParam = ParseBoolNoneOrFalse(element.GetAttribute("ob-param")); rule.obfuscateBody = ParseBoolNoneOrFalse(element.GetAttribute("ob-body")); return rule; } private FieldRule ParseFieldRule(string ruleName, XmlElement element) { var rule = new FieldRule(); rule.ruleName = ruleName; rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name")); return rule; } private PropertyRule ParsePropertyRule(string ruleName, XmlElement element) { var rule = new PropertyRule(); rule.ruleName = ruleName; rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name")); foreach (XmlNode node in element.ChildNodes) { if (!(node is XmlElement childElement)) { continue; } switch (node.Name) { case "getter": { if (rule.getter != null) { throw new Exception($"Invalid xml file, duplicate getter rule in property rule {ruleName}"); } rule.getter = ParseMethodRuleSpec(childElement); break; } case "setter": { if (rule.setter != null) { throw new Exception($"Invalid xml file, duplicate setter rule in property rule {ruleName}"); } rule.setter = ParseMethodRuleSpec(childElement); break; } default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in property rule {ruleName}"); } } return rule; } private EventRule ParseEventRule(string ruleName, XmlElement element) { var rule = new EventRule(); rule.ruleName = ruleName; rule.obfuscateName = ParseBoolNoneOrFalse(element.GetAttribute("ob-name")); foreach (XmlNode node in element.ChildNodes) { if (!(node is XmlElement childElement)) { continue; } switch (node.Name) { case "add": { if (rule.add != null) { throw new Exception($"Invalid xml file, duplicate getter rule in property rule {ruleName}"); } rule.add = ParseMethodRuleSpec(childElement); break; } case "remove": { if (rule.remove != null) { throw new Exception($"Invalid xml file, duplicate setter rule in property rule {ruleName}"); } rule.remove = ParseMethodRuleSpec(childElement); break; } case "fire": { if (rule.fire != null) { throw new Exception($"Invalid xml file, duplicate fire rule in property rule {ruleName}"); } rule.fire = ParseMethodRuleSpec(childElement); break; } default: throw new Exception($"Invalid xml file, unknown node {childElement.Name} in event rule {ruleName}"); } } return rule; } private void LoadXmls(List xmlFiles) { var rawAssemblySpecElements = new List(); foreach (string file in xmlFiles) { LoadRawXml(file, rawAssemblySpecElements); } ResolveAssemblySpecs(rawAssemblySpecElements); } private void ResolveAssemblySpecs(List rawAssemblySpecElements) { foreach (XmlElement ele in rawAssemblySpecElements) { string assemblyName = ele.GetAttribute("name"); if (string.IsNullOrEmpty(assemblyName)) { throw new Exception($"Invalid xml file, assembly name is empty"); } if (!_obfuscationAssemblyNames.Contains(assemblyName)) { throw new Exception($"unknown assembly name:{assemblyName}, not in ObfuzSettings.obfuscationAssemblyNames"); } if (_assemblyRuleSpecs.ContainsKey(assemblyName)) { throw new Exception($"Invalid xml file, duplicate assembly name {assemblyName}"); } var assemblyRule = new AssemblyRuleSpec() { assemblyName = assemblyName, rule = (AssemblyRule)GetOrParseRule(ele.GetAttribute("rule"), RuleType.Assembly, ele), }; _assemblyRuleSpecs.Add(assemblyName, assemblyRule); } } private RuleType ParseRuleType(string ruleType) { switch (ruleType) { case "assembly": return RuleType.Assembly; case "type": return RuleType.Type; case "method": return RuleType.Method; case "field": return RuleType.Field; case "property": return RuleType.Property; case "event": return RuleType.Event; default: throw new Exception($"Invalid rule type {ruleType}"); } } private ModifierType ParseModifierType(string modifierType) { if (string.IsNullOrEmpty(modifierType)) { return ModifierType.Private; } switch (modifierType) { case "public": return ModifierType.Public; case "protected": return ModifierType.Protected; case "private": return ModifierType.Private; default: throw new Exception($"Invalid modifier type {modifierType}"); } } private void LoadRawXml(string xmlFile, List rawAssemblyElements) { Debug.Log($"ObfuscateRule::LoadXml {xmlFile}"); var doc = new XmlDocument(); //var nsManager = new XmlNamespaceManager(doc.NameTable); //nsManager.AddNamespace("ob", "https://github.com/focus-creative-games/Obfuz"); // 绑定前缀到 URI doc.Load(xmlFile); var root = doc.DocumentElement; if (root.Name != "obfuz") { throw new Exception($"Invalid xml file {xmlFile}, root name should be 'obfuz'"); } foreach (XmlNode node in root.ChildNodes) { if (!(node is XmlElement element)) { continue; } switch (element.Name) { case "rules": { ParseRules(xmlFile, element); break; } case "assembly": { rawAssemblyElements.Add(element); break; } default: { throw new Exception($"Invalid xml file {xmlFile}, unknown node {element.Name}"); } } } } void ParseRules(string xmlFile, XmlElement rulesNode) { foreach (XmlNode node in rulesNode) { if (!(node is XmlElement ruleEle)) { continue; } string ruleName = ruleEle.GetAttribute("name"); string ruleTypeName = ruleEle.Name; RuleType ruleType = ParseRuleType(ruleTypeName); var key = (ruleName, ruleType); if (_rawRuleElements.ContainsKey(key)) { throw new Exception($"Invalid xml file {xmlFile}, duplicate rule name:{ruleName} type:{ruleType}"); } _rawRuleElements.Add(key, ruleEle); } } private ModifierType ComputeModifierType(TypeAttributes visibility) { if (visibility == TypeAttributes.NotPublic || visibility == TypeAttributes.NestedPrivate) { return ModifierType.Private; } if (visibility == TypeAttributes.Public || visibility == TypeAttributes.NestedPublic) { return ModifierType.Public; } return ModifierType.Protected; } private ModifierType ComputeModifierType(FieldAttributes access) { if (access == FieldAttributes.Private || access == FieldAttributes.PrivateScope) { return ModifierType.Private; } if (access == FieldAttributes.Public) { return ModifierType.Public; } return ModifierType.Protected; } //private ModifierType ComputeModifierType(MethodAttributes access) //{ // if (access == MethodAttributes.Private || access == MethodAttributes.PrivateScope) // { // return ModifierType.Private; // } // if (access == MethodAttributes.Public) // { // return ModifierType.Public; // } // return ModifierType.Protected; //} private bool MatchModifier(ModifierType modifierType, TypeDef typeDef) { return modifierType <= ComputeModifierType(typeDef.Visibility); } private bool MatchModifier(ModifierType modifierType, FieldDef fieldDef) { return modifierType <= ComputeModifierType(fieldDef.Access); } private bool MatchModifier(ModifierType modifierType, MethodDef methodDef) { return modifierType <= ComputeModifierType((FieldAttributes)methodDef.Access); } //private bool MatchModifier(ModifierType modifierType, PropertyDef propertyDef) //{ // return modifierType <= ComputeModifierType((FieldAttributes)propertyDef.Attributes); //} private class MethodComputeCache { public bool obfuscateName = true; public bool obfuscateParam = true; public bool obfuscateBody = true; } private class TypeDefComputeCache { public bool obfuscateName = true; public bool obfuscateNamespace = true; public readonly Dictionary methods = new Dictionary(); public readonly HashSet notObfuscatedFields = new HashSet(); public readonly HashSet notObfuscatedProperties = new HashSet(); public readonly HashSet notObfuscatedEvents = new HashSet(); } private readonly Dictionary _typeRenameCache = new Dictionary(); private readonly HashSet _obfuscationAssemblyNames; public ConfigurableRenamePolicy(List obfuscationAssemblyNames, List xmlFiles) { _obfuscationAssemblyNames = new HashSet(obfuscationAssemblyNames); LoadXmls(xmlFiles); } private TypeDefComputeCache GetOrCreateTypeDefRenameComputeCache(TypeDef typeDef) { if (_typeRenameCache.TryGetValue(typeDef, out var cache)) { return cache; } cache = new TypeDefComputeCache(); _typeRenameCache.Add(typeDef, cache); if (!_assemblyRuleSpecs.TryGetValue(typeDef.Module.Assembly.Name, out var assemblyRuleSpec) || assemblyRuleSpec.rule == null) { return cache; } string typeName = typeDef.FullName; var totalMethodSpecs = new List(); var totalMethodSpecFromPropertyAndEvents = new List<(MethodDef, MethodRuleSpec)>(); foreach (var typeRule in assemblyRuleSpec.rule.typeRuleSpecs) { if ((typeRule.nameMatcher != null && !typeRule.nameMatcher.IsMatch(typeName)) || !MatchModifier(typeRule.modifierType, typeDef)) { continue; } cache.obfuscateNamespace &= typeRule.rule.obfuscateNamespace; cache.obfuscateName &= typeRule.rule.obfuscateName; totalMethodSpecs.AddRange(typeRule.rule.methodRuleSpecs); foreach (var eventDef in typeDef.Events) { foreach (var eventSpec in typeRule.rule.eventRuleSpecs) { if (eventSpec.nameMatcher != null && !eventSpec.nameMatcher.IsMatch(eventDef.Name)) { continue; } EventRule eventRule = eventSpec.rule; if (!eventRule.obfuscateName) { cache.notObfuscatedEvents.Add(eventDef); } if (eventDef.AddMethod != null && eventRule.add != null && MatchModifier(eventRule.add.modifierType, eventDef.AddMethod)) { totalMethodSpecFromPropertyAndEvents.Add((eventDef.AddMethod,eventRule.add)); } if (eventDef.RemoveMethod != null && eventRule.remove != null && MatchModifier(eventRule.remove.modifierType, eventDef.RemoveMethod)) { totalMethodSpecFromPropertyAndEvents.Add((eventDef.RemoveMethod, eventRule.remove)); } if (eventDef.InvokeMethod != null && eventRule.fire != null && MatchModifier(eventRule.fire.modifierType, eventDef.InvokeMethod)) { totalMethodSpecFromPropertyAndEvents.Add((eventDef.InvokeMethod, eventRule.fire)); } } } foreach (var propertyDef in typeDef.Properties) { foreach (var propertySpec in typeRule.rule.propertyRuleSpecs) { if (propertySpec.nameMatcher != null && !propertySpec.nameMatcher.IsMatch(propertyDef.Name)) { continue; } PropertyRule propertyRule = propertySpec.rule; if (!propertyRule.obfuscateName) { cache.notObfuscatedProperties.Add(propertyDef); } if (propertyDef.GetMethod != null && propertyRule.getter != null && MatchModifier(propertyRule.getter.modifierType, propertyDef.GetMethod)) { totalMethodSpecFromPropertyAndEvents.Add((propertyDef.GetMethod, propertyRule.getter)); } if (propertyDef.SetMethod != null && propertyRule.setter != null && MatchModifier(propertyRule.setter.modifierType, propertyDef.SetMethod)) { totalMethodSpecFromPropertyAndEvents.Add((propertyDef.SetMethod, propertyRule.setter)); } } } foreach (var fieldDef in typeDef.Fields) { foreach (var fieldRule in typeRule.rule.fieldRuleSpecs) { if ((fieldRule.nameMatcher == null || fieldRule.nameMatcher.IsMatch(fieldDef.Name)) && MatchModifier(fieldRule.modifierType, fieldDef) && !fieldRule.rule.obfuscateName) { cache.notObfuscatedFields.Add(fieldDef); } } } foreach (MethodDef methodDef in typeDef.Methods) { foreach (var e in totalMethodSpecFromPropertyAndEvents) { if (e.Item1 != methodDef) { continue; } if (!cache.methods.TryGetValue(methodDef, out var methodCache)) { methodCache = new MethodComputeCache(); cache.methods.Add(methodDef, methodCache); } MethodRule methodRule = e.Item2.rule; methodCache.obfuscateName &= methodRule.obfuscateName; methodCache.obfuscateParam &= methodRule.obfuscateParam; methodCache.obfuscateBody &= methodRule.obfuscateBody; } foreach (MethodRuleSpec methodSpec in totalMethodSpecs) { if ((methodSpec.nameMatcher != null && !methodSpec.nameMatcher.IsMatch(methodDef.Name)) || !MatchModifier(methodSpec.modifierType, methodDef)) { continue; } if (!cache.methods.TryGetValue(methodDef, out var methodCache)) { methodCache = new MethodComputeCache(); cache.methods.Add(methodDef, methodCache); } MethodRule methodRule = methodSpec.rule; methodCache.obfuscateName &= methodRule.obfuscateName; methodCache.obfuscateParam &= methodRule.obfuscateParam; methodCache.obfuscateBody &= methodRule.obfuscateBody; } } } return cache; } public override bool NeedRename(TypeDef typeDef) { TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef); return cache.obfuscateName; } public override bool NeedRename(MethodDef methodDef) { TypeDef typeDef = methodDef.DeclaringType; TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef); if (!cache.methods.TryGetValue(methodDef, out var methodCache)) { return true; } return methodCache.obfuscateName; } public override bool NeedRename(FieldDef fieldDef) { TypeDef typeDef = fieldDef.DeclaringType; TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef); return !cache.notObfuscatedFields.Contains(fieldDef); } public override bool NeedRename(PropertyDef propertyDef) { TypeDef typeDef = propertyDef.DeclaringType; TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef); return !cache.notObfuscatedProperties.Contains(propertyDef); } public override bool NeedRename(EventDef eventDef) { TypeDef typeDef = eventDef.DeclaringType; TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef); return !cache.notObfuscatedEvents.Contains(eventDef); } public override bool NeedRename(ParamDef paramDef) { MethodDef methodDef = paramDef.DeclaringMethod; TypeDef typeDef = methodDef.DeclaringType; TypeDefComputeCache cache = GetOrCreateTypeDefRenameComputeCache(typeDef); if (!cache.methods.TryGetValue(methodDef, out var methodCache)) { return true; } return methodCache.obfuscateParam; } } }