diff --git a/Editor/Emit/MetadataImporter.cs b/Editor/Emit/MetadataImporter.cs new file mode 100644 index 0000000..b1ef16a --- /dev/null +++ b/Editor/Emit/MetadataImporter.cs @@ -0,0 +1,87 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine.Assertions; + +namespace Obfuz.Emit +{ + public class ModuleMetadataImporter + { + private readonly ModuleDef _module; + public ModuleMetadataImporter(ModuleDef module) + { + _module = module; + _module = module; + InitMetadatas(module); + } + + private static IMethod s_castIntAsFloat; + private static IMethod s_castLongAsDouble; + private static IMethod s_castFloatAsInt; + private static IMethod s_castDoubleAsLong; + + private void InitMetadatas(ModuleDef mod) + { + if (s_castFloatAsInt != null) + { + return; + } + var constUtilityType = typeof(ConstUtility); + + s_castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat")); + Assert.IsNotNull(s_castIntAsFloat, "CastIntAsFloat not found"); + s_castLongAsDouble = mod.Import(constUtilityType.GetMethod("CastLongAsDouble")); + Assert.IsNotNull(s_castLongAsDouble, "CastLongAsDouble not found"); + s_castFloatAsInt = mod.Import(constUtilityType.GetMethod("CastFloatAsInt")); + Assert.IsNotNull(s_castFloatAsInt, "CastFloatAsInt not found"); + s_castDoubleAsLong = mod.Import(constUtilityType.GetMethod("CastDoubleAsLong")); + Assert.IsNotNull(s_castDoubleAsLong, "CastDoubleAsLong not found"); + } + + public IMethod GetCastIntAsFloat() + { + return s_castIntAsFloat; + } + + public IMethod GetCastLongAsDouble() + { + return s_castLongAsDouble; + } + + public IMethod GetCastFloatAsInt() + { + return s_castFloatAsInt; + } + + public IMethod GetCastDoubleAsLong() + { + return s_castDoubleAsLong; + } + } + + public class MetadataImporter + { + + private readonly Dictionary _moduleMetadataImporters = new Dictionary(); + + public static MetadataImporter Instance { get; private set; } + + public static void Reset() + { + Instance = new MetadataImporter(); + } + + public ModuleMetadataImporter GetModuleMetadataImporter(ModuleDef module) + { + if (!_moduleMetadataImporters.TryGetValue(module, out var importer)) + { + importer = new ModuleMetadataImporter(module); + _moduleMetadataImporters[module] = importer; + } + return importer; + } + } +} diff --git a/Editor/Emit/VariableEncryption.cs b/Editor/Emit/VariableEncryption.cs new file mode 100644 index 0000000..7210ea2 --- /dev/null +++ b/Editor/Emit/VariableEncryption.cs @@ -0,0 +1,483 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using Obfuz.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine.Assertions; + +namespace Obfuz.Emit +{ + public class EncryptionCompileContext + { + public ModuleDef module; + } + + public interface IVariableTransformer + { + object Compute(object value); + + object ReverseCompute(object value); + + void EmitTransform(List output, EncryptionCompileContext ctx); + + void EmitRevertTransform(List output, EncryptionCompileContext ctx); + } + + public abstract class VariableTransformerBase : IVariableTransformer + { + public abstract object Compute(object value); + public abstract object ReverseCompute(object value); + public abstract void EmitRevertTransform(List output, EncryptionCompileContext ctx); + public abstract void EmitTransform(List output, EncryptionCompileContext ctx); + } + + public class AddVariableTransformer : VariableTransformerBase + { + private readonly DataNodeType _type; + private readonly object _addValue; + + public AddVariableTransformer(DataNodeType type, object addValue) + { + _type = type; + _addValue = addValue; + } + + public override object Compute(object value) + { + switch (_type) + { + case DataNodeType.Int32: + return (int)value + (int)_addValue; + case DataNodeType.Int64: + return (long)value + (long)_addValue; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public override object ReverseCompute(object value) + { + switch (_type) + { + case DataNodeType.Int32: + return (int)value - (int)_addValue; + case DataNodeType.Int64: + return (long)value - (long)_addValue; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public override void EmitTransform(List output, EncryptionCompileContext ctx) + { + switch (_type) + { + case DataNodeType.Int32: + output.Add(Instruction.Create(OpCodes.Ldc_I4, (int)_addValue)); + output.Add(Instruction.Create(OpCodes.Add)); + break; + case DataNodeType.Int64: + output.Add(Instruction.Create(OpCodes.Ldc_I8, (long)_addValue)); + output.Add(Instruction.Create(OpCodes.Add)); + break; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public override void EmitRevertTransform(List output, EncryptionCompileContext ctx) + { + switch (_type) + { + case DataNodeType.Int32: + output.Add(Instruction.Create(OpCodes.Ldc_I4, -(int)_addValue)); + output.Add(Instruction.Create(OpCodes.Add)); + break; + case DataNodeType.Int64: + output.Add(Instruction.Create(OpCodes.Ldc_I8, -(long)_addValue)); + output.Add(Instruction.Create(OpCodes.Add)); + break; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public static AddVariableTransformer Create(DataNodeType type, IRandom random) + { + switch (type) + { + case DataNodeType.Int32: return new AddVariableTransformer(type, random.NextInt()); + case DataNodeType.Int64: return new AddVariableTransformer(type, random.NextLong()); + default: + throw new NotSupportedException($"Unsupported type: {type}"); + } + } + } + + public class XorVariableTransformer : VariableTransformerBase + { + private readonly DataNodeType _type; + private readonly object _xorValue; + public XorVariableTransformer(DataNodeType type, object xorValue) + { + _type = type; + _xorValue = xorValue; + } + + public override object Compute(object value) + { + switch (_type) + { + case DataNodeType.Int32: + return (int)value ^ (int)_xorValue; + case DataNodeType.Int64: + return (long)value ^ (long)_xorValue; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public override object ReverseCompute(object value) + { + switch (_type) + { + case DataNodeType.Int32: + return (int)value ^ (int)_xorValue; + case DataNodeType.Int64: + return (long)value ^ (long)_xorValue; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public override void EmitTransform(List output, EncryptionCompileContext ctx) + { + switch (_type) + { + case DataNodeType.Int32: + output.Add(Instruction.Create(OpCodes.Ldc_I4, (int)_xorValue)); + output.Add(Instruction.Create(OpCodes.Xor)); + break; + case DataNodeType.Int64: + output.Add(Instruction.Create(OpCodes.Ldc_I8, (long)_xorValue)); + output.Add(Instruction.Create(OpCodes.Xor)); + break; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public override void EmitRevertTransform(List output, EncryptionCompileContext ctx) + { + switch (_type) + { + case DataNodeType.Int32: + output.Add(Instruction.Create(OpCodes.Ldc_I4, (int)_xorValue)); + output.Add(Instruction.Create(OpCodes.Xor)); + break; + case DataNodeType.Int64: + output.Add(Instruction.Create(OpCodes.Ldc_I8, (long)_xorValue)); + output.Add(Instruction.Create(OpCodes.Xor)); + break; + default: throw new NotSupportedException($"Unsupported type: {_type}"); + } + } + + public static XorVariableTransformer Create(DataNodeType type, IRandom random) + { + switch (type) + { + case DataNodeType.Int32: return new XorVariableTransformer(type, random.NextInt()); + case DataNodeType.Int64: return new XorVariableTransformer(type, random.NextLong()); + default: + throw new NotSupportedException($"Unsupported type: {type}"); + } + } + } + + public class CastFloatAsIntTransformer : VariableTransformerBase + { + private readonly DataNodeType _outputType; + + public CastFloatAsIntTransformer(DataNodeType srcType) + { + switch (srcType) + { + case DataNodeType.Float32: _outputType = DataNodeType.Int32; break; + case DataNodeType.Float64: _outputType = DataNodeType.Int64; break; + default: throw new NotSupportedException($"Unsupported type: {srcType}"); + } + } + + public override object Compute(object value) + { + switch (_outputType) + { + case DataNodeType.Int32: + return ConstUtility.CastFloatAsInt((float)value); + case DataNodeType.Int64: + return ConstUtility.CastDoubleAsLong((double)value); + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public override object ReverseCompute(object value) + { + switch (_outputType) + { + case DataNodeType.Int32: + return ConstUtility.CastIntAsFloat((int)value); + case DataNodeType.Int64: + return ConstUtility.CastLongAsDouble((long)value); + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public override void EmitTransform(List output, EncryptionCompileContext ctx) + { + switch (_outputType) + { + case DataNodeType.Int32: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastFloatAsInt())); + break; + case DataNodeType.Int64: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastDoubleAsLong())); + break; + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public override void EmitRevertTransform(List output, EncryptionCompileContext ctx) + { + switch (_outputType) + { + case DataNodeType.Int32: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastIntAsFloat())); + break; + case DataNodeType.Int64: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastLongAsDouble())); + break; + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public static CastFloatAsIntTransformer Create(DataNodeType type) + { + switch (type) + { + case DataNodeType.Float32: + case DataNodeType.Float64: return new CastFloatAsIntTransformer(type); + default: + throw new NotSupportedException($"Unsupported type: {type}"); + } + } + } + + public class CastIntAsFloatTransformer : VariableTransformerBase + { + private readonly DataNodeType _outputType; + + public CastIntAsFloatTransformer(DataNodeType srcType) + { + switch (srcType) + { + case DataNodeType.Int32: _outputType = DataNodeType.Float32; break; + case DataNodeType.Int64: _outputType = DataNodeType.Float64; break; + default: throw new NotSupportedException($"Unsupported type: {srcType}"); + } + } + + public override object Compute(object value) + { + switch (_outputType) + { + case DataNodeType.Float32: + return ConstUtility.CastIntAsFloat((int)value); + case DataNodeType.Float64: + return ConstUtility.CastLongAsDouble((long)value); + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public override object ReverseCompute(object value) + { + switch (_outputType) + { + case DataNodeType.Float32: + return ConstUtility.CastFloatAsInt((float)value); + case DataNodeType.Float64: + return ConstUtility.CastDoubleAsLong((double)value); + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public override void EmitTransform(List output, EncryptionCompileContext ctx) + { + switch (_outputType) + { + case DataNodeType.Float32: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastIntAsFloat())); + break; + case DataNodeType.Float64: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastLongAsDouble())); + break; + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public override void EmitRevertTransform(List output, EncryptionCompileContext ctx) + { + switch (_outputType) + { + case DataNodeType.Float32: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastFloatAsInt())); + break; + case DataNodeType.Float64: + output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastDoubleAsLong())); + break; + default: throw new NotSupportedException($"Unsupported type: {_outputType}"); + } + } + + public static CastIntAsFloatTransformer Create(DataNodeType type) + { + switch (type) + { + case DataNodeType.Int32: + case DataNodeType.Int64: return new CastIntAsFloatTransformer(type); + default: + throw new NotSupportedException($"Unsupported type: {type}"); + } + } + } + + public class VariableEncryption + { + private readonly List _transformers = new List(); + + private readonly DataNodeType _type; + + public VariableEncryption(DataNodeType type, IRandom random) + { + _type = type; + if (type == DataNodeType.Float32) + { + _transformers.Add(CastFloatAsIntTransformer.Create(type)); + _transformers.AddRange(CreateTransformers(DataNodeType.Int32, random)); + _transformers.Add(CastIntAsFloatTransformer.Create(DataNodeType.Int32)); + + Assert.AreEqual(1.0f, (float)ComputeValueAfterRevertTransform(ComputeValueAfterTransform(1.0f, _transformers), _transformers)); + } + else if (type == DataNodeType.Float64) + { + _transformers.Add(CastFloatAsIntTransformer.Create(type)); + _transformers.AddRange(CreateTransformers(DataNodeType.Int64, random)); + _transformers.Add(CastIntAsFloatTransformer.Create(DataNodeType.Int64)); + Assert.AreEqual(1.0, (double)ComputeValueAfterRevertTransform(ComputeValueAfterTransform(1.0, _transformers), _transformers)); + } + else if (type == DataNodeType.Int32) + { + _transformers.AddRange(CreateTransformers(type, random)); + Assert.AreEqual(1, (int)ComputeValueAfterRevertTransform(ComputeValueAfterTransform(1, _transformers), _transformers)); + } + else if (type == DataNodeType.Int64) + { + _transformers.AddRange(CreateTransformers(type, random)); + Assert.AreEqual(1L, (long)ComputeValueAfterRevertTransform(ComputeValueAfterTransform(1L, _transformers), _transformers)); + } + else + { + throw new NotSupportedException($"Unsupported type: {type} for VariableEncryption"); + } + } + + private List CreateTransformers(DataNodeType type, IRandom random) + { + var output = new List(); + output.Add(XorVariableTransformer.Create(type, random)); + output.Add(AddVariableTransformer.Create(type, random)); + output.Add(XorVariableTransformer.Create(type, random)); + //int count = 3; + //for (int i = 0; i < count; i++) + //{ + // switch(random.NextInt(2)) + // { + // case 0: + // { + // var transformer = AddVariableTransformer.Create(type, random); + // output.Add(transformer); + // break; + // } + // case 1: + // { + // var transformer = XorVariableTransformer.Create(type, random); + // output.Add(transformer); + // break; + // } + // } + //} + AddMapZeroToZeroTransform(type, random, output); + return output; + } + + public static object ComputeValueAfterTransform(object value, List transformers) + { + foreach (var transformer in transformers) + { + value = transformer.Compute(value); + } + return value; + } + + public static object ComputeValueAfterRevertTransform(object value, List transformers) + { + for (int i = transformers.Count - 1; i >= 0; i--) + { + var transformer = transformers[i]; + value = transformer.ReverseCompute(value); + } + return value; + } + + + private void AddMapZeroToZeroTransform(DataNodeType type, IRandom random, List output) + { + switch (type) + { + case DataNodeType.Int32: + { + int value = (int)ComputeValueAfterTransform(0, output); + if (value != 0) + { + output.Add(new AddVariableTransformer(type, -value)); + } + break; + } + case DataNodeType.Int64: + { + long value = (long)ComputeValueAfterTransform(0L, output); + if (value != 0) + { + output.Add(new AddVariableTransformer(type, -value)); + } + break; + } + default: + throw new NotSupportedException($"Unsupported type: {type}"); + } + } + + public void EmitTransform(List output, EncryptionCompileContext ctx) + { + foreach (var transformer in _transformers) + { + transformer.EmitTransform(output, ctx); + } + } + + public void EmitRevertTransform(List output, EncryptionCompileContext ctx) + { + for (int i = _transformers.Count - 1; i >= 0; i--) + { + var transformer = _transformers[i]; + transformer.EmitRevertTransform(output, ctx); + } + } + } +} diff --git a/Editor/MemEncrypt/DefaultMemoryEncryptor.cs b/Editor/MemEncrypt/DefaultMemoryEncryptor.cs index 41e3acf..5da46d9 100644 --- a/Editor/MemEncrypt/DefaultMemoryEncryptor.cs +++ b/Editor/MemEncrypt/DefaultMemoryEncryptor.cs @@ -1,5 +1,7 @@ using dnlib.DotNet; using dnlib.DotNet.Emit; +using Obfuz.Emit; +using Obfuz.Utils; using System; using System.Collections.Generic; using UnityEngine.Assertions; @@ -42,44 +44,32 @@ namespace Obfuz.MemEncrypt Assert.IsNotNull(s_castDoubleAsLong, "CastDoubleAsLong not found"); } + + private VariableEncryption CreateEncryption(ElementType type) + { + IRandom random = new RandomWithKey(new byte[16], 1234); + switch (type) + { + case ElementType.I4: + return new VariableEncryption(DataNodeType.Int32, random); + case ElementType.I8: + return new VariableEncryption(DataNodeType.Int64, random); + case ElementType.R4: + return new VariableEncryption(DataNodeType.Float32, random); + case ElementType.R8: + return new VariableEncryption(DataNodeType.Float64, random); + default: throw new Exception($"Unsupported type {type} for MemoryEncryptor"); + } + } + public void Encrypt(FieldDef field, List outputInstructions, MemoryEncryptionContext ctx) { - ElementType type = field.FieldType.RemovePinnedAndModifiers().ElementType; - if (type == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castFloatAsInt)); - type = ElementType.I4; - } - else if (type == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castDoubleAsLong)); - type = ElementType.I8; - } - if (type == ElementType.I4) - { - outputInstructions.Add(Instruction.CreateLdcI4(100)); - outputInstructions.Add(Instruction.Create(OpCodes.Add)); - } - else if (type == ElementType.I8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, 100L)); - outputInstructions.Add(Instruction.Create(OpCodes.Add)); - } - else - { - throw new NotSupportedException($"Unsupported type {type} for MemoryEncryptor"); - } - if (type == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castIntAsFloat)); - type = ElementType.I4; - } - else if (type == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castLongAsDouble)); - type = ElementType.I8; - } + ElementType type = field.FieldType.RemovePinnedAndModifiers().ElementType; + var encryption = CreateEncryption(type); + + encryption.EmitTransform(outputInstructions, new EncryptionCompileContext { module = _module }); + outputInstructions.Add(ctx.currentInstruction.Clone()); } @@ -87,41 +77,9 @@ namespace Obfuz.MemEncrypt { outputInstructions.Add(ctx.currentInstruction.Clone()); ElementType type = field.FieldType.RemovePinnedAndModifiers().ElementType; - if (type == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castFloatAsInt)); - type = ElementType.I4; - } - else if (type == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castDoubleAsLong)); - type = ElementType.I8; - } + var encryption = CreateEncryption(type); - if (type == ElementType.I4) - { - outputInstructions.Add(Instruction.CreateLdcI4(100)); - outputInstructions.Add(Instruction.Create(OpCodes.Sub)); - } - else if (type == ElementType.I8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, 100L)); - outputInstructions.Add(Instruction.Create(OpCodes.Sub)); - } - else - { - throw new NotSupportedException($"Unsupported type {type} for MemoryEncryptor"); - } - if (type == ElementType.R4) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castIntAsFloat)); - type = ElementType.I4; - } - else if (type == ElementType.R8) - { - outputInstructions.Add(Instruction.Create(OpCodes.Call, s_castLongAsDouble)); - type = ElementType.I8; - } + encryption.EmitRevertTransform(outputInstructions, new EncryptionCompileContext { module = _module }); } } diff --git a/Editor/Obfuscator.cs b/Editor/Obfuscator.cs index f36dd88..17b0a0d 100644 --- a/Editor/Obfuscator.cs +++ b/Editor/Obfuscator.cs @@ -46,12 +46,13 @@ namespace Obfuz { _options = options; _obfuscationAssemblyNames = options.obfuscationAssemblyNames; + MetadataImporter.Reset(); _assemblyCache = new AssemblyCache(new PathAssemblyResolver(options.assemblySearchDirs.ToArray())); _pipeline.AddPass(new MemoryEncryptionPass()); - _pipeline.AddPass(new ProxyCallPass()); - _pipeline.AddPass(new ExprObfuscationPass()); - _pipeline.AddPass(new DataVirtualizationPass()); + //_pipeline.AddPass(new ProxyCallPass()); + //_pipeline.AddPass(new ExprObfuscationPass()); + //_pipeline.AddPass(new DataVirtualizationPass()); _pipeline.AddPass(new RenameSymbolPass()); _pipeline.AddPass(new CleanUpInstructionPass());