构建过程中自动转换link.xml中原始的类型名为混淆后的名称,确保混淆后能正确保留类型

before-split
walon 2025-05-28 12:00:07 +08:00
parent b85f3f54a0
commit 28ac98352d
5 changed files with 269 additions and 0 deletions

View File

@ -54,6 +54,11 @@ namespace Obfuz.Settings
return $"{ObfuzRootDir}/{target}/TempObfuscatedAssemblies"; return $"{ObfuzRootDir}/{target}/TempObfuscatedAssemblies";
} }
public string GetObfuscatedLinkXmlPath(BuildTarget target)
{
return $"{ObfuzRootDir}/{target}/link.xml";
}
private static ObfuzSettings s_Instance; private static ObfuzSettings s_Instance;
public static ObfuzSettings Instance public static ObfuzSettings Instance

View File

@ -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<string>(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<string> 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();
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 66881cca1e4a78c44b4c9fcd7f8b4fb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<string, string> MethodMappings = new Dictionary<string, string>();
}
class AssemblyMappingInfo
{
public Dictionary<string, string> TypeMappings = new Dictionary<string, string>();
public Dictionary<string, string> MethodMappings = new Dictionary<string, string>();
}
private readonly Dictionary<string, AssemblyMappingInfo> _assemblies = new Dictionary<string, AssemblyMappingInfo>();
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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8429e75dcc6a7e742a3cabaa3e8491c5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: