From e10a42f8dd69934480ca3b4eb9535960535aa625 Mon Sep 17 00:00:00 2001 From: walon Date: Tue, 22 Apr 2025 08:13:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0int=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=B7=B7=E6=B7=86=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/{Virtualization => Utils}/IRandom.cs | 4 +- Editor/Utils/RandomWithKey.cs | 58 +++++++++++++++++++ .../ConfigDataObfuscationPolicy.cs | 32 +++++++++- .../Virtualization/CreateExpressionOptions.cs | 4 +- Editor/Virtualization/DataNodeCreatorBase.cs | 7 +++ .../Virtualization/DataNodes/DataNodeBase.cs | 12 ++-- .../Virtualization/DataVirtualizationPass.cs | 13 +++-- .../Virtualization/DefaultDataObfuscator.cs | 28 +++++---- .../Virtualization/Functions/FunctionBase.cs | 6 +- .../Functions/Int32FunctionAdd.cs | 2 +- .../Functions/Int32FunctionXor.cs | 25 ++++++++ Editor/Virtualization/IDataNode.cs | 2 - Editor/Virtualization/IFunction.cs | 2 +- .../Virtualization/RandomDataNodeCreator.cs | 50 ++++++++++++++++ 14 files changed, 211 insertions(+), 34 deletions(-) rename Editor/{Virtualization => Utils}/IRandom.cs (70%) create mode 100644 Editor/Utils/RandomWithKey.cs create mode 100644 Editor/Virtualization/DataNodeCreatorBase.cs create mode 100644 Editor/Virtualization/Functions/Int32FunctionXor.cs create mode 100644 Editor/Virtualization/RandomDataNodeCreator.cs diff --git a/Editor/Virtualization/IRandom.cs b/Editor/Utils/IRandom.cs similarity index 70% rename from Editor/Virtualization/IRandom.cs rename to Editor/Utils/IRandom.cs index e50e1bd..b3f8730 100644 --- a/Editor/Virtualization/IRandom.cs +++ b/Editor/Utils/IRandom.cs @@ -1,9 +1,11 @@ -namespace Obfuz.Virtualization +namespace Obfuz.Utils { public interface IRandom { int NextInt(int min, int max); int NextInt(int max); + + int NextInt(); } } diff --git a/Editor/Utils/RandomWithKey.cs b/Editor/Utils/RandomWithKey.cs new file mode 100644 index 0000000..292eb36 --- /dev/null +++ b/Editor/Utils/RandomWithKey.cs @@ -0,0 +1,58 @@ +using Obfuz.Virtualization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.Utils +{ + public class RandomWithKey : IRandom + { + private readonly byte[] _key; + + private readonly Random _random; + + private int _nextIndex; + + public RandomWithKey(byte[] key, int seed) + { + _key = key; + // TODO use key and seed to generate a random number + _random = new Random(GenerateSeed(key, seed)); + } + + private int GenerateSeed(byte[] key, int seed) + { + foreach (var b in key) + { + seed = seed * 31 + b; + } + return seed; + } + + public int NextInt(int min, int max) + { + return min + NextInt(max - min); + } + + public int NextInt(int max) + { + return (int)((uint)NextInt() % (uint)max); + } + + private int GetNextKeyByte() + { + if (_nextIndex >= _key.Length) + { + _nextIndex = 0; + } + return _key[_nextIndex++]; + } + + public int NextInt() + { + return _random.Next() ^ GetNextKeyByte(); + } + } +} diff --git a/Editor/Virtualization/ConfigDataObfuscationPolicy.cs b/Editor/Virtualization/ConfigDataObfuscationPolicy.cs index c817926..2876c68 100644 --- a/Editor/Virtualization/ConfigDataObfuscationPolicy.cs +++ b/Editor/Virtualization/ConfigDataObfuscationPolicy.cs @@ -1,4 +1,5 @@ -using System; +using dnlib.DotNet; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,5 +9,34 @@ namespace Obfuz.Virtualization { public class ConfigDataObfuscationPolicy : DataObfuscationPolicyBase { + public override bool NeedObfuscateMethod(MethodDef method) + { + return true; + } + + public override bool NeedObfuscateInt(MethodDef method, int value) + { + return value > 10000; + } + + public override bool NeedObfuscateLong(MethodDef method, long value) + { + return value > 10000; + } + + public override bool NeedObfuscateFloat(MethodDef method, float value) + { + return true; + } + + public override bool NeedObfuscateDouble(MethodDef method, double value) + { + return true; + } + + public override bool NeedObfuscateString(MethodDef method, string value) + { + return true; + } } } diff --git a/Editor/Virtualization/CreateExpressionOptions.cs b/Editor/Virtualization/CreateExpressionOptions.cs index 31930e1..117d710 100644 --- a/Editor/Virtualization/CreateExpressionOptions.cs +++ b/Editor/Virtualization/CreateExpressionOptions.cs @@ -1,4 +1,6 @@ -namespace Obfuz.Virtualization +using Obfuz.Utils; + +namespace Obfuz.Virtualization { public struct CreateExpressionOptions { diff --git a/Editor/Virtualization/DataNodeCreatorBase.cs b/Editor/Virtualization/DataNodeCreatorBase.cs new file mode 100644 index 0000000..063c190 --- /dev/null +++ b/Editor/Virtualization/DataNodeCreatorBase.cs @@ -0,0 +1,7 @@ +namespace Obfuz.Virtualization +{ + public abstract class DataNodeCreatorBase : IDataNodeCreator + { + public abstract IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options); + } +} diff --git a/Editor/Virtualization/DataNodes/DataNodeBase.cs b/Editor/Virtualization/DataNodes/DataNodeBase.cs index 6d37231..7b4d933 100644 --- a/Editor/Virtualization/DataNodes/DataNodeBase.cs +++ b/Editor/Virtualization/DataNodes/DataNodeBase.cs @@ -2,11 +2,9 @@ { public abstract class DataNodeBase : IDataNode { - public DataNodeType Type { get; protected set; } + public DataNodeType Type { get; set; } - public IDataNode Expr { get; protected set; } - - public abstract object Value { get; protected set; } + public abstract object Value { get; set; } public abstract void Compile(CompileContext ctx); } @@ -14,12 +12,12 @@ public abstract class DataNodeBase : DataNodeBase { - public T Value2 { get; protected set; } + public T Value2 { get; set; } public override object Value { get => Value2; - protected set => Value2 = (T)value; + set => Value2 = (T)value; } } @@ -31,7 +29,7 @@ public override object Value { get => _value; - protected set => _value = value; + set => _value = value; } } } diff --git a/Editor/Virtualization/DataVirtualizationPass.cs b/Editor/Virtualization/DataVirtualizationPass.cs index d977647..7973b95 100644 --- a/Editor/Virtualization/DataVirtualizationPass.cs +++ b/Editor/Virtualization/DataVirtualizationPass.cs @@ -34,7 +34,7 @@ namespace Obfuz.Virtualization { foreach (MethodDef method in type.Methods) { - if (!method.HasBody && !_dataObfuscatorPolicy.NeedObfuscateMethod(method)) + if (!method.HasBody || !_dataObfuscatorPolicy.NeedObfuscateMethod(method)) { continue; } @@ -50,7 +50,7 @@ namespace Obfuz.Virtualization IList instructions = method.Body.Instructions; var obfuscatedInstructions = new List(); var resultInstructions = new List(); - for (int i = 0; i < instructions.Count; ) + for (int i = 0; i < instructions.Count; i++) { Instruction inst = instructions[i]; bool obfuscated = false; @@ -130,10 +130,8 @@ namespace Obfuz.Virtualization } break; } - default: throw new NotSupportedException($"Unsupported operand type: {inst.OpCode.OperandType} for instruction: {inst}"); } resultInstructions.Add(inst); - i++; if (obfuscated) { // current instruction may be the target of control flow instruction, so we can't remove it directly. @@ -141,9 +139,14 @@ namespace Obfuz.Virtualization inst.OpCode = OpCodes.Nop; inst.Operand = null; resultInstructions.AddRange(obfuscatedInstructions); - i += obfuscatedInstructions.Count + 1; } } + + instructions.Clear(); + foreach (var obInst in obfuscatedInstructions) + { + instructions.Add(obInst); + } } } } diff --git a/Editor/Virtualization/DefaultDataObfuscator.cs b/Editor/Virtualization/DefaultDataObfuscator.cs index b4e7e9c..ea1e7f4 100644 --- a/Editor/Virtualization/DefaultDataObfuscator.cs +++ b/Editor/Virtualization/DefaultDataObfuscator.cs @@ -7,34 +7,38 @@ namespace Obfuz.Virtualization { public class DefaultDataObfuscator : IDataObfuscator { - public bool ObfuscateInt(MethodDef method, int value, List obfuscatedInstructions) + private readonly RandomDataNodeCreator _nodeCreator = new RandomDataNodeCreator(); + + public void ObfuscateInt(MethodDef method, int value, List obfuscatedInstructions) { - return false; + IDataNode node = _nodeCreator.CreateRandom(DataNodeType.Int32, value); + obfuscatedInstructions.Add(Instruction.CreateLdcI4(value)); } - public bool TryObfuscateLong(MethodDef method, long value, List obfuscatedInstructions) + public void ObfuscateLong(MethodDef method, long value, List obfuscatedInstructions) { - return false; + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, value)); } - public bool TryObfuscateFloat(MethodDef method, float value, List obfuscatedInstructions) + public void ObfuscateFloat(MethodDef method, float value, List obfuscatedInstructions) { - return false; + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_R4, value)); } - public bool TryObfuscateDouble(MethodDef method, double value, List obfuscatedInstructions) + public void ObfuscateDouble(MethodDef method, double value, List obfuscatedInstructions) { - return false; + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_R8, value)); } - public bool TryObfuscateBytes(MethodDef method, Array value, List obfuscatedInstructions) + public void ObfuscateBytes(MethodDef method, Array value, List obfuscatedInstructions) { - return false; + throw new NotSupportedException(); + //obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_I4, value.Length)); } - public bool TryObfuscateString(MethodDef method, string value, List obfuscatedInstructions) + public void ObfuscateString(MethodDef method, string value, List obfuscatedInstructions) { - return false; + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value)); } } } diff --git a/Editor/Virtualization/Functions/FunctionBase.cs b/Editor/Virtualization/Functions/FunctionBase.cs index a6585cb..c8becc8 100644 --- a/Editor/Virtualization/Functions/FunctionBase.cs +++ b/Editor/Virtualization/Functions/FunctionBase.cs @@ -11,10 +11,10 @@ namespace Obfuz.Virtualization public abstract void CreateArguments(DataNodeType type, object value, CreateExpressionOptions options, List args); - public ConstExpression CreateCallable(IDataNode result, CreateExpressionOptions options) + public ConstExpression CreateCallable(DataNodeType type, object value, CreateExpressionOptions options) { var args = new List(); - CreateArguments(result.Type, result.Value, options, args); + CreateArguments(type, value, options, args); options.depth += 1; var argNodes = new List(); @@ -24,7 +24,7 @@ namespace Obfuz.Virtualization argNodes.Add(argNode); } - return new ConstExpression(this, args.Select(a => options.expressionCreator.CreateRandom(a.type, a.value, options)).ToList(), new ConstValue(result.Type, result.Value)); + return new ConstExpression(this, args.Select(a => options.expressionCreator.CreateRandom(a.type, a.value, options)).ToList(), new ConstValue(type, value)); } } } diff --git a/Editor/Virtualization/Functions/Int32FunctionAdd.cs b/Editor/Virtualization/Functions/Int32FunctionAdd.cs index e7d85c9..dfc8c1c 100644 --- a/Editor/Virtualization/Functions/Int32FunctionAdd.cs +++ b/Editor/Virtualization/Functions/Int32FunctionAdd.cs @@ -16,7 +16,7 @@ namespace Obfuz.Virtualization.Functions { int value = (int)v; - int op1 = value >= 0 ? options.random.NextInt(value) : -options.random.NextInt(-value); + int op1 = options.random.NextInt(); int op2 = value - op1; args.Add(new ConstValue(DataNodeType.Int32, op1)); args.Add(new ConstValue(DataNodeType.Int32, op2)); diff --git a/Editor/Virtualization/Functions/Int32FunctionXor.cs b/Editor/Virtualization/Functions/Int32FunctionXor.cs new file mode 100644 index 0000000..3324d28 --- /dev/null +++ b/Editor/Virtualization/Functions/Int32FunctionXor.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static UnityEngine.Networking.UnityWebRequest; + +namespace Obfuz.Virtualization.Functions +{ + public class Int32FunctionXor : Int32FunctionBase + { + public override DataNodeType ReturnType => DataNodeType.Int32; + + public override void CreateArguments(DataNodeType type, object v, CreateExpressionOptions options, List args) + { + int value = (int)v; + + int op1 = options.random.NextInt(); + int op2 = value ^ op1; + args.Add(new ConstValue(DataNodeType.Int32, op1)); + args.Add(new ConstValue(DataNodeType.Int32, op2)); + } + } +} diff --git a/Editor/Virtualization/IDataNode.cs b/Editor/Virtualization/IDataNode.cs index aa1024a..386d386 100644 --- a/Editor/Virtualization/IDataNode.cs +++ b/Editor/Virtualization/IDataNode.cs @@ -13,8 +13,6 @@ namespace Obfuz.Virtualization object Value { get; } - IDataNode Expr { get; } - void Compile(CompileContext ctx); } } diff --git a/Editor/Virtualization/IFunction.cs b/Editor/Virtualization/IFunction.cs index a71eeb6..96f7a44 100644 --- a/Editor/Virtualization/IFunction.cs +++ b/Editor/Virtualization/IFunction.cs @@ -4,6 +4,6 @@ { DataNodeType ReturnType { get; } - ConstExpression CreateCallable(IDataNode result, CreateExpressionOptions options); + ConstExpression CreateCallable(DataNodeType type, object value, CreateExpressionOptions options); } } diff --git a/Editor/Virtualization/RandomDataNodeCreator.cs b/Editor/Virtualization/RandomDataNodeCreator.cs new file mode 100644 index 0000000..115c0d1 --- /dev/null +++ b/Editor/Virtualization/RandomDataNodeCreator.cs @@ -0,0 +1,50 @@ + +using Obfuz.Utils; +using Obfuz.Virtualization.Functions; +using System.Collections.Generic; + +namespace Obfuz.Virtualization +{ + public class RandomDataNodeCreator : DataNodeCreatorBase + { + private readonly Dictionary> _functions = new Dictionary>(); + + private readonly IRandom _random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5); + + public RandomDataNodeCreator() + { + var int32Funcs = new List() + { + new Int32FunctionAdd(), + new Int32FunctionXor(), + }; + _functions.Add(DataNodeType.Int32, int32Funcs); + } + + public override IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options) + { + if (!_functions.TryGetValue(type, out var funcs)) + { + throw new System.Exception($"No functions available for type {type}"); + } + if (options.depth >= 2) + { + return new ConstDataNode() { Type = type, Value = value }; + } + var func = funcs[options.random.NextInt(funcs.Count)]; + ++options.depth; + return func.CreateCallable(type, value, options); + } + + public IDataNode CreateRandom(DataNodeType type, object value) + { + var options = new CreateExpressionOptions + { + depth = 0, + random = _random, + expressionCreator = this, + }; + return CreateRandom(type, value, options); + } + } +}