diff --git a/Editor/CleanUpInstructionPass.cs b/Editor/CleanUpInstructionPass.cs new file mode 100644 index 0000000..8308dac --- /dev/null +++ b/Editor/CleanUpInstructionPass.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz +{ + public class CleanUpInstructionPass : ObfuscationPassBase + { + public override void Process(ObfuscatorContext ctx) + { + // TODO remove all nop instructions + } + + public override void Start(ObfuscatorContext ctx) + { + + } + + public override void Stop(ObfuscatorContext ctx) + { + + } + } +} diff --git a/Editor/ObfuscationPassBase.cs b/Editor/ObfuscationPassBase.cs index a308db9..78b60b9 100644 --- a/Editor/ObfuscationPassBase.cs +++ b/Editor/ObfuscationPassBase.cs @@ -2,13 +2,10 @@ { public abstract class ObfuscationPassBase : IObfuscationPass { - public virtual void Start(ObfuscatorContext ctx) - { - } + public abstract void Start(ObfuscatorContext ctx); + + public abstract void Stop(ObfuscatorContext ctx); - public virtual void Stop(ObfuscatorContext ctx) - { - } public abstract void Process(ObfuscatorContext ctx); } } diff --git a/Editor/Obfuscator.cs b/Editor/Obfuscator.cs index d779bec..e3d8c20 100644 --- a/Editor/Obfuscator.cs +++ b/Editor/Obfuscator.cs @@ -46,6 +46,7 @@ namespace Obfuz _pipeline.AddPass(new DataVirtualizationPass()); _pipeline.AddPass(new RenameSymbolPass()); + _pipeline.AddPass(new CleanUpInstructionPass()); _ctx = new ObfuscatorContext diff --git a/Editor/ObfuscateRuleConfig.cs b/Editor/Rename/ObfuscateRuleConfig.cs similarity index 100% rename from Editor/ObfuscateRuleConfig.cs rename to Editor/Rename/ObfuscateRuleConfig.cs diff --git a/Editor/AssemblyCache.cs b/Editor/Utils/AssemblyCache.cs similarity index 100% rename from Editor/AssemblyCache.cs rename to Editor/Utils/AssemblyCache.cs diff --git a/Editor/AssemblyResolverBase.cs b/Editor/Utils/AssemblyResolverBase.cs similarity index 100% rename from Editor/AssemblyResolverBase.cs rename to Editor/Utils/AssemblyResolverBase.cs diff --git a/Editor/CollectionExtensions.cs b/Editor/Utils/CollectionExtensions.cs similarity index 100% rename from Editor/CollectionExtensions.cs rename to Editor/Utils/CollectionExtensions.cs diff --git a/Editor/FileUtil.cs b/Editor/Utils/FileUtil.cs similarity index 100% rename from Editor/FileUtil.cs rename to Editor/Utils/FileUtil.cs diff --git a/Editor/IAssemblyResolver.cs b/Editor/Utils/IAssemblyResolver.cs similarity index 100% rename from Editor/IAssemblyResolver.cs rename to Editor/Utils/IAssemblyResolver.cs diff --git a/Editor/MetaUtil.cs b/Editor/Utils/MetaUtil.cs similarity index 100% rename from Editor/MetaUtil.cs rename to Editor/Utils/MetaUtil.cs diff --git a/Editor/NameMatcher.cs b/Editor/Utils/NameMatcher.cs similarity index 100% rename from Editor/NameMatcher.cs rename to Editor/Utils/NameMatcher.cs diff --git a/Editor/PathAssemblyResolver.cs b/Editor/Utils/PathAssemblyResolver.cs similarity index 100% rename from Editor/PathAssemblyResolver.cs rename to Editor/Utils/PathAssemblyResolver.cs diff --git a/Editor/TypeSigUtil.cs b/Editor/Utils/TypeSigUtil.cs similarity index 100% rename from Editor/TypeSigUtil.cs rename to Editor/Utils/TypeSigUtil.cs diff --git a/Editor/Virtualization/ConfigDataObfuscationPolicy.cs b/Editor/Virtualization/ConfigDataObfuscationPolicy.cs new file mode 100644 index 0000000..c817926 --- /dev/null +++ b/Editor/Virtualization/ConfigDataObfuscationPolicy.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.Virtualization +{ + public class ConfigDataObfuscationPolicy : DataObfuscationPolicyBase + { + } +} diff --git a/Editor/Virtualization/DataObfuscationPolicyBase.cs b/Editor/Virtualization/DataObfuscationPolicyBase.cs new file mode 100644 index 0000000..a47e893 --- /dev/null +++ b/Editor/Virtualization/DataObfuscationPolicyBase.cs @@ -0,0 +1,37 @@ +using dnlib.DotNet; + +namespace Obfuz.Virtualization +{ + public abstract class DataObfuscationPolicyBase : IDataObfuscationPolicy + { + public virtual bool NeedObfuscateMethod(MethodDef method) + { + return true; + } + + public virtual bool NeedObfuscateInt(MethodDef method, int value) + { + return true; + } + + public virtual bool NeedObfuscateLong(MethodDef method, long value) + { + return true; + } + + public virtual bool NeedObfuscateFloat(MethodDef method, float value) + { + return true; + } + + public virtual bool NeedObfuscateDouble(MethodDef method, double value) + { + return true; + } + + public virtual bool NeedObfuscateString(MethodDef method, string value) + { + return true; + } + } +} diff --git a/Editor/Virtualization/DataVirtualizationPass.cs b/Editor/Virtualization/DataVirtualizationPass.cs index 36b6f18..d977647 100644 --- a/Editor/Virtualization/DataVirtualizationPass.cs +++ b/Editor/Virtualization/DataVirtualizationPass.cs @@ -1,16 +1,149 @@ -using System; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace Obfuz.Virtualization { + public class DataVirtualizationPass : ObfuscationPassBase { - public override void Process(ObfuscatorContext ctx) + private IDataObfuscationPolicy _dataObfuscatorPolicy; + private IDataObfuscator _dataObfuscator; + + public override void Start(ObfuscatorContext ctx) + { + _dataObfuscatorPolicy = new ConfigDataObfuscationPolicy(); + _dataObfuscator = new DefaultDataObfuscator(); + } + + public override void Stop(ObfuscatorContext ctx) { } + + public override void Process(ObfuscatorContext ctx) + { + foreach (var ass in ctx.assemblies) + { + foreach (TypeDef type in ass.module.GetTypes()) + { + foreach (MethodDef method in type.Methods) + { + if (!method.HasBody && !_dataObfuscatorPolicy.NeedObfuscateMethod(method)) + { + continue; + } + // TODO if isGeneratedBy Obfuscator, continue + ObfuscateData(method); + } + } + } + } + + private void ObfuscateData(MethodDef method) + { + IList instructions = method.Body.Instructions; + var obfuscatedInstructions = new List(); + var resultInstructions = new List(); + for (int i = 0; i < instructions.Count; ) + { + Instruction inst = instructions[i]; + bool obfuscated = false; + switch (inst.OpCode.OperandType) + { + case OperandType.InlineI: + case OperandType.ShortInlineI: + case OperandType.ShortInlineR: + case OperandType.InlineR: + { + obfuscatedInstructions.Clear(); + object operand = inst.Operand; + if (operand is int) + { + int value = (int)operand; + if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) + { + _dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions); + obfuscated = 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: + { + //RuntimeHelpers.InitializeArray + string value = (string)inst.Operand; + if (_dataObfuscatorPolicy.NeedObfuscateString(method, value)) + { + _dataObfuscator.ObfuscateString(method, value, obfuscatedInstructions); + obfuscated = true; + } + 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. + // we replace it with nop now, then remove it in CleanUpInstructionPass + inst.OpCode = OpCodes.Nop; + inst.Operand = null; + resultInstructions.AddRange(obfuscatedInstructions); + i += obfuscatedInstructions.Count + 1; + } + } + } } } diff --git a/Editor/Virtualization/DefaultDataObfuscator.cs b/Editor/Virtualization/DefaultDataObfuscator.cs new file mode 100644 index 0000000..b4e7e9c --- /dev/null +++ b/Editor/Virtualization/DefaultDataObfuscator.cs @@ -0,0 +1,40 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; +using System.Collections.Generic; + +namespace Obfuz.Virtualization +{ + public class DefaultDataObfuscator : IDataObfuscator + { + public bool ObfuscateInt(MethodDef method, int value, List obfuscatedInstructions) + { + return false; + } + + public bool TryObfuscateLong(MethodDef method, long value, List obfuscatedInstructions) + { + return false; + } + + public bool TryObfuscateFloat(MethodDef method, float value, List obfuscatedInstructions) + { + return false; + } + + public bool TryObfuscateDouble(MethodDef method, double value, List obfuscatedInstructions) + { + return false; + } + + public bool TryObfuscateBytes(MethodDef method, Array value, List obfuscatedInstructions) + { + return false; + } + + public bool TryObfuscateString(MethodDef method, string value, List obfuscatedInstructions) + { + return false; + } + } +} diff --git a/Editor/Virtualization/IDataObfuscationPolicy.cs b/Editor/Virtualization/IDataObfuscationPolicy.cs new file mode 100644 index 0000000..6275903 --- /dev/null +++ b/Editor/Virtualization/IDataObfuscationPolicy.cs @@ -0,0 +1,24 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz.Virtualization +{ + public interface IDataObfuscationPolicy + { + bool NeedObfuscateMethod(MethodDef method); + + bool NeedObfuscateInt(MethodDef method, int value); + + bool NeedObfuscateLong(MethodDef method, long value); + + bool NeedObfuscateFloat(MethodDef method, float value); + + bool NeedObfuscateDouble(MethodDef method, double value); + + bool NeedObfuscateString(MethodDef method, string value); + } +} diff --git a/Editor/Virtualization/IDataObfuscator.cs b/Editor/Virtualization/IDataObfuscator.cs new file mode 100644 index 0000000..d2fc8f0 --- /dev/null +++ b/Editor/Virtualization/IDataObfuscator.cs @@ -0,0 +1,23 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; +using System.Collections.Generic; + +namespace Obfuz.Virtualization +{ + public interface IDataObfuscator + { + + void ObfuscateInt(MethodDef method, int value, List obfuscatedInstructions); + + void ObfuscateLong(MethodDef method, long value, List obfuscatedInstructions); + + void ObfuscateFloat(MethodDef method, float value, List obfuscatedInstructions); + + void ObfuscateDouble(MethodDef method, double value, List obfuscatedInstructions); + + void ObfuscateString(MethodDef method, string value, List obfuscatedInstructions); + + void ObfuscateBytes(MethodDef method, Array value, List obfuscatedInstructions); + } +}