diff --git a/Editor/DynamicProxy/ConfigDynamicProxyPolicy.cs b/Editor/DynamicProxy/ConfigDynamicProxyPolicy.cs new file mode 100644 index 0000000..caec8db --- /dev/null +++ b/Editor/DynamicProxy/ConfigDynamicProxyPolicy.cs @@ -0,0 +1,22 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.DynamicProxy +{ + public class ConfigDynamicProxyPolicy : DynamicProxyPolicyBase + { + public override bool NeedDynamicProxyCallInMethod(MethodDef method) + { + return true; + } + + public override bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir) + { + return true; + } + } +} diff --git a/Editor/DynamicProxy/DefaultDynamicProxyObfuscator.cs b/Editor/DynamicProxy/DefaultDynamicProxyObfuscator.cs new file mode 100644 index 0000000..b1338d4 --- /dev/null +++ b/Editor/DynamicProxy/DefaultDynamicProxyObfuscator.cs @@ -0,0 +1,14 @@ +using dnlib.DotNet.Emit; +using dnlib.DotNet; +using System.Collections.Generic; + +namespace Obfuz.DynamicProxy +{ + public class DefaultDynamicProxyObfuscator : DynamicProxyObfuscatorBase + { + public override void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions) + { + // Default implementation does nothing + } + } +} diff --git a/Editor/DynamicProxy/DynamicProxyObfuscatorBase.cs b/Editor/DynamicProxy/DynamicProxyObfuscatorBase.cs new file mode 100644 index 0000000..827abcb --- /dev/null +++ b/Editor/DynamicProxy/DynamicProxyObfuscatorBase.cs @@ -0,0 +1,11 @@ +using dnlib.DotNet.Emit; +using dnlib.DotNet; +using System.Collections.Generic; + +namespace Obfuz.DynamicProxy +{ + public abstract class DynamicProxyObfuscatorBase : IDynamicProxyObfuscator + { + public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions); + } +} diff --git a/Editor/DynamicProxy/DynamicProxyPass.cs b/Editor/DynamicProxy/DynamicProxyPass.cs new file mode 100644 index 0000000..d225da1 --- /dev/null +++ b/Editor/DynamicProxy/DynamicProxyPass.cs @@ -0,0 +1,72 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using Obfuz.Virtualization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using UnityEngine.Assertions; + +namespace Obfuz.DynamicProxy +{ + public class DynamicProxyPass : MethodBodyObfuscationPassBase + { + private readonly IDynamicProxyPolicy _dynamicProxyPolicy; + private readonly IDynamicProxyObfuscator _dynamicProxyObfuscator; + + public DynamicProxyPass() + { + _dynamicProxyPolicy = new ConfigDynamicProxyPolicy(); + _dynamicProxyObfuscator = new DefaultDynamicProxyObfuscator(); + } + + public override void Stop(ObfuscatorContext ctx) + { + + } + + public override void Start(ObfuscatorContext ctx) + { + + } + + protected override bool NeedObfuscateMethod(MethodDef method) + { + return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method); + } + + protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList instructions, int instructionIndex, List obfuscatedInstructions) + { + switch (inst.OpCode.Code) + { + case Code.Call: + { + IMethod calledMethod = (IMethod)inst.Operand; + if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, false)) + { + return false; + } + _dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, obfuscatedInstructions); + return true; + } + case Code.Callvirt: + { + if (instructionIndex > 0 && instructions[instructionIndex - 1].OpCode.Code == Code.Constrained) + { + return false; + } + IMethod calledMethod = (IMethod)inst.Operand; + if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, true)) + { + return false; + } + _dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, obfuscatedInstructions); + return true; + } + default: return false; + } + } + } +} diff --git a/Editor/DynamicProxy/DynamicProxyPolicyBase.cs b/Editor/DynamicProxy/DynamicProxyPolicyBase.cs new file mode 100644 index 0000000..8718fe1 --- /dev/null +++ b/Editor/DynamicProxy/DynamicProxyPolicyBase.cs @@ -0,0 +1,11 @@ +using dnlib.DotNet; + +namespace Obfuz.DynamicProxy +{ + public abstract class DynamicProxyPolicyBase : IDynamicProxyPolicy + { + public abstract bool NeedDynamicProxyCallInMethod(MethodDef method); + + public abstract bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir); + } +} diff --git a/Editor/DynamicProxy/IDynamicProxyObfuscator.cs b/Editor/DynamicProxy/IDynamicProxyObfuscator.cs new file mode 100644 index 0000000..14e1fbc --- /dev/null +++ b/Editor/DynamicProxy/IDynamicProxyObfuscator.cs @@ -0,0 +1,15 @@ +using dnlib.DotNet.Emit; +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.DynamicProxy +{ + public interface IDynamicProxyObfuscator + { + void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions); + } +} diff --git a/Editor/DynamicProxy/IDynamicProxyPolicy.cs b/Editor/DynamicProxy/IDynamicProxyPolicy.cs new file mode 100644 index 0000000..2154c6b --- /dev/null +++ b/Editor/DynamicProxy/IDynamicProxyPolicy.cs @@ -0,0 +1,16 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.DynamicProxy +{ + public interface IDynamicProxyPolicy + { + bool NeedDynamicProxyCallInMethod(MethodDef method); + + bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir); + } +} diff --git a/Editor/Emit/DynamicProxyMethodAllocator.cs b/Editor/Emit/DynamicProxyMethodAllocator.cs new file mode 100644 index 0000000..60bf307 --- /dev/null +++ b/Editor/Emit/DynamicProxyMethodAllocator.cs @@ -0,0 +1,69 @@ +using dnlib.DotNet; +using Obfuz.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.Emit +{ + public struct DynamicProxyMethodData + { + public MethodDef proxyMethod; + public int methodId; + } + + class ModuleDynamicProxyMethodAllocator + { + private readonly ModuleDef _module; + private readonly IRandom _random; + + public ModuleDynamicProxyMethodAllocator(ModuleDef module, IRandom random) + { + _module = module; + _random = random; + } + + public DynamicProxyMethodData Allocate(IMethod method) + { + return null; + } + + public void Done() + { + + } + } + + public class DynamicProxyMethodAllocator + { + private readonly IRandom _random; + + private readonly Dictionary _moduleAllocators = new Dictionary(); + + public DynamicProxyMethodAllocator(IRandom random) + { + _random = random; + } + + public DynamicProxyMethodData Allocate(ModuleDef mod, IMethod method) + { + if (!_moduleAllocators.TryGetValue(mod, out var allocator)) + { + allocator = new ModuleDynamicProxyMethodAllocator(mod, _random); + _moduleAllocators.Add(mod, allocator); + } + return allocator.Allocate(method); + } + + public void Done() + { + foreach (var allocator in _moduleAllocators.Values) + { + allocator.Done(); + } + _moduleAllocators.Clear(); + } + } +} diff --git a/Editor/ExprObfuscation/ExprObfuscationPass.cs b/Editor/ExprObfuscation/ExprObfuscationPass.cs new file mode 100644 index 0000000..e7fada4 --- /dev/null +++ b/Editor/ExprObfuscation/ExprObfuscationPass.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.ExprObfuscation +{ + public class ExprObfuscationPass : ObfuscationPassBase + { + public override void Process(ObfuscatorContext ctx) + { + + } + + public override void Start(ObfuscatorContext ctx) + { + + } + + public override void Stop(ObfuscatorContext ctx) + { + + } + } +} diff --git a/Editor/MethodBodyObfuscationPassBase.cs b/Editor/MethodBodyObfuscationPassBase.cs new file mode 100644 index 0000000..ddbd7ed --- /dev/null +++ b/Editor/MethodBodyObfuscationPassBase.cs @@ -0,0 +1,69 @@ +using dnlib.DotNet.Emit; +using dnlib.DotNet; +using System.Collections.Generic; +using System.Linq; + +namespace Obfuz +{ + public abstract class MethodBodyObfuscationPassBase : ObfuscationPassBase + { + protected abstract bool NeedObfuscateMethod(MethodDef method); + + public override void Process(ObfuscatorContext ctx) + { + 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$") || !NeedObfuscateMethod(method)) + { + continue; + } + // TODO if isGeneratedBy Obfuscator, continue + ObfuscateData(method); + } + } + } + } + + + protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList instructions, int instructionIndex, List outputInstructions); + + private void ObfuscateData(MethodDef method) + { + IList instructions = method.Body.Instructions; + var outputInstructions = new List(); + var totalFinalInstructions = new List(); + for (int i = 0; i < instructions.Count; i++) + { + Instruction inst = instructions[i]; + totalFinalInstructions.Add(inst); + if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions)) + { + // 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; + for (int k = 1; k < outputInstructions.Count; k++) + { + totalFinalInstructions.Add(outputInstructions[k]); + } + } + } + + instructions.Clear(); + foreach (var obInst in totalFinalInstructions) + { + instructions.Add(obInst); + } + } + } +} diff --git a/Editor/ObfuscationPassBase.cs b/Editor/ObfuscationPassBase.cs index 78b60b9..e81c897 100644 --- a/Editor/ObfuscationPassBase.cs +++ b/Editor/ObfuscationPassBase.cs @@ -1,4 +1,6 @@ -namespace Obfuz +using Obfuz.Virtualization; + +namespace Obfuz { public abstract class ObfuscationPassBase : IObfuscationPass { diff --git a/Editor/Obfuscator.cs b/Editor/Obfuscator.cs index e3d8c20..a88e3ac 100644 --- a/Editor/Obfuscator.cs +++ b/Editor/Obfuscator.cs @@ -1,4 +1,6 @@ using dnlib.DotNet; +using Obfuz.DynamicProxy; +using Obfuz.ExprObfuscation; using Obfuz.Rename; using Obfuz.Virtualization; using System; @@ -44,6 +46,8 @@ namespace Obfuz _obfuscationAssemblyNames = options.obfuscationAssemblyNames; _assemblyCache = new AssemblyCache(new PathAssemblyResolver(options.assemblySearchDirs.ToArray())); + _pipeline.AddPass(new DynamicProxyPass()); + _pipeline.AddPass(new ExprObfuscationPass()); _pipeline.AddPass(new DataVirtualizationPass()); _pipeline.AddPass(new RenameSymbolPass()); _pipeline.AddPass(new CleanUpInstructionPass());