From 09a6b6f6af6740c02c215729307433b32fbf5f29 Mon Sep 17 00:00:00 2001 From: walon Date: Wed, 23 Apr 2025 13:46:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=20Bytes=E6=B7=B7=E6=B7=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConfigDataObfuscationPolicy.cs | 5 ++ .../BytesInitializeFromFieldRvaDataNode.cs | 77 +++++++++++++++++++ .../DataNodes/ConstFromFieldRvaDataNode.cs | 8 +- .../DataObfuscationPolicyBase.cs | 5 ++ .../Virtualization/DataVirtualizationPass.cs | 23 ++++++ .../Virtualization/DefaultDataObfuscator.cs | 4 +- .../BytesInitializeFromFieldRvaDataCreator.cs | 17 ++++ .../Virtualization/IDataObfuscationPolicy.cs | 2 + .../Virtualization/RandomDataNodeCreator.cs | 5 ++ Runtime/ConstUtility.cs | 5 ++ 10 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 Editor/Virtualization/DataNodes/BytesInitializeFromFieldRvaDataNode.cs create mode 100644 Editor/Virtualization/Functions/BytesInitializeFromFieldRvaDataCreator.cs diff --git a/Editor/Virtualization/ConfigDataObfuscationPolicy.cs b/Editor/Virtualization/ConfigDataObfuscationPolicy.cs index afb3d1c..b14c0e5 100644 --- a/Editor/Virtualization/ConfigDataObfuscationPolicy.cs +++ b/Editor/Virtualization/ConfigDataObfuscationPolicy.cs @@ -38,5 +38,10 @@ namespace Obfuz.Virtualization { return true; } + + public override bool NeedObfuscateArray(MethodDef method, byte[] array) + { + return true; + } } } diff --git a/Editor/Virtualization/DataNodes/BytesInitializeFromFieldRvaDataNode.cs b/Editor/Virtualization/DataNodes/BytesInitializeFromFieldRvaDataNode.cs new file mode 100644 index 0000000..1d317f3 --- /dev/null +++ b/Editor/Virtualization/DataNodes/BytesInitializeFromFieldRvaDataNode.cs @@ -0,0 +1,77 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using Obfuz.Emit; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static UnityEngine.Networking.UnityWebRequest; +using UnityEngine.UIElements; + +namespace Obfuz.Virtualization +{ + [NodeOutput(DataNodeType.Int32)] + [NodeOutput(DataNodeType.Int64)] + [NodeOutput(DataNodeType.Float32)] + [NodeOutput(DataNodeType.Float64)] + [NodeOutput(DataNodeType.Bytes)] + [NodeOutput(DataNodeType.String)] + public class BytesInitializeFromFieldRvaDataNode : DataNodeAny + { + + private RvaData AllocateRvaData(CompileContext ctx) + { + ModuleDef mod = ctx.method.Module; + RvaDataAllocator allocator = ctx.rvaDataAllocator; + switch (Type) + { + //case DataNodeType.Int32: return allocator.Allocate(mod, IntValue); + //case DataNodeType.Int64: return allocator.Allocate(mod, LongValue); + //case DataNodeType.Float32: return allocator.Allocate(mod, FloatValue); + //case DataNodeType.Float64: return allocator.Allocate(mod, DoubleValue); + case DataNodeType.Bytes: return allocator.Allocate(mod, BytesValue); + //case DataNodeType.String: return allocator.Allocate(mod, StringValue); + default: + throw new NotSupportedException($"Unsupported type: {Type}."); + } + } + + private static IMethod s_convertBytes; + + private void InitImportMetadatas(ModuleDef mod) + { + if (s_convertBytes != null) + { + return; + } + s_convertBytes = mod.Import(typeof(ConstUtility).GetMethod("InitializeArray", new[] { typeof(Array), typeof(byte[]), typeof(int), typeof(int) })); + } + + IMethod GetConvertMethod(ModuleDef mod) + { + InitImportMetadatas(mod); + return s_convertBytes; + } + + public override void Compile(CompileContext ctx) + { + // only support Int32, int64, bytes. + // string can only create from StringFromBytesNode + // x = memcpy array.GetRange(index, length); + var output = ctx.output; + RvaData rvaData = AllocateRvaData(ctx); + ModuleDef mod = ctx.method.Module; + IMethod convertMethod = GetConvertMethod(mod); + + ctx.output.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.offset)); + output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size)); + //output.Add(Instruction.Create(OpCodes.Newarr, mod.CorLibTypes.Byte.ToTypeDefOrRef())); + //output.Add(Instruction.Create(OpCodes.Ldc_I4, 0)); + //output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size)); + output.Add(Instruction.Create(OpCodes.Call, convertMethod)); + } + } +} diff --git a/Editor/Virtualization/DataNodes/ConstFromFieldRvaDataNode.cs b/Editor/Virtualization/DataNodes/ConstFromFieldRvaDataNode.cs index 433278a..0f294b0 100644 --- a/Editor/Virtualization/DataNodes/ConstFromFieldRvaDataNode.cs +++ b/Editor/Virtualization/DataNodes/ConstFromFieldRvaDataNode.cs @@ -59,7 +59,7 @@ namespace Obfuz.Virtualization s_convertDouble = mod.Import(typeof(BitConverter).GetMethod("ToDouble", new[] { typeof(byte[]), typeof(int) })); s_convertString = mod.Import(typeof(Encoding).GetMethod("GetString", new[] { typeof(byte[]), typeof(int), typeof(int) })); s_Encoding_Utf8 = mod.Import(typeof(Encoding).GetField("UTF8")); - s_convertBytes = mod.Import(typeof(Array).GetMethod("Copy", new[] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) })); + s_convertBytes = mod.Import(typeof(ConstUtility).GetMethod("GetBytes", new[] { typeof(byte[]), typeof(int), typeof(int) })); } IMethod GetConvertMethod(ModuleDef mod) @@ -116,9 +116,9 @@ namespace Obfuz.Virtualization ctx.output.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.offset)); output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size)); - output.Add(Instruction.Create(OpCodes.Newarr, mod.CorLibTypes.Byte.ToTypeDefOrRef())); - output.Add(Instruction.Create(OpCodes.Ldc_I4, 0)); - output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size)); + //output.Add(Instruction.Create(OpCodes.Newarr, mod.CorLibTypes.Byte.ToTypeDefOrRef())); + //output.Add(Instruction.Create(OpCodes.Ldc_I4, 0)); + //output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size)); output.Add(Instruction.Create(OpCodes.Call, convertMethod)); break; } diff --git a/Editor/Virtualization/DataObfuscationPolicyBase.cs b/Editor/Virtualization/DataObfuscationPolicyBase.cs index a47e893..eff81fe 100644 --- a/Editor/Virtualization/DataObfuscationPolicyBase.cs +++ b/Editor/Virtualization/DataObfuscationPolicyBase.cs @@ -33,5 +33,10 @@ namespace Obfuz.Virtualization { return true; } + + public virtual bool NeedObfuscateArray(MethodDef method, byte[] array) + { + return true; + } } } diff --git a/Editor/Virtualization/DataVirtualizationPass.cs b/Editor/Virtualization/DataVirtualizationPass.cs index b1a66ec..afa654b 100644 --- a/Editor/Virtualization/DataVirtualizationPass.cs +++ b/Editor/Virtualization/DataVirtualizationPass.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; +using UnityEngine.Assertions; namespace Obfuz.Virtualization { @@ -138,6 +139,28 @@ namespace Obfuz.Virtualization } break; } + case OperandType.InlineMethod: + { + if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") + { + Instruction prevInst = instructions[i - 1]; + if (prevInst.OpCode.Code == Code.Ldtoken) + { + IField rvaField = (IField)prevInst.Operand; + FieldDef ravFieldDef = rvaField.ResolveFieldDefThrow(); + byte[] data = ravFieldDef.InitialValue; + if (data != null && _dataObfuscatorPolicy.NeedObfuscateArray(method, data)) + { + // remove prev ldtoken instruction + Assert.AreEqual(Code.Ldtoken, resultInstructions[resultInstructions.Count - 1].OpCode.Code); + resultInstructions.RemoveAt(resultInstructions.Count - 1); + _dataObfuscator.ObfuscateBytes(method, data, obfuscatedInstructions); + obfuscated = true; + } + } + } + break; + } } resultInstructions.Add(inst); if (obfuscated) diff --git a/Editor/Virtualization/DefaultDataObfuscator.cs b/Editor/Virtualization/DefaultDataObfuscator.cs index 9be395d..f4ac857 100644 --- a/Editor/Virtualization/DefaultDataObfuscator.cs +++ b/Editor/Virtualization/DefaultDataObfuscator.cs @@ -64,7 +64,9 @@ namespace Obfuz.Virtualization public void ObfuscateBytes(MethodDef method, Array value, List obfuscatedInstructions) { - throw new NotSupportedException(); + IDataNode node = _nodeCreator.CreateRandom(DataNodeType.Bytes, value); + CompileNode(node, method, obfuscatedInstructions); + //throw new NotSupportedException(); //obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_I4, value.Length)); } diff --git a/Editor/Virtualization/Functions/BytesInitializeFromFieldRvaDataCreator.cs b/Editor/Virtualization/Functions/BytesInitializeFromFieldRvaDataCreator.cs new file mode 100644 index 0000000..bea40c3 --- /dev/null +++ b/Editor/Virtualization/Functions/BytesInitializeFromFieldRvaDataCreator.cs @@ -0,0 +1,17 @@ +using dnlib.DotNet.Emit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.Virtualization.Functions +{ + public class BytesInitializeFromFieldRvaDataCreator : NodeCreatorBase + { + public override IDataNode CreateExpr(DataNodeType type, object value, CreateExpressionOptions options) + { + return new BytesInitializeFromFieldRvaDataNode { Type = type, Value = value }; + } + } +} diff --git a/Editor/Virtualization/IDataObfuscationPolicy.cs b/Editor/Virtualization/IDataObfuscationPolicy.cs index 6275903..055bf72 100644 --- a/Editor/Virtualization/IDataObfuscationPolicy.cs +++ b/Editor/Virtualization/IDataObfuscationPolicy.cs @@ -20,5 +20,7 @@ namespace Obfuz.Virtualization bool NeedObfuscateDouble(MethodDef method, double value); bool NeedObfuscateString(MethodDef method, string value); + + bool NeedObfuscateArray(MethodDef method, byte[] array); } } diff --git a/Editor/Virtualization/RandomDataNodeCreator.cs b/Editor/Virtualization/RandomDataNodeCreator.cs index 5946421..6bc11b4 100644 --- a/Editor/Virtualization/RandomDataNodeCreator.cs +++ b/Editor/Virtualization/RandomDataNodeCreator.cs @@ -38,6 +38,11 @@ namespace Obfuz.Virtualization new ConstFieldDataCreator(), }; _functions.Add(DataNodeType.String, stringFuncs); + var bytesFuncs = new List() + { + new BytesInitializeFromFieldRvaDataCreator(), + }; + _functions.Add(DataNodeType.Bytes, bytesFuncs); } public override IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options) diff --git a/Runtime/ConstUtility.cs b/Runtime/ConstUtility.cs index cfcfb4f..209661e 100644 --- a/Runtime/ConstUtility.cs +++ b/Runtime/ConstUtility.cs @@ -41,6 +41,11 @@ namespace Obfuz return result; } + public static void InitializeArray(Array array, byte[] data, int offset, int length) + { + Buffer.BlockCopy(data, offset, array, 0, length); + } + public static int CastFloatAsInt(float value) { return UnsafeUtility.As(ref value);