From b604810171e670e060f092f93cc3f213a12cf430 Mon Sep 17 00:00:00 2001 From: walon Date: Thu, 24 Apr 2025 12:10:15 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=20DataVirtualizationPass?= =?UTF-8?q?=EF=BC=8C=E7=A7=BB=E9=99=A4=E9=87=8D=E5=A4=8D=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/DynamicProxy/DynamicProxyPass.cs | 8 +- Editor/Emit/DynamicProxyMethodAllocator.cs | 2 +- Editor/ExprObfuscation/ExprObfuscationPass.cs | 19 +- Editor/MethodBodyObfuscationPassBase.cs | 12 +- .../Virtualization/DataVirtualizationPass.cs | 216 +++++++----------- 5 files changed, 114 insertions(+), 143 deletions(-) diff --git a/Editor/DynamicProxy/DynamicProxyPass.cs b/Editor/DynamicProxy/DynamicProxyPass.cs index d225da1..49c37ad 100644 --- a/Editor/DynamicProxy/DynamicProxyPass.cs +++ b/Editor/DynamicProxy/DynamicProxyPass.cs @@ -37,8 +37,10 @@ namespace Obfuz.DynamicProxy return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method); } - protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList instructions, int instructionIndex, List obfuscatedInstructions) + protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList instructions, int instructionIndex, + List outputInstructions, List totalFinalInstructions) { + return false; switch (inst.OpCode.Code) { case Code.Call: @@ -48,7 +50,7 @@ namespace Obfuz.DynamicProxy { return false; } - _dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, obfuscatedInstructions); + _dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, outputInstructions); return true; } case Code.Callvirt: @@ -62,7 +64,7 @@ namespace Obfuz.DynamicProxy { return false; } - _dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, obfuscatedInstructions); + _dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, outputInstructions); return true; } default: return false; diff --git a/Editor/Emit/DynamicProxyMethodAllocator.cs b/Editor/Emit/DynamicProxyMethodAllocator.cs index 60bf307..4e4de17 100644 --- a/Editor/Emit/DynamicProxyMethodAllocator.cs +++ b/Editor/Emit/DynamicProxyMethodAllocator.cs @@ -27,7 +27,7 @@ namespace Obfuz.Emit public DynamicProxyMethodData Allocate(IMethod method) { - return null; + return default; } public void Done() diff --git a/Editor/ExprObfuscation/ExprObfuscationPass.cs b/Editor/ExprObfuscation/ExprObfuscationPass.cs index e7fada4..c304fb9 100644 --- a/Editor/ExprObfuscation/ExprObfuscationPass.cs +++ b/Editor/ExprObfuscation/ExprObfuscationPass.cs @@ -1,4 +1,6 @@ -using System; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,12 +8,9 @@ using System.Threading.Tasks; namespace Obfuz.ExprObfuscation { - public class ExprObfuscationPass : ObfuscationPassBase + public class ExprObfuscationPass : MethodBodyObfuscationPassBase { - public override void Process(ObfuscatorContext ctx) - { - } public override void Start(ObfuscatorContext ctx) { @@ -22,5 +21,15 @@ namespace Obfuz.ExprObfuscation { } + + protected override bool NeedObfuscateMethod(MethodDef method) + { + return false; + } + + protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, List outputInstructions, List totalFinalInstructions) + { + return false; + } } } diff --git a/Editor/MethodBodyObfuscationPassBase.cs b/Editor/MethodBodyObfuscationPassBase.cs index ddbd7ed..ac72345 100644 --- a/Editor/MethodBodyObfuscationPassBase.cs +++ b/Editor/MethodBodyObfuscationPassBase.cs @@ -35,7 +35,8 @@ namespace Obfuz } - protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, List outputInstructions); + protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, + List outputInstructions, List totalFinalInstructions); private void ObfuscateData(MethodDef method) { @@ -45,18 +46,23 @@ namespace Obfuz for (int i = 0; i < instructions.Count; i++) { Instruction inst = instructions[i]; - totalFinalInstructions.Add(inst); - if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions)) + outputInstructions.Clear(); + if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions, totalFinalInstructions)) { // current instruction may be the target of control flow instruction, so we can't remove it directly. // we replace it with nop now, then remove it in CleanUpInstructionPass inst.OpCode = outputInstructions[0].OpCode; inst.Operand = outputInstructions[0].Operand; + totalFinalInstructions.Add(inst); for (int k = 1; k < outputInstructions.Count; k++) { totalFinalInstructions.Add(outputInstructions[k]); } } + else + { + totalFinalInstructions.Add(inst); + } } instructions.Clear(); diff --git a/Editor/Virtualization/DataVirtualizationPass.cs b/Editor/Virtualization/DataVirtualizationPass.cs index afa654b..e6c65e0 100644 --- a/Editor/Virtualization/DataVirtualizationPass.cs +++ b/Editor/Virtualization/DataVirtualizationPass.cs @@ -11,7 +11,7 @@ using UnityEngine.Assertions; namespace Obfuz.Virtualization { - public class DataVirtualizationPass : ObfuscationPassBase + public class DataVirtualizationPass : MethodBodyObfuscationPassBase { private IDataObfuscationPolicy _dataObfuscatorPolicy; private IDataObfuscator _dataObfuscator; @@ -27,159 +27,113 @@ namespace Obfuz.Virtualization _dataObfuscator.Stop(); } - public override void Process(ObfuscatorContext ctx) + protected override bool NeedObfuscateMethod(MethodDef method) { - foreach (var ass in ctx.assemblies) - { - // ToArray to avoid modify list exception - foreach (TypeDef type in ass.module.GetTypes().ToArray()) - { - if (type.Name.StartsWith("$Obfuz$")) - { - continue; - } - // ToArray to avoid modify list exception - foreach (MethodDef method in type.Methods.ToArray()) - { - if (!method.HasBody || method.Name.StartsWith("$Obfuz$") || !_dataObfuscatorPolicy.NeedObfuscateMethod(method)) - { - continue; - } - // TODO if isGeneratedBy Obfuscator, continue - ObfuscateData(method); - } - } - } + return _dataObfuscatorPolicy.NeedObfuscateMethod(method); } - private void ObfuscateData(MethodDef method) + protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList instructions, int instructionIndex, + List outputInstructions, List totalFinalInstructions) { - IList instructions = method.Body.Instructions; - var obfuscatedInstructions = new List(); - var resultInstructions = new List(); - for (int i = 0; i < instructions.Count; i++) + switch (inst.OpCode.OperandType) { - Instruction inst = instructions[i]; - bool obfuscated = false; - switch (inst.OpCode.OperandType) + case OperandType.InlineI: + case OperandType.InlineI8: + case OperandType.ShortInlineI: + case OperandType.ShortInlineR: + case OperandType.InlineR: { - case OperandType.InlineI: - case OperandType.InlineI8: - case OperandType.ShortInlineI: - case OperandType.ShortInlineR: - case OperandType.InlineR: + object operand = inst.Operand; + if (operand is int) { - obfuscatedInstructions.Clear(); - object operand = inst.Operand; - if (operand is int) + int value = (int)operand; + if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) { - int value = (int)operand; - if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) - { - _dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions); - obfuscated = true; - } + _dataObfuscator.ObfuscateInt(method, value, outputInstructions); + return true; } - else if (operand is sbyte) - { - int value = (sbyte)operand; - if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) - { - _dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions); - obfuscated = true; - } - } - else if (operand is byte) - { - int value = (byte)operand; - if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) - { - _dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions); - obfuscated = true; - } - } - else if (operand is long) - { - long value = (long)operand; - if (_dataObfuscatorPolicy.NeedObfuscateLong(method, value)) - { - _dataObfuscator.ObfuscateLong(method, value, obfuscatedInstructions); - obfuscated = true; - } - } - else if (operand is float) - { - float value = (float)operand; - if (_dataObfuscatorPolicy.NeedObfuscateFloat(method, value)) - { - _dataObfuscator.ObfuscateFloat(method, value, obfuscatedInstructions); - obfuscated = true; - } - } - else if (operand is double) - { - double value = (double)operand; - if (_dataObfuscatorPolicy.NeedObfuscateDouble(method, value)) - { - _dataObfuscator.ObfuscateDouble(method, value, obfuscatedInstructions); - obfuscated = true; - } - } - break; } - case OperandType.InlineString: + else if (operand is sbyte) { - obfuscatedInstructions.Clear(); - //RuntimeHelpers.InitializeArray - string value = (string)inst.Operand; - if (_dataObfuscatorPolicy.NeedObfuscateString(method, value)) + int value = (sbyte)operand; + if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) { - _dataObfuscator.ObfuscateString(method, value, obfuscatedInstructions); - obfuscated = true; + _dataObfuscator.ObfuscateInt(method, value, outputInstructions); + return true; } - break; } - case OperandType.InlineMethod: + else if (operand is byte) { - if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") + int value = (byte)operand; + if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) { - 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; - } - } + _dataObfuscator.ObfuscateInt(method, value, outputInstructions); + return true; } - break; } + else if (operand is long) + { + long value = (long)operand; + if (_dataObfuscatorPolicy.NeedObfuscateLong(method, value)) + { + _dataObfuscator.ObfuscateLong(method, value, outputInstructions); + return true; + } + } + else if (operand is float) + { + float value = (float)operand; + if (_dataObfuscatorPolicy.NeedObfuscateFloat(method, value)) + { + _dataObfuscator.ObfuscateFloat(method, value, outputInstructions); + return true; + } + } + else if (operand is double) + { + double value = (double)operand; + if (_dataObfuscatorPolicy.NeedObfuscateDouble(method, value)) + { + _dataObfuscator.ObfuscateDouble(method, value, outputInstructions); + return true; + } + } + return false; } - resultInstructions.Add(inst); - if (obfuscated) + case OperandType.InlineString: { - // current instruction may be the target of control flow instruction, so we can't remove it directly. - // we replace it with nop now, then remove it in CleanUpInstructionPass - inst.OpCode = obfuscatedInstructions[0].OpCode; - inst.Operand = obfuscatedInstructions[0].Operand; - for (int k = 1; k < obfuscatedInstructions.Count; k++) + //RuntimeHelpers.InitializeArray + string value = (string)inst.Operand; + if (_dataObfuscatorPolicy.NeedObfuscateString(method, value)) { - resultInstructions.Add(obfuscatedInstructions[k]); + _dataObfuscator.ObfuscateString(method, value, outputInstructions); + return true; } + return false; } - } - - instructions.Clear(); - foreach (var obInst in resultInstructions) - { - instructions.Add(obInst); + case OperandType.InlineMethod: + { + if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") + { + Instruction prevInst = instructions[instructionIndex - 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, totalFinalInstructions[totalFinalInstructions.Count - 1].OpCode.Code); + totalFinalInstructions.RemoveAt(totalFinalInstructions.Count - 1); + _dataObfuscator.ObfuscateBytes(method, data, outputInstructions); + return true; + } + } + } + return false; + } + default: return false; } } }