feature: 支持代码水印

main
walon 2025-08-02 21:50:26 +08:00
parent 4db68f707b
commit 1e027e6299
9 changed files with 185 additions and 0 deletions

View File

@ -17,6 +17,7 @@ namespace Obfuz.ObfusPasses
EvalStackObfus = 0x1000, EvalStackObfus = 0x1000,
RemoveConstField = 0x100000, RemoveConstField = 0x100000,
WaterMark = 0x200000,
AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus, AllObfus = SymbolObfus | CallObfus | ExprObfus | ControlFlowObfus | EvalStackObfus,
AllEncrypt = ConstEncrypt | FieldEncrypt, AllEncrypt = ConstEncrypt | FieldEncrypt,

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8b381c6b90aae174a994bd6f2ae6464f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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("<PrivateImplementationDetails>");
if (moduleType == null)
{
//throw new Exception($"Module '{module.Name}' does not contain a '<PrivateImplementationDetails>' type.");
moduleType = new TypeDefUser("<PrivateImplementationDetails>", 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);
}
}
}
}

View File

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

View File

@ -8,6 +8,7 @@ using Obfuz.ObfusPasses.ExprObfus;
using Obfuz.ObfusPasses.FieldEncrypt; using Obfuz.ObfusPasses.FieldEncrypt;
using Obfuz.ObfusPasses.RemoveConstField; using Obfuz.ObfusPasses.RemoveConstField;
using Obfuz.ObfusPasses.SymbolObfus; using Obfuz.ObfusPasses.SymbolObfus;
using Obfuz.ObfusPasses.Watermark;
using Obfuz.Settings; using Obfuz.Settings;
using Obfuz.Utils; using Obfuz.Utils;
using System.Collections.Generic; using System.Collections.Generic;
@ -202,6 +203,10 @@ namespace Obfuz
{ {
builder.AddPass(new ControlFlowObfusPass(settings.controlFlowObfusSettings.ToFacade())); builder.AddPass(new ControlFlowObfusPass(settings.controlFlowObfusSettings.ToFacade()));
} }
if (obfuscationPasses.HasFlag(ObfuscationPassType.WaterMark))
{
builder.AddPass(new WatermarkPass(settings.watermarkSettings.ToFacade()));
}
if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus)) if (obfuscationPasses.HasFlag(ObfuscationPassType.SymbolObfus))
{ {
builder.AddPass(new SymbolObfusPass(settings.symbolObfusSettings.ToFacade())); builder.AddPass(new SymbolObfusPass(settings.symbolObfusSettings.ToFacade()));

View File

@ -50,6 +50,9 @@ namespace Obfuz.Settings
[Tooltip("garbage code generator settings")] [Tooltip("garbage code generator settings")]
public GarbageCodeGenerationSettings garbageCodeGenerationSettings; public GarbageCodeGenerationSettings garbageCodeGenerationSettings;
[Tooltip("watermark settings")]
public WatermarkSettings watermarkSettings;
[Tooltip("polymorphic dll settings")] [Tooltip("polymorphic dll settings")]
public PolymorphicDllSettings polymorphicDllSettings; public PolymorphicDllSettings polymorphicDllSettings;

View File

@ -41,6 +41,7 @@ namespace Obfuz.Settings
private SerializedProperty _controlFlowObfusSettings; private SerializedProperty _controlFlowObfusSettings;
private SerializedProperty _garbageCodeGenerationSettings; private SerializedProperty _garbageCodeGenerationSettings;
private SerializedProperty _watermarkSettings;
private SerializedProperty _polymorphicDllSettings; private SerializedProperty _polymorphicDllSettings;
@ -82,6 +83,7 @@ namespace Obfuz.Settings
_controlFlowObfusSettings = _serializedObject.FindProperty("controlFlowObfusSettings"); _controlFlowObfusSettings = _serializedObject.FindProperty("controlFlowObfusSettings");
_garbageCodeGenerationSettings = _serializedObject.FindProperty("garbageCodeGenerationSettings"); _garbageCodeGenerationSettings = _serializedObject.FindProperty("garbageCodeGenerationSettings");
_watermarkSettings = _serializedObject.FindProperty("watermarkSettings");
_polymorphicDllSettings = _serializedObject.FindProperty("polymorphicDllSettings"); _polymorphicDllSettings = _serializedObject.FindProperty("polymorphicDllSettings");
} }
@ -113,6 +115,7 @@ namespace Obfuz.Settings
EditorGUILayout.PropertyField(_controlFlowObfusSettings); EditorGUILayout.PropertyField(_controlFlowObfusSettings);
EditorGUILayout.PropertyField(_garbageCodeGenerationSettings); EditorGUILayout.PropertyField(_garbageCodeGenerationSettings);
EditorGUILayout.PropertyField(_watermarkSettings);
EditorGUILayout.PropertyField(_polymorphicDllSettings); EditorGUILayout.PropertyField(_polymorphicDllSettings);

View File

@ -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
};
}
}
}

View File

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