From 1e027e6299c36d05d8b8848c1d1d53c2edb058f5 Mon Sep 17 00:00:00 2001 From: walon Date: Sat, 2 Aug 2025 21:50:26 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B0=B4=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/ObfusPasses/ObfuscationPassType.cs | 1 + Editor/ObfusPasses/WalterMark.meta | 8 ++ .../ObfusPasses/WalterMark/WatermarkPass.cs | 112 ++++++++++++++++++ .../WalterMark/WatermarkPass.cs.meta | 11 ++ Editor/ObfuscatorBuilder.cs | 5 + Editor/Settings/ObfuzSettings.cs | 3 + Editor/Settings/ObfuzSettingsProvider.cs | 3 + Editor/Settings/WatermarkSettings.cs | 31 +++++ Editor/Settings/WatermarkSettings.cs.meta | 11 ++ 9 files changed, 185 insertions(+) create mode 100644 Editor/ObfusPasses/WalterMark.meta create mode 100644 Editor/ObfusPasses/WalterMark/WatermarkPass.cs create mode 100644 Editor/ObfusPasses/WalterMark/WatermarkPass.cs.meta create mode 100644 Editor/Settings/WatermarkSettings.cs create mode 100644 Editor/Settings/WatermarkSettings.cs.meta diff --git a/Editor/ObfusPasses/ObfuscationPassType.cs b/Editor/ObfusPasses/ObfuscationPassType.cs index 697a161..d69717c 100644 --- a/Editor/ObfusPasses/ObfuscationPassType.cs +++ b/Editor/ObfusPasses/ObfuscationPassType.cs @@ -17,6 +17,7 @@ namespace Obfuz.ObfusPasses EvalStackObfus = 0x1000, RemoveConstField = 0x100000, + WaterMark = 0x200000, AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus, AllEncrypt = ConstEncrypt | FieldEncrypt, diff --git a/Editor/ObfusPasses/WalterMark.meta b/Editor/ObfusPasses/WalterMark.meta new file mode 100644 index 0000000..09f95ed --- /dev/null +++ b/Editor/ObfusPasses/WalterMark.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b381c6b90aae174a994bd6f2ae6464f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ObfusPasses/WalterMark/WatermarkPass.cs b/Editor/ObfusPasses/WalterMark/WatermarkPass.cs new file mode 100644 index 0000000..b1c6fcc --- /dev/null +++ b/Editor/ObfusPasses/WalterMark/WatermarkPass.cs @@ -0,0 +1,112 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using dnlib.DotNet.PolymorphicWriter.Utilities; +using Obfuz.Settings; +using Obfuz.Utils; +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using UnityEngine; +using FieldAttributes = dnlib.DotNet.FieldAttributes; +using KeyGenerator = Obfuz.Utils.KeyGenerator; +using TypeAttributes = dnlib.DotNet.TypeAttributes; + +namespace Obfuz.ObfusPasses.Watermark +{ + public class WatermarkPass : ObfuscationPassBase + { + private readonly WatermarkSettingsFacade _watermarkSettings; + + public WatermarkPass(WatermarkSettingsFacade watermarkSettingsFacade) + { + this._watermarkSettings = watermarkSettingsFacade; + } + + public override ObfuscationPassType Type => ObfuscationPassType.WaterMark; + + public override void Start() + { + } + + public override void Stop() + { + + } + + public override void Process() + { + var ctx = ObfuscationPassContext.Current; + foreach (ModuleDef mod in ctx.modulesToObfuscate) + { + AddWaterMarkToAssembly(mod, _watermarkSettings.text); + } + } + + private TypeDef GetDataHolderType(ModuleDef module, TypeDef declaringType, int size) + { + + using (var scope = new DisableTypeDefFindCacheScope(module)) + { + var dataHolderType = new TypeDefUser($"$Obfuz$WatermarkDataHolderSize{size}_{declaringType.NestedTypes.Count}", module.Import(typeof(System.ValueType))); + dataHolderType.Attributes = TypeAttributes.NestedPrivate | TypeAttributes.Sealed; + dataHolderType.Layout = TypeAttributes.ExplicitLayout; + dataHolderType.PackingSize = 1; + dataHolderType.ClassSize = (uint)size; + dataHolderType.DeclaringType = declaringType; + return dataHolderType; + } + } + + private void AddWaterMarkToAssembly(ModuleDef module, string waterMarkText) + { + string finalWatermarkText = $"{waterMarkText} [{module.Name}]"; + TypeDef moduleType = module.FindNormal(""); + if (moduleType == null) + { + //throw new Exception($"Module '{module.Name}' does not contain a '' type."); + moduleType = new TypeDefUser("", module.Import(typeof(object))); + moduleType.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed; + moduleType.CustomAttributes.Add(new CustomAttribute(module.Import(module.Import(typeof(CompilerGeneratedAttribute)).ResolveTypeDefThrow().FindDefaultConstructor()))); + module.Types.Add(moduleType); + } + + var ctx = ObfuscationPassContext.Current; + EncryptionScopeInfo encryptionScope = ctx.moduleEntityManager.EncryptionScopeProvider.GetScope(module); + var random = encryptionScope.localRandomCreator(0); + byte[] watermarkBytes = KeyGenerator.GenerateKey(finalWatermarkText, _watermarkSettings.signatureLength); + for (int subIndex = 0; subIndex < watermarkBytes.Length;) + { + int subSegmentLength = Math.Min(random.NextInt(16, 32) & ~3, watermarkBytes.Length - subIndex); + int paddingLength = random.NextInt(8, 32) & ~3; + int totalLength = subSegmentLength + paddingLength; + TypeDef dataHolderType = GetDataHolderType(module, moduleType, totalLength); + + byte[] subSegment = new byte[totalLength]; + Buffer.BlockCopy(watermarkBytes, subIndex, subSegment, 0, subSegmentLength); + + for (int i = subSegmentLength; i < totalLength; i++) + { + subSegment[i] = (byte)random.NextInt(0, 256); + } + + subIndex += subSegmentLength; + var field = new FieldDefUser($"$Obfuz$WatermarkDataHolderField{moduleType.Fields.Count}", + new FieldSig(dataHolderType.ToTypeSig()), + FieldAttributes.Assembly | FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.HasFieldRVA); + field.DeclaringType = moduleType; + field.InitialValue = subSegment; + } + + var moduleTypeFields = moduleType.Fields.ToList(); + RandomUtil.ShuffleList(moduleTypeFields, random); + moduleType.Fields.Clear(); + foreach (var field in moduleTypeFields) + { + moduleType.Fields.Add(field); + } + } + + + } +} diff --git a/Editor/ObfusPasses/WalterMark/WatermarkPass.cs.meta b/Editor/ObfusPasses/WalterMark/WatermarkPass.cs.meta new file mode 100644 index 0000000..47cf325 --- /dev/null +++ b/Editor/ObfusPasses/WalterMark/WatermarkPass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20c95bc217949f344909cc7049d6046e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ObfuscatorBuilder.cs b/Editor/ObfuscatorBuilder.cs index 8c600af..507130d 100644 --- a/Editor/ObfuscatorBuilder.cs +++ b/Editor/ObfuscatorBuilder.cs @@ -8,6 +8,7 @@ using Obfuz.ObfusPasses.ExprObfus; using Obfuz.ObfusPasses.FieldEncrypt; using Obfuz.ObfusPasses.RemoveConstField; using Obfuz.ObfusPasses.SymbolObfus; +using Obfuz.ObfusPasses.Watermark; using Obfuz.Settings; using Obfuz.Utils; using System.Collections.Generic; @@ -202,6 +203,10 @@ namespace Obfuz { builder.AddPass(new ControlFlowObfusPass(settings.controlFlowObfusSettings.ToFacade())); } + if (obfuscationPasses.HasFlag(ObfuscationPassType.WaterMark)) + { + builder.AddPass(new WatermarkPass(settings.watermarkSettings.ToFacade())); + } if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus)) { builder.AddPass(new SymbolObfusPass(settings.symbolObfusSettings.ToFacade())); diff --git a/Editor/Settings/ObfuzSettings.cs b/Editor/Settings/ObfuzSettings.cs index 190240a..4f111a3 100644 --- a/Editor/Settings/ObfuzSettings.cs +++ b/Editor/Settings/ObfuzSettings.cs @@ -50,6 +50,9 @@ namespace Obfuz.Settings [Tooltip("garbage code generator settings")] public GarbageCodeGenerationSettings garbageCodeGenerationSettings; + [Tooltip("watermark settings")] + public WatermarkSettings watermarkSettings; + [Tooltip("polymorphic dll settings")] public PolymorphicDllSettings polymorphicDllSettings; diff --git a/Editor/Settings/ObfuzSettingsProvider.cs b/Editor/Settings/ObfuzSettingsProvider.cs index 342dc7a..bea128c 100644 --- a/Editor/Settings/ObfuzSettingsProvider.cs +++ b/Editor/Settings/ObfuzSettingsProvider.cs @@ -41,6 +41,7 @@ namespace Obfuz.Settings private SerializedProperty _controlFlowObfusSettings; private SerializedProperty _garbageCodeGenerationSettings; + private SerializedProperty _watermarkSettings; private SerializedProperty _polymorphicDllSettings; @@ -82,6 +83,7 @@ namespace Obfuz.Settings _controlFlowObfusSettings = _serializedObject.FindProperty("controlFlowObfusSettings"); _garbageCodeGenerationSettings = _serializedObject.FindProperty("garbageCodeGenerationSettings"); + _watermarkSettings = _serializedObject.FindProperty("watermarkSettings"); _polymorphicDllSettings = _serializedObject.FindProperty("polymorphicDllSettings"); } @@ -113,6 +115,7 @@ namespace Obfuz.Settings EditorGUILayout.PropertyField(_controlFlowObfusSettings); EditorGUILayout.PropertyField(_garbageCodeGenerationSettings); + EditorGUILayout.PropertyField(_watermarkSettings); EditorGUILayout.PropertyField(_polymorphicDllSettings); diff --git a/Editor/Settings/WatermarkSettings.cs b/Editor/Settings/WatermarkSettings.cs new file mode 100644 index 0000000..785fbca --- /dev/null +++ b/Editor/Settings/WatermarkSettings.cs @@ -0,0 +1,31 @@ +using System; +using UnityEngine; + +namespace Obfuz.Settings +{ + public class WatermarkSettingsFacade + { + public string text; + + public int signatureLength; + } + + [Serializable] + public class WatermarkSettings + { + [Tooltip("Watermark text")] + public string text = "Obfuscated by Obfuz"; + + [Tooltip("Length of the signature in bytes")] + public int signatureLength = 256; + + public WatermarkSettingsFacade ToFacade() + { + return new WatermarkSettingsFacade + { + text = text, + signatureLength = signatureLength + }; + } + } +} diff --git a/Editor/Settings/WatermarkSettings.cs.meta b/Editor/Settings/WatermarkSettings.cs.meta new file mode 100644 index 0000000..e822353 --- /dev/null +++ b/Editor/Settings/WatermarkSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52885711cad0a9541ab5987b98cdcce5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: