diff --git a/Editor/Data/RvaDataAllocator.cs b/Editor/Data/RvaDataAllocator.cs index e3b9710..8827ee0 100644 --- a/Editor/Data/RvaDataAllocator.cs +++ b/Editor/Data/RvaDataAllocator.cs @@ -303,7 +303,7 @@ namespace Obfuz.Data } } - public void Done() + public override void Done() { if (_done) { diff --git a/Editor/Emit/DefaultMetadataImporter.cs b/Editor/Emit/DefaultMetadataImporter.cs index db59b47..eb977f2 100644 --- a/Editor/Emit/DefaultMetadataImporter.cs +++ b/Editor/Emit/DefaultMetadataImporter.cs @@ -248,6 +248,11 @@ namespace Obfuz.Emit } } + public override void Done() + { + + } + public EncryptionServiceMetadataImporter GetEncryptionServiceMetadataImporterOfModule(ModuleDef mod) { return _encryptionScopeProvider.IsDynamicSecretAssembly(mod) ? _dynamicDefaultEncryptionServiceMetadataImporter : _staticDefaultEncryptionServiceMetadataImporter; diff --git a/Editor/Emit/EvalStackCalculator.cs b/Editor/Emit/EvalStackCalculator.cs index 3958a15..a7fd4f3 100644 --- a/Editor/Emit/EvalStackCalculator.cs +++ b/Editor/Emit/EvalStackCalculator.cs @@ -270,7 +270,7 @@ namespace Obfuz.Emit private void SimulateRunAllBlocks() { - bool methodHasReturnValue = _method.ReturnType.RemovePinnedAndModifiers().ElementType != ElementType.Void; + bool methodHasReturnValue = !MetaUtil.IsVoidType(_method.ReturnType); CilBody body = _method.Body; if (body.HasExceptionHandlers) diff --git a/Editor/Emit/GroupByModuleEntityManager.cs b/Editor/Emit/GroupByModuleEntityManager.cs index 4c89567..5745cf2 100644 --- a/Editor/Emit/GroupByModuleEntityManager.cs +++ b/Editor/Emit/GroupByModuleEntityManager.cs @@ -7,11 +7,15 @@ namespace Obfuz.Emit public interface IGroupByModuleEntity { void Init(ModuleDef mod); + + void Done(); } public abstract class GroupByModuleEntityBase : IGroupByModuleEntity { public abstract void Init(ModuleDef mod); + + public abstract void Done(); } public class GroupByModuleEntityManager @@ -55,6 +59,16 @@ namespace Obfuz.Emit return managers; } + public void Done() where T : IGroupByModuleEntity + { + var managers = GetEntities(); + foreach (var manager in managers) + { + manager.Done(); + } + _moduleEntityManagers.Remove((default(ModuleDef), typeof(T))); + } + public DefaultMetadataImporter GetDefaultModuleMetadataImporter(ModuleDef module, EncryptionScopeProvider encryptionScopeProvider) { return GetEntity(module, () => new DefaultMetadataImporter(encryptionScopeProvider)); diff --git a/Editor/Emit/LocalVariableAllocator.cs b/Editor/Emit/LocalVariableAllocator.cs index 60eec70..3fb0015 100644 --- a/Editor/Emit/LocalVariableAllocator.cs +++ b/Editor/Emit/LocalVariableAllocator.cs @@ -11,6 +11,8 @@ namespace Obfuz.Emit private readonly List _allocatedVars = new List(); + public IReadOnlyList AllocatedLocals => _allocatedVars; + public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator) { @@ -63,5 +65,10 @@ namespace Obfuz.Emit { _freeLocals.Add(local); } + + public ScopeLocalVariables CreateScope() + { + return new ScopeLocalVariables(this); + } } } diff --git a/Editor/ObfusPasses/CallObfus/CallObfusPass.cs b/Editor/ObfusPasses/CallObfus/CallObfusPass.cs index 15299c2..68721bf 100644 --- a/Editor/ObfusPasses/CallObfus/CallObfusPass.cs +++ b/Editor/ObfusPasses/CallObfus/CallObfusPass.cs @@ -7,8 +7,15 @@ using System.Collections.Generic; namespace Obfuz.ObfusPasses.CallObfus { + class ObfusMethodContext + { + public MethodDef method; + public LocalVariableAllocator localVariableAllocator; + public IRandom localRandom; + public EncryptionScopeInfo encryptionScope; + } - public class CallObfusPass : BasicBlockObfuscationPassBase + public class CallObfusPass : ObfuscationMethodPassBase { private readonly CallObfuscationSettingsFacade _settings; private readonly SpecialWhiteListMethodCalculator _specialWhiteListMethodCache; @@ -32,17 +39,80 @@ namespace Obfuz.ObfusPasses.CallObfus public override void Start() { var ctx = ObfuscationPassContext.Current; - _dynamicProxyObfuscator = new DefaultCallProxyObfuscator(ctx.encryptionScopeProvider, ctx.constFieldAllocator, ctx.moduleEntityManager, _settings); + _dynamicProxyObfuscator = CreateObfuscator(ctx, _settings.proxyMode); _dynamicProxyPolicy = new ConfigurableObfuscationPolicy(ctx.coreSettings.assembliesToObfuscate, _settings.ruleFiles); } + private IObfuscator CreateObfuscator(ObfuscationPassContext ctx, ProxyMode mode) + { + switch (mode) + { + case ProxyMode.Dispatch: + return new DispatchProxyObfuscator(ctx.encryptionScopeProvider, ctx.constFieldAllocator, ctx.moduleEntityManager, _settings); + case ProxyMode.Delegate: + return new DelegateProxyObfuscator(ctx.encryptionScopeProvider, ctx.moduleEntityManager, ctx.rvaDataAllocator, _settings); + default: + throw new System.NotSupportedException($"Unsupported proxy mode: {mode}"); + } + } + + protected override void ObfuscateData(MethodDef method) + { + BasicBlockCollection bbc = new BasicBlockCollection(method, false); + + IList instructions = method.Body.Instructions; + + var outputInstructions = new List(); + var totalFinalInstructions = new List(); + + ObfuscationPassContext ctx = ObfuscationPassContext.Current; + var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module); + var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); + var omc = new ObfusMethodContext + { + method = method, + localVariableAllocator = new LocalVariableAllocator(method), + localRandom = localRandom, + encryptionScope = encryptionScope, + }; + Instruction lastInst = null; + for (int i = 0; i < instructions.Count; i++) + { + Instruction inst = instructions[i]; + BasicBlock block = bbc.GetBasicBlockByInstruction(inst); + outputInstructions.Clear(); + if (TryObfuscateInstruction(method, lastInst, inst, outputInstructions, omc)) + { + // 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); + } + lastInst = inst; + } + + instructions.Clear(); + foreach (var obInst in totalFinalInstructions) + { + instructions.Add(obInst); + } + } + protected override bool NeedObfuscateMethod(MethodDef method) { return _dynamicProxyPolicy.NeedObfuscateCallInMethod(method); } - protected override bool TryObfuscateInstruction(MethodDef callerMethod, Instruction inst, BasicBlock block, - int instructionIndex, IList globalInstructions, List outputInstructions, List totalFinalInstructions) + private bool TryObfuscateInstruction(MethodDef callerMethod, Instruction lastInst, Instruction inst, List outputInstructions, ObfusMethodContext ctx) { IMethod calledMethod = inst.Operand as IMethod; if (calledMethod == null || !calledMethod.IsMethod) @@ -64,7 +134,7 @@ namespace Obfuz.ObfusPasses.CallObfus } case Code.Callvirt: { - if (instructionIndex > 0 && globalInstructions[instructionIndex - 1].OpCode.Code == Code.Constrained) + if (lastInst != null && lastInst.OpCode.Code == Code.Constrained) { return false; } @@ -81,15 +151,12 @@ namespace Obfuz.ObfusPasses.CallObfus } - if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir, block.inLoop)) + if (!_dynamicProxyPolicy.NeedObfuscateCalledMethod(callerMethod, calledMethod, callVir)) { return false; } - ObfuscationCachePolicy cachePolicy = _dynamicProxyPolicy.GetMethodObfuscationCachePolicy(callerMethod); - bool cachedCallIndex = block.inLoop ? cachePolicy.cacheInLoop : cachePolicy.cacheNotInLoop; - _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, cachedCallIndex, outputInstructions); - return true; + return _dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, outputInstructions); } } } diff --git a/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs b/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs index aeb4723..57a30e5 100644 --- a/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs +++ b/Editor/ObfusPasses/CallObfus/ConfigurableObfuscationPolicy.cs @@ -1,5 +1,6 @@ using dnlib.DotNet; using Obfuz.Conf; +using Obfuz.Settings; using Obfuz.Utils; using System; using System.Collections.Generic; @@ -34,29 +35,12 @@ namespace Obfuz.ObfusPasses.CallObfus class ObfuscationRule : IRule { - public bool? disableObfuscation; - public bool? obfuscateCallInLoop; - public bool? cacheCallIndexInLoop; - public bool? cacheCallIndexNotLoop; + public ObfuscationLevel? obfuscationLevel; public void InheritParent(ObfuscationRule parentRule) { - if (disableObfuscation == null) - { - disableObfuscation = parentRule.disableObfuscation; - } - if (obfuscateCallInLoop == null) - { - obfuscateCallInLoop = parentRule.obfuscateCallInLoop; - } - if (cacheCallIndexInLoop == null) - { - cacheCallIndexInLoop = parentRule.cacheCallIndexInLoop; - } - if (cacheCallIndexNotLoop == null) - { - cacheCallIndexNotLoop = parentRule.cacheCallIndexNotLoop; - } + if (obfuscationLevel == null) + obfuscationLevel = parentRule.obfuscationLevel; } } @@ -75,10 +59,7 @@ namespace Obfuz.ObfusPasses.CallObfus private static readonly ObfuscationRule s_default = new ObfuscationRule() { - disableObfuscation = false, - obfuscateCallInLoop = true, - cacheCallIndexInLoop = true, - cacheCallIndexNotLoop = true, + obfuscationLevel = ObfuscationLevel.Basic, }; private readonly XmlAssemblyTypeMethodRuleParser _configParser; @@ -147,21 +128,9 @@ namespace Obfuz.ObfusPasses.CallObfus private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) { var rule = new ObfuscationRule(); - if (ele.HasAttribute("disableObfuscation")) + if (ele.HasAttribute("obfuscationLevel")) { - rule.disableObfuscation = ConfigUtil.ParseBool(ele.GetAttribute("disableObfuscation")); - } - if (ele.HasAttribute("obfuscateCallInLoop")) - { - rule.obfuscateCallInLoop = ConfigUtil.ParseBool(ele.GetAttribute("obfuscateCallInLoop")); - } - if (ele.HasAttribute("cacheCallIndexInLoop")) - { - rule.cacheCallIndexInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheCallIndexInLoop")); - } - if (ele.HasAttribute("cacheCallIndexNotLoop")) - { - rule.cacheCallIndexNotLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheCallIndexNotLoop")); + rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); } return rule; } @@ -262,17 +231,7 @@ namespace Obfuz.ObfusPasses.CallObfus public override bool NeedObfuscateCallInMethod(MethodDef method) { ObfuscationRule rule = GetMethodObfuscationRule(method); - return rule.disableObfuscation != true; - } - - public override ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method) - { - ObfuscationRule rule = GetMethodObfuscationRule(method); - return new ObfuscationCachePolicy() - { - cacheInLoop = rule.cacheCallIndexInLoop.Value, - cacheNotInLoop = rule.cacheCallIndexNotLoop.Value, - }; + return rule.obfuscationLevel != null && rule.obfuscationLevel.Value >= ObfuscationLevel.Basic; } private bool ComputeIsInWhiteList(IMethod calledMethod) @@ -329,18 +288,12 @@ namespace Obfuz.ObfusPasses.CallObfus return false; } - public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop) + public override bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir) { if (_whiteListMethodCache.GetValue(calledMethod)) { return false; } - - ObfuscationRule rule = GetMethodObfuscationRule(callerMethod); - if (currentInLoop && rule.obfuscateCallInLoop == false) - { - return false; - } return true; } } diff --git a/Editor/ObfusPasses/CallObfus/DefaultCallProxyObfuscator.cs b/Editor/ObfusPasses/CallObfus/DefaultCallProxyObfuscator.cs deleted file mode 100644 index 8714fce..0000000 --- a/Editor/ObfusPasses/CallObfus/DefaultCallProxyObfuscator.cs +++ /dev/null @@ -1,53 +0,0 @@ -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using Obfuz.Data; -using Obfuz.Emit; -using Obfuz.Settings; -using Obfuz.Utils; -using System.Collections.Generic; - -namespace Obfuz.ObfusPasses.CallObfus -{ - public class DefaultCallProxyObfuscator : ObfuscatorBase - { - private readonly EncryptionScopeProvider _encryptionScopeProvider; - private readonly ConstFieldAllocator _constFieldAllocator; - private readonly CallProxyAllocator _proxyCallAllocator; - private readonly GroupByModuleEntityManager _moduleEntityManager; - - public DefaultCallProxyObfuscator(EncryptionScopeProvider encryptionScopeProvider, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, CallObfuscationSettingsFacade settings) - { - _encryptionScopeProvider = encryptionScopeProvider; - _constFieldAllocator = constFieldAllocator; - _moduleEntityManager = moduleEntityManager; - _proxyCallAllocator = new CallProxyAllocator(encryptionScopeProvider, moduleEntityManager, settings); - } - - public override void Done() - { - _proxyCallAllocator.Done(); - } - - public override void Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List obfuscatedInstructions) - { - - MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod, null)); - ProxyCallMethodData proxyCallMethodData = _proxyCallAllocator.Allocate(callerMethod.Module, calledMethod, callVir); - DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(callerMethod.Module, _encryptionScopeProvider); - - if (needCacheCall) - { - FieldDef cacheField = _constFieldAllocator.Allocate(callerMethod.Module, proxyCallMethodData.index); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); - } - else - { - obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptedIndex)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptOps)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt)); - } - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod)); - } - } -} diff --git a/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs b/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs new file mode 100644 index 0000000..b0255fc --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs @@ -0,0 +1,300 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using NUnit.Framework; +using Obfuz.Data; +using Obfuz.Emit; +using Obfuz.Settings; +using Obfuz.Utils; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Obfuz.ObfusPasses.CallObfus +{ + + struct DelegateProxyMethodData + { + public readonly FieldDef delegateInstanceField; + public readonly MethodDef delegateInvokeMethod; + + public DelegateProxyMethodData(FieldDef delegateInstanceField, MethodDef delegateInvokeMethod) + { + this.delegateInstanceField = delegateInstanceField; + this.delegateInvokeMethod = delegateInvokeMethod; + } + } + + class ModuleDelegateProxyAllocator : IGroupByModuleEntity + { + private readonly GroupByModuleEntityManager _moduleEntityManager; + private readonly EncryptionScopeProvider _encryptionScopeProvider; + private readonly RvaDataAllocator _rvaDataAllocator; + private readonly CallObfuscationSettingsFacade _settings; + private readonly CachedDictionary _delegateTypes; + private readonly HashSet _allocatedDelegateNames = new HashSet(); + + private ModuleDef _module; + + private TypeDef _delegateInstanceHolderType; + private bool _done; + + class CallInfo + { + public string key1; + public int key2; + public IMethod method; + public bool callVir; + + public int index; + public TypeDef delegateType; + public FieldDef delegateInstanceField; + public MethodDef delegateInvokeMethod; + public MethodDef proxyMethod; + } + private readonly Dictionary _callMethods = new Dictionary(); + + public ModuleDelegateProxyAllocator(GroupByModuleEntityManager moduleEntityManager, EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, CallObfuscationSettingsFacade settings) + { + _moduleEntityManager = moduleEntityManager; + _encryptionScopeProvider = encryptionScopeProvider; + _rvaDataAllocator = rvaDataAllocator; + _settings = settings; + _delegateTypes = new CachedDictionary(SignatureEqualityComparer.Instance, CreateDelegateForSignature); + } + + public void Init(ModuleDef mod) + { + _module = mod; + + _delegateInstanceHolderType = CreateDelegateInstanceHolderTypeDef(); + } + + private string AllocateDelegateTypeName(MethodSig delegateInvokeSig) + { + uint hashCode = (uint)SignatureEqualityComparer.Instance.GetHashCode(delegateInvokeSig); + string typeName = $"$Obfuz$Delegate_{hashCode}"; + if (_allocatedDelegateNames.Add(typeName)) + { + return typeName; + } + for (int i = 0; ;i++) + { + typeName = $"$Obfuz$Delegate_{hashCode}_{i}"; + if (_allocatedDelegateNames.Add(typeName)) + { + return typeName; + } + } + } + + private TypeDef CreateDelegateForSignature(MethodSig delegateInvokeSig) + { + using (var scope = new DisableTypeDefFindCacheScope(_module)) + { + + string typeName = AllocateDelegateTypeName(delegateInvokeSig); + _module.Import(typeof(MulticastDelegate)); + + TypeDef delegateType = new TypeDefUser("", typeName, _module.CorLibTypes.GetTypeRef("System", "MulticastDelegate")); + delegateType.Attributes = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public; + _module.Types.Add(delegateType); + + MethodDef ctor = new MethodDefUser( + ".ctor", + MethodSig.CreateInstance(_module.CorLibTypes.Void, _module.CorLibTypes.Object, _module.CorLibTypes.IntPtr), + MethodImplAttributes.Runtime, + MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public + ); + ctor.DeclaringType = delegateType; + + + MethodDef invokeMethod = new MethodDefUser( + "Invoke", + MethodSig.CreateInstance(delegateInvokeSig.RetType, delegateInvokeSig.Params.ToArray()), + MethodImplAttributes.Runtime, + MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual + ); + invokeMethod.DeclaringType = delegateType; + return delegateType; + } + } + + private TypeDef CreateDelegateInstanceHolderTypeDef() + { + using (var scope = new DisableTypeDefFindCacheScope(_module)) + { + string typeName = "$Obfuz$DelegateInstanceHolder"; + TypeDef holderType = new TypeDefUser("", typeName, _module.CorLibTypes.Object.ToTypeDefOrRef()); + holderType.Attributes = TypeAttributes.Class | TypeAttributes.Public; + _module.Types.Add(holderType); + return holderType; + } + } + + private string AllocateFieldName(IMethod method, bool callVir) + { + uint hashCode = (uint)MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method); + string typeName = $"$Obfuz$Delegate$Field_{hashCode}_{callVir}"; + if (_allocatedDelegateNames.Add(typeName)) + { + return typeName; + } + for (int i = 0; ; i++) + { + typeName = $"$Obfuz$Delegate$Field_{hashCode}_{callVir}_{i}"; + if (_allocatedDelegateNames.Add(typeName)) + { + return typeName; + } + } + } + + private MethodDef CreateProxyMethod(string name, IMethod calledMethod, bool callVir, MethodSig delegateInvokeSig) + { + var proxyMethod = new MethodDefUser(name, delegateInvokeSig, MethodImplAttributes.Managed, MethodAttributes.Public | MethodAttributes.Static); + var body = new CilBody(); + proxyMethod.Body = body; + var ins = body.Instructions; + + foreach (Parameter param in proxyMethod.Parameters) + { + ins.Add(Instruction.Create(OpCodes.Ldarg, param)); + } + + ins.Add(Instruction.Create(callVir ? OpCodes.Callvirt : OpCodes.Call, calledMethod)); + ins.Add(Instruction.Create(OpCodes.Ret)); + return proxyMethod; + } + + public DelegateProxyMethodData Allocate(IMethod method, bool callVir, MethodSig delegateInvokeSig) + { + var key = new MethodKey(method, callVir); + if (!_callMethods.TryGetValue(key, out var callInfo)) + { + TypeDef delegateType = _delegateTypes.GetValue(delegateInvokeSig); + MethodDef delegateInvokeMethod = delegateType.FindMethod("Invoke"); + string fieldName = AllocateFieldName(method, callVir); + FieldDef delegateInstanceField = new FieldDefUser(fieldName, new FieldSig(delegateType.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly); + string key1 = $"{method.FullName}_{callVir}"; + callInfo = new CallInfo + { + key1 = key1, + key2 = HashUtil.ComputePrimitiveOrStringOrBytesHashCode(key1) * 33445566, + method = method, + callVir = callVir, + delegateType = delegateType, + delegateInstanceField = delegateInstanceField, + delegateInvokeMethod = delegateInvokeMethod, + proxyMethod = CreateProxyMethod($"{fieldName}$Proxy", method, callVir, delegateInvokeSig), + }; + _callMethods.Add(key, callInfo); + } + return new DelegateProxyMethodData(callInfo.delegateInstanceField, callInfo.delegateInvokeMethod); + } + + public void Done() + { + if (_done) + { + throw new Exception("Already done"); + } + _done = true; + + // for stable order, we sort methods by name + List callMethodList = _callMethods.Values.ToList(); + callMethodList.Sort((a, b) => a.key1.CompareTo(b.key1)); + + var cctor = new MethodDefUser(".cctor", + MethodSig.CreateStatic(_module.CorLibTypes.Void), + MethodImplAttributes.IL | MethodImplAttributes.Managed, + MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Private); + cctor.DeclaringType = _delegateInstanceHolderType; + //_rvaTypeDef.Methods.Add(cctor); + var body = new CilBody(); + cctor.Body = body; + var ins = body.Instructions; + + // var arr = new array[]; + // var d = new delegate; + // arr[index] = d; + int index = 0; + ins.Add(Instruction.CreateLdcI4(callMethodList.Count)); + ins.Add(Instruction.Create(OpCodes.Newarr, _module.CorLibTypes.Object)); + foreach (CallInfo ci in callMethodList) + { + ci.index = index; + _delegateInstanceHolderType.Methods.Add(ci.proxyMethod); + ins.Add(Instruction.Create(OpCodes.Dup)); + ins.Add(Instruction.CreateLdcI4(index)); + ins.Add(Instruction.Create(OpCodes.Ldnull)); + ins.Add(Instruction.Create(OpCodes.Ldftn, ci.proxyMethod)); + MethodDef ctor = ci.delegateType.FindMethod(".ctor"); + Assert.NotNull(ctor, $"Delegate type {ci.delegateType.FullName} does not have a constructor."); + ins.Add(Instruction.Create(OpCodes.Newobj, ctor)); + ins.Add(Instruction.Create(OpCodes.Stelem_Ref)); + ++index; + } + + + + List callMethodList2 = callMethodList.ToList(); + callMethodList2.Sort((a, b) => a.key2.CompareTo(b.key2)); + + EncryptionScopeInfo encryptionScope = _encryptionScopeProvider.GetScope(_module); + DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(_module, _encryptionScopeProvider); + foreach (CallInfo ci in callMethodList2) + { + _delegateInstanceHolderType.Fields.Add(ci.delegateInstanceField); + + + ins.Add(Instruction.Create(OpCodes.Dup)); + + IRandom localRandom = encryptionScope.localRandomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(ci.key1)); + int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, encryptionScope.encryptor, 4); + int salt = localRandom.NextInt(); + + int encryptedValue = encryptionScope.encryptor.Encrypt(ci.index, ops, salt); + RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); + ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + ins.Add(Instruction.CreateLdcI4(rvaData.offset)); + ins.Add(Instruction.CreateLdcI4(ops)); + ins.Add(Instruction.CreateLdcI4(salt)); + ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt)); + ins.Add(Instruction.Create(OpCodes.Ldelem_Ref)); + ins.Add(Instruction.Create(OpCodes.Stsfld, ci.delegateInstanceField)); + } + + ins.Add(Instruction.Create(OpCodes.Pop)); + ins.Add(Instruction.Create(OpCodes.Ret)); + } + } + + class DelegateProxyAllocator + { + private readonly EncryptionScopeProvider _encryptionScopeProvider; + private readonly GroupByModuleEntityManager _moduleEntityManager; + private readonly CallObfuscationSettingsFacade _settings; + private readonly RvaDataAllocator _rvaDataAllocator; + + public DelegateProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, RvaDataAllocator rvaDataAllocator, CallObfuscationSettingsFacade settings) + { + _encryptionScopeProvider = encryptionScopeProvider; + _moduleEntityManager = moduleEntityManager; + _rvaDataAllocator = rvaDataAllocator; + _settings = settings; + } + + public ModuleDelegateProxyAllocator GetModuleAllocator(ModuleDef mod) + { + return _moduleEntityManager.GetEntity(mod, () => new ModuleDelegateProxyAllocator(_moduleEntityManager, _encryptionScopeProvider, _rvaDataAllocator, _settings)); + } + + public void Done() + { + foreach (var allocator in _moduleEntityManager.GetEntities()) + { + allocator.Done(); + } + } + } +} diff --git a/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta b/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta new file mode 100644 index 0000000..d324d9a --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/DelegateProxyAllocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02761bacbed8a8b489ae3e7f49f0f84a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs b/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs new file mode 100644 index 0000000..b736dc1 --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs @@ -0,0 +1,83 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using Obfuz.Data; +using Obfuz.Emit; +using Obfuz.Settings; +using Obfuz.Utils; +using System.Collections.Generic; +using System.Linq; + +namespace Obfuz.ObfusPasses.CallObfus +{ + + public class DelegateProxyObfuscator : ObfuscatorBase + { + private readonly DelegateProxyAllocator _delegateProxyAllocator; + + public DelegateProxyObfuscator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, RvaDataAllocator rvaDataAllocator, CallObfuscationSettingsFacade settings) + { + _delegateProxyAllocator = new DelegateProxyAllocator(encryptionScopeProvider, moduleEntityManager, rvaDataAllocator, settings); + } + + public override void Done() + { + _delegateProxyAllocator.Done(); + } + + private MethodSig CreateProxyMethodSig(ModuleDef module, IMethod method) + { + MethodSig methodSig = MetaUtil.ToSharedMethodSig(module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method, null)); + //MethodSig methodSig = MetaUtil.GetInflatedMethodSig(method).Clone(); + //methodSig.Params + switch (MetaUtil.GetThisArgType(method)) + { + case ThisArgType.Class: + { + methodSig.Params.Insert(0, module.CorLibTypes.Object); + break; + } + case ThisArgType.ValueType: + { + methodSig.Params.Insert(0, module.CorLibTypes.IntPtr); + break; + } + } + return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray()); + } + + public override bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions) + { + ModuleDelegateProxyAllocator allocator = _delegateProxyAllocator.GetModuleAllocator(callingMethod.Module); + LocalVariableAllocator localVarAllocator = new LocalVariableAllocator(callingMethod); + MethodSig methodSig = CreateProxyMethodSig(callingMethod.Module, calledMethod); + DelegateProxyMethodData proxyData = allocator.Allocate(calledMethod, callVir, methodSig); + bool isVoidReturn = MetaUtil.IsVoidType(methodSig.RetType); + + using (var varScope = localVarAllocator.CreateScope()) + { + List localVars = new List(); + if (!isVoidReturn) + { + varScope.AllocateLocal(methodSig.RetType); + } + foreach (var p in methodSig.Params) + { + localVars.Add(varScope.AllocateLocal(p)); + } + // save args + for (int i = localVars.Count - 1; i >= 0; i--) + { + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Stloc, localVars[i])); + } + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, proxyData.delegateInstanceField)); + foreach (var local in localVars) + { + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldloc, local)); + } + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Callvirt, proxyData.delegateInvokeMethod)); + } + + return true; + } + } +} diff --git a/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta b/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta new file mode 100644 index 0000000..4cb75c3 --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/DelegateProxyObfuscator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1102cd9f03de27c4b9fde3d6a87277c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ObfusPasses/CallObfus/CallProxyAllocator.cs b/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs similarity index 87% rename from Editor/ObfusPasses/CallObfus/CallProxyAllocator.cs rename to Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs index b779997..8ebfca9 100644 --- a/Editor/ObfusPasses/CallObfus/CallProxyAllocator.cs +++ b/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs @@ -12,6 +12,7 @@ using TypeAttributes = dnlib.DotNet.TypeAttributes; namespace Obfuz.ObfusPasses.CallObfus { + public struct ProxyCallMethodData { public readonly MethodDef proxyMethod; @@ -30,7 +31,7 @@ namespace Obfuz.ObfusPasses.CallObfus } } - class ModuleCallProxyAllocator : IGroupByModuleEntity + class ModuleDispatchProxyAllocator : IGroupByModuleEntity { private ModuleDef _module; private readonly EncryptionScopeProvider _encryptionScopeProvider; @@ -39,29 +40,6 @@ namespace Obfuz.ObfusPasses.CallObfus private EncryptionScopeInfo _encryptionScope; private bool _done; - class MethodKey : IEquatable - { - public readonly IMethod _method; - public readonly bool _callVir; - private readonly int _hashCode; - - public MethodKey(IMethod method, bool callVir) - { - _method = method; - _callVir = callVir; - _hashCode = HashUtil.CombineHash(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method), callVir ? 1 : 0); - } - - public override int GetHashCode() - { - return _hashCode; - } - - public bool Equals(MethodKey other) - { - return MethodEqualityComparer.CompareDeclaringTypes.Equals(_method, other._method) && _callVir == other._callVir; - } - } class MethodProxyInfo { @@ -93,7 +71,7 @@ namespace Obfuz.ObfusPasses.CallObfus private TypeDef _proxyTypeDef; - public ModuleCallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, CallObfuscationSettingsFacade settings) + public ModuleDispatchProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, CallObfuscationSettingsFacade settings) { _encryptionScopeProvider = encryptionScopeProvider; _settings = settings; @@ -298,33 +276,33 @@ namespace Obfuz.ObfusPasses.CallObfus } } - public class CallProxyAllocator + public class DispatchProxyAllocator { private readonly EncryptionScopeProvider _encryptionScopeProvider; private GroupByModuleEntityManager _moduleEntityManager; private readonly CallObfuscationSettingsFacade _settings; - public CallProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, CallObfuscationSettingsFacade settings) + public DispatchProxyAllocator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, CallObfuscationSettingsFacade settings) { _encryptionScopeProvider = encryptionScopeProvider; _moduleEntityManager = moduleEntityManager; _settings = settings; } - private ModuleCallProxyAllocator GetModuleAllocator(ModuleDef mod) + private ModuleDispatchProxyAllocator GetModuleAllocator(ModuleDef mod) { - return _moduleEntityManager.GetEntity(mod, () => new ModuleCallProxyAllocator(_encryptionScopeProvider, _settings)); + return _moduleEntityManager.GetEntity(mod, () => new ModuleDispatchProxyAllocator(_encryptionScopeProvider, _settings)); } public ProxyCallMethodData Allocate(ModuleDef mod, IMethod method, bool callVir) { - ModuleCallProxyAllocator allocator = GetModuleAllocator(mod); + ModuleDispatchProxyAllocator allocator = GetModuleAllocator(mod); return allocator.Allocate(method, callVir); } public void Done() { - foreach (var allocator in _moduleEntityManager.GetEntities()) + foreach (var allocator in _moduleEntityManager.GetEntities()) { allocator.Done(); } diff --git a/Editor/ObfusPasses/CallObfus/CallProxyAllocator.cs.meta b/Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs.meta similarity index 100% rename from Editor/ObfusPasses/CallObfus/CallProxyAllocator.cs.meta rename to Editor/ObfusPasses/CallObfus/DispatchProxyAllocator.cs.meta diff --git a/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs b/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs new file mode 100644 index 0000000..27bccff --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs @@ -0,0 +1,58 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using Obfuz.Data; +using Obfuz.Emit; +using Obfuz.Settings; +using Obfuz.Utils; +using System.Collections.Generic; + +namespace Obfuz.ObfusPasses.CallObfus +{ + + public class DispatchProxyObfuscator : ObfuscatorBase + { + private readonly EncryptionScopeProvider _encryptionScopeProvider; + private readonly ConstFieldAllocator _constFieldAllocator; + private readonly DispatchProxyAllocator _proxyCallAllocator; + private readonly GroupByModuleEntityManager _moduleEntityManager; + + public DispatchProxyObfuscator(EncryptionScopeProvider encryptionScopeProvider, ConstFieldAllocator constFieldAllocator, GroupByModuleEntityManager moduleEntityManager, CallObfuscationSettingsFacade settings) + { + _encryptionScopeProvider = encryptionScopeProvider; + _constFieldAllocator = constFieldAllocator; + _moduleEntityManager = moduleEntityManager; + _proxyCallAllocator = new DispatchProxyAllocator(encryptionScopeProvider, moduleEntityManager, settings); + } + + public override void Done() + { + _proxyCallAllocator.Done(); + } + + public override bool Obfuscate(MethodDef callerMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions) + { + + MethodSig sharedMethodSig = MetaUtil.ToSharedMethodSig(calledMethod.Module.CorLibTypes, MetaUtil.GetInflatedMethodSig(calledMethod, null)); + ProxyCallMethodData proxyCallMethodData = _proxyCallAllocator.Allocate(callerMethod.Module, calledMethod, callVir); + DefaultMetadataImporter importer = _moduleEntityManager.GetDefaultModuleMetadataImporter(callerMethod.Module, _encryptionScopeProvider); + + //if (needCacheCall) + //{ + // FieldDef cacheField = _constFieldAllocator.Allocate(callerMethod.Module, proxyCallMethodData.index); + // obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); + //} + //else + //{ + // obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptedIndex)); + // obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.encryptOps)); + // obfuscatedInstructions.Add(Instruction.CreateLdcI4(proxyCallMethodData.salt)); + // obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptInt)); + //} + + FieldDef cacheField = _constFieldAllocator.Allocate(callerMethod.Module, proxyCallMethodData.index); + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, proxyCallMethodData.proxyMethod)); + return true; + } + } +} diff --git a/Editor/ObfusPasses/CallObfus/DefaultCallProxyObfuscator.cs.meta b/Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs.meta similarity index 100% rename from Editor/ObfusPasses/CallObfus/DefaultCallProxyObfuscator.cs.meta rename to Editor/ObfusPasses/CallObfus/DispatchProxyObfuscator.cs.meta diff --git a/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs b/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs index 458165d..941291b 100644 --- a/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs +++ b/Editor/ObfusPasses/CallObfus/IObfuscationPolicy.cs @@ -3,27 +3,17 @@ namespace Obfuz.ObfusPasses.CallObfus { - public struct ObfuscationCachePolicy - { - public bool cacheInLoop; - public bool cacheNotInLoop; - } - public interface IObfuscationPolicy { bool NeedObfuscateCallInMethod(MethodDef method); - ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method); - - bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop); + bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir); } public abstract class ObfuscationPolicyBase : IObfuscationPolicy { public abstract bool NeedObfuscateCallInMethod(MethodDef method); - public abstract ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method); - - public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop); + public abstract bool NeedObfuscateCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir); } } diff --git a/Editor/ObfusPasses/CallObfus/IObfuscator.cs b/Editor/ObfusPasses/CallObfus/IObfuscator.cs index 6b305f1..bd26274 100644 --- a/Editor/ObfusPasses/CallObfus/IObfuscator.cs +++ b/Editor/ObfusPasses/CallObfus/IObfuscator.cs @@ -6,14 +6,15 @@ namespace Obfuz.ObfusPasses.CallObfus { public interface IObfuscator { - void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List obfuscatedInstructions); + bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions); void Done(); } public abstract class ObfuscatorBase : IObfuscator { - public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List obfuscatedInstructions); + public abstract bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List obfuscatedInstructions); + public abstract void Done(); } } diff --git a/Editor/ObfusPasses/CallObfus/MethodKey.cs b/Editor/ObfusPasses/CallObfus/MethodKey.cs new file mode 100644 index 0000000..9927558 --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/MethodKey.cs @@ -0,0 +1,30 @@ +using dnlib.DotNet; +using Obfuz.Utils; +using System; + +namespace Obfuz.ObfusPasses.CallObfus +{ + class MethodKey : IEquatable + { + public readonly IMethod _method; + public readonly bool _callVir; + private readonly int _hashCode; + + public MethodKey(IMethod method, bool callVir) + { + _method = method; + _callVir = callVir; + _hashCode = HashUtil.CombineHash(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method), callVir ? 1 : 0); + } + + public override int GetHashCode() + { + return _hashCode; + } + + public bool Equals(MethodKey other) + { + return MethodEqualityComparer.CompareDeclaringTypes.Equals(_method, other._method) && _callVir == other._callVir; + } + } +} diff --git a/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta b/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta new file mode 100644 index 0000000..f7a1a2a --- /dev/null +++ b/Editor/ObfusPasses/CallObfus/MethodKey.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1193647b317b56f4b83aa080d0a17f7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs b/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs index 75083ea..b86b1e7 100644 --- a/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs +++ b/Editor/ObfusPasses/ControlFlowObfus/ConfigurableObfuscationPolicy.cs @@ -1,6 +1,7 @@ using dnlib.DotNet; using Obfuz.Conf; using Obfuz.Settings; +using Obfuz.Utils; using System; using System.Collections.Generic; using System.Xml; @@ -97,17 +98,12 @@ namespace Obfuz.ObfusPasses.ControlFlowObfus } } - private ObfuscationLevel ParseObfuscationLevel(string str) - { - return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str); - } - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) { var rule = new ObfuscationRule(); if (ele.HasAttribute("obfuscationLevel")) { - rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); + rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); } return rule; } diff --git a/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs b/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs index 221b074..d41eaf2 100644 --- a/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs +++ b/Editor/ObfusPasses/EvalStackObfus/ConfigurableObfuscationPolicy.cs @@ -1,6 +1,7 @@ using dnlib.DotNet; using Obfuz.Conf; using Obfuz.Settings; +using Obfuz.Utils; using System; using System.Collections.Generic; using System.Xml; @@ -103,17 +104,12 @@ namespace Obfuz.ObfusPasses.EvalStackObfus } } - private ObfuscationLevel ParseObfuscationLevel(string str) - { - return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str); - } - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) { var rule = new ObfuscationRule(); if (ele.HasAttribute("obfuscationLevel")) { - rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); + rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); } if (ele.HasAttribute("obfuscationPercentage")) { diff --git a/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs b/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs index f7045dc..73929f1 100644 --- a/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs +++ b/Editor/ObfusPasses/ExprObfus/ConfigurableObfuscationPolicy.cs @@ -1,6 +1,7 @@ using dnlib.DotNet; using Obfuz.Conf; using Obfuz.Settings; +using Obfuz.Utils; using System; using System.Collections.Generic; using System.Xml; @@ -103,17 +104,12 @@ namespace Obfuz.ObfusPasses.ExprObfus } } - private ObfuscationLevel ParseObfuscationLevel(string str) - { - return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str); - } - private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) { var rule = new ObfuscationRule(); if (ele.HasAttribute("obfuscationLevel")) { - rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); + rule.obfuscationLevel = ConfigUtil.ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel")); } if (ele.HasAttribute("obfuscationPercentage")) { diff --git a/Editor/Settings/CallObfuscationSettings.cs b/Editor/Settings/CallObfuscationSettings.cs index 983a32f..a7ee139 100644 --- a/Editor/Settings/CallObfuscationSettings.cs +++ b/Editor/Settings/CallObfuscationSettings.cs @@ -5,17 +5,26 @@ using UnityEngine; namespace Obfuz.Settings { + public enum ProxyMode + { + Dispatch, + Delegate, + } + public class CallObfuscationSettingsFacade { - public List ruleFiles; + public ProxyMode proxyMode; public int obfuscationLevel; public int maxProxyMethodCountPerDispatchMethod; public bool obfuscateCallToMethodInMscorlib; + public List ruleFiles; } [Serializable] public class CallObfuscationSettings { + public ProxyMode proxyMode = ProxyMode.Dispatch; + [Tooltip("The obfuscation level for the obfuscation. Higher levels provide more security but may impact performance.")] [Range(1, 4)] public int obfuscationLevel = 1; @@ -23,7 +32,7 @@ namespace Obfuz.Settings [Tooltip("The maximum number of proxy methods that can be generated per dispatch method. This helps to limit the complexity of the generated code and improve performance.")] public int maxProxyMethodCountPerDispatchMethod = 100; - [Tooltip("Whether to obfuscate calls to methods in mscorlib. This can help to protect against reverse engineering, but may cause compatibility issues with some libraries.")] + [Tooltip("Whether to obfuscate calls to methods in mscorlib. Enable this option will impact performance.")] public bool obfuscateCallToMethodInMscorlib; [Tooltip("rule config xml files")] @@ -33,10 +42,11 @@ namespace Obfuz.Settings { return new CallObfuscationSettingsFacade { - ruleFiles = ruleFiles?.ToList() ?? new List(), + proxyMode = proxyMode, obfuscationLevel = obfuscationLevel, maxProxyMethodCountPerDispatchMethod = maxProxyMethodCountPerDispatchMethod, obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib, + ruleFiles = ruleFiles?.ToList() ?? new List(), }; } } diff --git a/Editor/Utils/ConfigUtil.cs b/Editor/Utils/ConfigUtil.cs index 1110a43..bc2c549 100644 --- a/Editor/Utils/ConfigUtil.cs +++ b/Editor/Utils/ConfigUtil.cs @@ -1,4 +1,5 @@ -using System; +using Obfuz.Settings; +using System; namespace Obfuz.Utils { @@ -68,5 +69,10 @@ namespace Obfuz.Utils } return double.Parse(str); } + + public static ObfuscationLevel ParseObfuscationLevel(string str) + { + return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str); + } } } diff --git a/Editor/Utils/MetaUtil.cs b/Editor/Utils/MetaUtil.cs index 0f20e11..21a7ace 100644 --- a/Editor/Utils/MetaUtil.cs +++ b/Editor/Utils/MetaUtil.cs @@ -28,6 +28,10 @@ namespace Obfuz.Utils return ("", fullName.Substring(index + 1)); } + public static bool IsVoidType(TypeSig type) + { + return type.RemovePinnedAndModifiers().ElementType == ElementType.Void; + } public static TypeDef GetBaseTypeDef(TypeDef type) {