From 6011272fe74d7fd14d4e20e40f293c19e3d8e7d0 Mon Sep 17 00:00:00 2001 From: walon Date: Sat, 10 May 2025 17:41:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20XmlAssemblyTypeMethodRuleP?= =?UTF-8?q?arser.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Conf/XmlAssemblyTypeMethodRuleParser.cs | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs diff --git a/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs b/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs new file mode 100644 index 0000000..aac0a66 --- /dev/null +++ b/Editor/Conf/XmlAssemblyTypeMethodRuleParser.cs @@ -0,0 +1,267 @@ +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 UnityEditor.VersionControl; +using UnityEngine; + +namespace Obfuz.Conf +{ + public interface IRule + { + void InheritParent(T parentRule); + } + + + public interface IMethodRule where R: IRule + { + string Name { get; set; } + NameMatcher NameMatcher { get; set; } + + R Rule { get; set; } + } + + public abstract class MethodRuleBase : IMethodRule where R : IRule + { + public string Name { get; set; } + public NameMatcher NameMatcher { get; set; } + + public R Rule { get; set; } + } + + public interface ITypeRule where T: IMethodRule where R : IRule + { + string Name { get; set; } + + NameMatcher NameMatcher { get; set; } + + R Rule { get; set; } + + List Methods { get; set; } + } + + public abstract class TypeRuleBase : ITypeRule where T : IMethodRule where R : IRule + { + public string Name { get; set; } + + public NameMatcher NameMatcher { get; set; } + + public R Rule { get; set; } + + public List Methods { get; set; } + } + + public interface IAssemblyRule where TType : ITypeRule where TMethod : IMethodRule where TRule : IRule + { + string Name { get; set; } + + TRule Rule { get; set; } + + List Types { get; set; } + } + public abstract class AssemblyRuleBase : IAssemblyRule where TType : ITypeRule where TMethod : IMethodRule where TRule : IRule + { + public string Name { get; set; } + + public TRule Rule { get; set; } + + public List Types { get; set; } + } + + public class XmlAssemblyTypeMethodRuleParser + where TMethod : IMethodRule, new() + where TType : ITypeRule, new() + where TAssembly : IAssemblyRule, new() + where TRule : IRule, new() + { + private readonly HashSet _toObfuscatedAssemblyNames; + private readonly Func _ruleParser; + private readonly Action _unknownNodeTypeHandler; + private readonly Dictionary _assemblySpecs = new Dictionary(); + + public XmlAssemblyTypeMethodRuleParser(IEnumerable toObfuscatedAssemblyNames, Func ruleParser, Action unknownNodeTypeHandler) + { + _toObfuscatedAssemblyNames = new HashSet(toObfuscatedAssemblyNames); + _ruleParser = ruleParser; + _unknownNodeTypeHandler = unknownNodeTypeHandler; + } + + public Dictionary AssemblySpecs => _assemblySpecs; + + public void LoadConfigs(IEnumerable configFiles) + { + foreach (var configFile in configFiles) + { + LoadConfig(configFile); + } + } + + public void LoadConfig(string configFile) + { + if (string.IsNullOrEmpty(configFile)) + { + throw new Exception($"Invalid xml file {configFile}, file name is empty"); + } + Debug.Log($"ConfigurableObfuscationPolicy::LoadConfig {configFile}"); + var doc = new XmlDocument(); + doc.Load(configFile); + var root = doc.DocumentElement; + if (root.Name != "obfuz") + { + throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'"); + } + foreach (XmlNode node in root.ChildNodes) + { + if (!(node is XmlElement ele)) + { + continue; + } + switch (ele.Name) + { + case "assembly": + { + TAssembly assSpec = ParseAssembly(configFile, ele); + _assemblySpecs.Add(assSpec.Name, assSpec); + break; + } + default: + { + if (_unknownNodeTypeHandler == null) + { + throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}"); + } + _unknownNodeTypeHandler(configFile, ele); + break; + } + } + } + } + + private TAssembly ParseAssembly(string configFile, XmlElement ele) + { + var assemblySpec = new TAssembly(); + string name = ele.GetAttribute("name"); + if (!_toObfuscatedAssemblyNames.Contains(name)) + { + throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames"); + } + if (_assemblySpecs.ContainsKey(name)) + { + throw new Exception($"Invalid xml file {configFile}, assembly name {name} is duplicated"); + } + assemblySpec.Name = name; + assemblySpec.Rule = _ruleParser(configFile, ele); + + var types = new List(); + assemblySpec.Types = types; + foreach (XmlNode node in ele.ChildNodes) + { + if (!(node is XmlElement childEle)) + { + continue; + } + switch (childEle.Name) + { + case "type": + { + types.Add(ParseType(configFile, childEle)); + break; + } + default: + { + throw new Exception($"Invalid xml file, unknown node {childEle.Name}"); + } + } + } + return assemblySpec; + } + + private TType ParseType(string configFile, XmlElement element) + { + var typeSpec = new TType(); + + string name = element.GetAttribute("name"); + typeSpec.Name = name; + typeSpec.NameMatcher = new NameMatcher(name); + typeSpec.Rule = _ruleParser(configFile, element); + + var methods = new List(); + typeSpec.Methods = methods; + foreach (XmlNode node in element.ChildNodes) + { + if (!(node is XmlElement ele)) + { + continue; + } + switch (ele.Name) + { + case "method": + { + methods.Add(ParseMethod(configFile, ele)); + break; + } + default: + { + throw new Exception($"Invalid xml file, unknown node {ele.Name}"); + } + } + } + return typeSpec; + } + + private TMethod ParseMethod(string configFile, XmlElement element) + { + var methodSpec = new TMethod(); + string name = element.GetAttribute("name"); + methodSpec.Name = name; + methodSpec.NameMatcher = new NameMatcher(name); + methodSpec.Rule = _ruleParser(configFile, element); + return methodSpec; + } + + public TRule GetMethodRule(MethodDef method, TRule defaultRule) + { + var assemblyName = method.DeclaringType.Module.Assembly.Name; + if (!_assemblySpecs.TryGetValue(assemblyName, out var assSpec)) + { + return defaultRule; + } + string declaringTypeName = method.DeclaringType.FullName; + foreach (var typeSpec in assSpec.Types) + { + if (typeSpec.NameMatcher.IsMatch(declaringTypeName)) + { + foreach (var methodSpec in typeSpec.Methods) + { + if (methodSpec.NameMatcher.IsMatch(method.Name)) + { + return methodSpec.Rule; + } + } + return typeSpec.Rule; + } + } + return assSpec.Rule; + } + + public void InheritParentRules(TRule defaultRule) + { + foreach (TAssembly assSpec in _assemblySpecs.Values) + { + assSpec.Rule.InheritParent(defaultRule); + foreach (TType typeSpec in assSpec.Types) + { + typeSpec.Rule.InheritParent(assSpec.Rule); + foreach (TMethod methodSpec in typeSpec.Methods) + { + methodSpec.Rule.InheritParent(typeSpec.Rule); + } + } + } + } + } +}