From 28ac98352df1c9cccb5ed4c086b091ca9457d128 Mon Sep 17 00:00:00 2001 From: walon Date: Wed, 28 May 2025 12:00:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9E=84=E5=BB=BA=E8=BF=87=E7=A8=8B=E4=B8=AD?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=BD=AC=E6=8D=A2link.xml=E4=B8=AD=E5=8E=9F?= =?UTF-8?q?=E5=A7=8B=E7=9A=84=E7=B1=BB=E5=9E=8B=E5=90=8D=E4=B8=BA=E6=B7=B7?= =?UTF-8?q?=E6=B7=86=E5=90=8E=E7=9A=84=E5=90=8D=E7=A7=B0=EF=BC=8C=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E6=B7=B7=E6=B7=86=E5=90=8E=E8=83=BD=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Editor/Settings/ObfuzSettings.cs | 5 + .../Editor/Unity/LinkXmlProcess.cs | 126 ++++++++++++++++++ .../Editor/Unity/LinkXmlProcess.cs.meta | 11 ++ .../Editor/Unity/LiteSymbolMappingReader.cs | 116 ++++++++++++++++ .../Unity/LiteSymbolMappingReader.cs.meta | 11 ++ 5 files changed, 269 insertions(+) create mode 100644 com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs create mode 100644 com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta create mode 100644 com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs create mode 100644 com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta diff --git a/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs b/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs index b137d18..a510d8b 100644 --- a/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs +++ b/com.code-philosophy.obfuz/Editor/Settings/ObfuzSettings.cs @@ -54,6 +54,11 @@ namespace Obfuz.Settings return $"{ObfuzRootDir}/{target}/TempObfuscatedAssemblies"; } + public string GetObfuscatedLinkXmlPath(BuildTarget target) + { + return $"{ObfuzRootDir}/{target}/link.xml"; + } + private static ObfuzSettings s_Instance; public static ObfuzSettings Instance diff --git a/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs b/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs new file mode 100644 index 0000000..f307da7 --- /dev/null +++ b/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs @@ -0,0 +1,126 @@ +using Obfuz.Settings; +using Obfuz.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEditor.UnityLinker; +using UnityEngine; +using static UnityEngine.GraphicsBuffer; +using FileUtil = Obfuz.Utils.FileUtil; + +namespace Obfuz.Unity +{ + public class LinkXmlProcess : IUnityLinkerProcessor + { + public int callbackOrder => 10000; + + public string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data) + { + return GenerateAdditionalLinkXmlFile(data.target); + } + + public static string GenerateAdditionalLinkXmlFile(BuildTarget target) + { + ObfuzSettings settings = ObfuzSettings.Instance; + string linkXmlPath = settings.GetObfuscatedLinkXmlPath(target); + FileUtil.CreateParentDir(linkXmlPath); + + var writer = System.Xml.XmlWriter.Create(linkXmlPath, + new System.Xml.XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true }); + try + { + string[] linkGuids = AssetDatabase.FindAssets("t:TextAsset"); + var linkXmlPaths = linkGuids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)) + .Where(f => Path.GetFileName(f) == "link.xml") + .ToArray(); + + var symbolMapping = new LiteSymbolMappingReader(settings.symbolObfusSettings.symbolMappingFile); + var assembliesToObfuscated = new HashSet(settings.assemblySettings.GetAssembliesToObfuscate()); + + writer.WriteStartDocument(); + writer.WriteStartElement("linker"); + foreach (string linkPath in linkXmlPaths) + { + TransformLinkXml(linkPath, symbolMapping, assembliesToObfuscated, writer); + } + writer.WriteEndElement(); + writer.WriteEndDocument(); + } + finally + { + writer.Close(); + } + Debug.Log($"LinkXmlProcess write {linkXmlPath}"); + return linkXmlPath; + } + + private static void TransformLinkXml(string xmlFile, LiteSymbolMappingReader symbolMapping, HashSet assembliesToObfuscated, XmlWriter writer) + { + Debug.Log($"LinkXmlProcess transform link.xml:{xmlFile}"); + var doc = new XmlDocument(); + doc.Load(xmlFile); + var root = doc.DocumentElement; + foreach (XmlNode assNode in root.ChildNodes) + { + if (!(assNode is XmlElement assElement)) + { + continue; + } + if (assElement.Name == "assembly") + { + string assemblyName = assElement.GetAttribute("fullname"); + if (string.IsNullOrEmpty(assemblyName)) + { + throw new Exception($"Invalid node name: {assElement.Name}. attribute 'fullname' missing."); + } + if (!assembliesToObfuscated.Contains(assemblyName)) + { + continue; // Skip assemblies that are not to be obfuscated + } + writer.WriteStartElement("assembly"); + writer.WriteAttributeString("fullname", assemblyName); + if (assElement.HasAttribute("preserve")) + { + writer.WriteAttributeString("preserve", assElement.GetAttribute("preserve")); + } + + foreach (XmlNode typeNode in assElement.ChildNodes) + { + if (typeNode is XmlElement typeElement) + { + if (typeElement.Name == "type") + { + string typeName = typeElement.GetAttribute("fullname"); + if (string.IsNullOrEmpty(typeName)) + { + throw new Exception($"Invalid node name: {typeElement.Name}. attribute 'fullname' missing."); + } + if (!symbolMapping.TryGetNewTypeName(assemblyName, typeName, out string newTypeName)) + { + continue; + } + + writer.WriteStartElement("type"); + writer.WriteAttributeString("fullname", newTypeName); + if (typeElement.HasAttribute("preserve")) + { + writer.WriteAttributeString("preserve", typeElement.GetAttribute("preserve")); + } + writer.WriteEndElement(); + } + } + } + + writer.WriteEndElement(); + } + } + } + } +} diff --git a/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta b/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta new file mode 100644 index 0000000..7ddd2b4 --- /dev/null +++ b/com.code-philosophy.obfuz/Editor/Unity/LinkXmlProcess.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66881cca1e4a78c44b4c9fcd7f8b4fb9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs b/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs new file mode 100644 index 0000000..c04c683 --- /dev/null +++ b/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs @@ -0,0 +1,116 @@ + +using System.Collections.Generic; +using System.Xml; + +namespace Obfuz.Unity +{ + + public class LiteSymbolMappingReader + { + class TypeMappingInfo + { + public string oldFullName; + public string newFullName; + + //public Dictionary MethodMappings = new Dictionary(); + } + + class AssemblyMappingInfo + { + public Dictionary TypeMappings = new Dictionary(); + public Dictionary MethodMappings = new Dictionary(); + } + + private readonly Dictionary _assemblies = new Dictionary(); + + public LiteSymbolMappingReader(string mappingFile) + { + LoadXmlMappingFile(mappingFile); + } + + private void LoadXmlMappingFile(string mappingFile) + { + var doc = new XmlDocument(); + doc.Load(mappingFile); + var root = doc.DocumentElement; + foreach (XmlNode node in root.ChildNodes) + { + if (!(node is XmlElement element)) + { + continue; + } + LoadAssemblyMapping(element); + } + } + + private void LoadAssemblyMapping(XmlElement ele) + { + if (ele.Name != "assembly") + { + throw new System.Exception($"Invalid node name: {ele.Name}. Expected 'assembly'."); + } + string assName = ele.GetAttribute("name"); + if (string.IsNullOrEmpty(assName)) + { + throw new System.Exception($"Invalid node name: {ele.Name}. attribute 'name' missing."); + } + if (!_assemblies.TryGetValue(assName, out var assemblyMappingInfo)) + { + assemblyMappingInfo = new AssemblyMappingInfo(); + _assemblies[assName] = assemblyMappingInfo; + } + + foreach (XmlNode node in ele.ChildNodes) + { + if (!(node is XmlElement element)) + { + continue; + } + if (element.Name == "type") + { + LoadTypeMapping(element, assemblyMappingInfo); + } + } + } + + private void LoadTypeMapping(XmlElement ele, AssemblyMappingInfo assemblyMappingInfo) + { + string oldFullName = ele.GetAttribute("fullName"); + string newFullName = ele.GetAttribute("newFullName"); + string status = ele.GetAttribute("status"); + if (status == "Renamed") + { + if (string.IsNullOrEmpty(oldFullName) || string.IsNullOrEmpty(newFullName)) + { + throw new System.Exception($"Invalid node name: {ele.Name}. attributes 'fullName' or 'newFullName' missing."); + } + assemblyMappingInfo.TypeMappings[oldFullName] = newFullName; + } + //foreach (XmlNode node in ele.ChildNodes) + //{ + // if (!(node is XmlElement c)) + // { + // continue; + // } + // if (node.Name == "method") + // { + // LoadMethodMapping(c); + // } + //} + } + + public bool TryGetNewTypeName(string assemblyName, string oldFullName, out string newFullName) + { + newFullName = null; + if (_assemblies.TryGetValue(assemblyName, out var assemblyMappingInfo)) + { + if (assemblyMappingInfo.TypeMappings.TryGetValue(oldFullName, out newFullName)) + { + return true; + } + } + return false; + } + + } +} diff --git a/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta b/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta new file mode 100644 index 0000000..4abd760 --- /dev/null +++ b/com.code-philosophy.obfuz/Editor/Unity/LiteSymbolMappingReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8429e75dcc6a7e742a3cabaa3e8491c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: