CallObufs新增Delegate Proxy支持
parent
9b9eb6d12d
commit
4b0c5d7521
|
@ -303,7 +303,7 @@ namespace Obfuz.Data
|
|||
}
|
||||
}
|
||||
|
||||
public void Done()
|
||||
public override void Done()
|
||||
{
|
||||
if (_done)
|
||||
{
|
||||
|
|
|
@ -248,6 +248,11 @@ namespace Obfuz.Emit
|
|||
}
|
||||
}
|
||||
|
||||
public override void Done()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EncryptionServiceMetadataImporter GetEncryptionServiceMetadataImporterOfModule(ModuleDef mod)
|
||||
{
|
||||
return _encryptionScopeProvider.IsDynamicSecretAssembly(mod) ? _dynamicDefaultEncryptionServiceMetadataImporter : _staticDefaultEncryptionServiceMetadataImporter;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<T>() where T : IGroupByModuleEntity
|
||||
{
|
||||
var managers = GetEntities<T>();
|
||||
foreach (var manager in managers)
|
||||
{
|
||||
manager.Done();
|
||||
}
|
||||
_moduleEntityManagers.Remove((default(ModuleDef), typeof(T)));
|
||||
}
|
||||
|
||||
public DefaultMetadataImporter GetDefaultModuleMetadataImporter(ModuleDef module, EncryptionScopeProvider encryptionScopeProvider)
|
||||
{
|
||||
return GetEntity<DefaultMetadataImporter>(module, () => new DefaultMetadataImporter(encryptionScopeProvider));
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace Obfuz.Emit
|
|||
|
||||
private readonly List<Local> _allocatedVars = new List<Local>();
|
||||
|
||||
public IReadOnlyList<Local> AllocatedLocals => _allocatedVars;
|
||||
|
||||
|
||||
public ScopeLocalVariables(LocalVariableAllocator localVariableAllocator)
|
||||
{
|
||||
|
@ -63,5 +65,10 @@ namespace Obfuz.Emit
|
|||
{
|
||||
_freeLocals.Add(local);
|
||||
}
|
||||
|
||||
public ScopeLocalVariables CreateScope()
|
||||
{
|
||||
return new ScopeLocalVariables(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Instruction> instructions = method.Body.Instructions;
|
||||
|
||||
var outputInstructions = new List<Instruction>();
|
||||
var totalFinalInstructions = new List<Instruction>();
|
||||
|
||||
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<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||
private bool TryObfuscateInstruction(MethodDef callerMethod, Instruction lastInst, Instruction inst, List<Instruction> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ObfuscationRule>
|
||||
{
|
||||
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<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Instruction> 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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<MethodSig, TypeDef> _delegateTypes;
|
||||
private readonly HashSet<string> _allocatedDelegateNames = new HashSet<string>();
|
||||
|
||||
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<MethodKey, CallInfo> _callMethods = new Dictionary<MethodKey, CallInfo>();
|
||||
|
||||
public ModuleDelegateProxyAllocator(GroupByModuleEntityManager moduleEntityManager, EncryptionScopeProvider encryptionScopeProvider, RvaDataAllocator rvaDataAllocator, CallObfuscationSettingsFacade settings)
|
||||
{
|
||||
_moduleEntityManager = moduleEntityManager;
|
||||
_encryptionScopeProvider = encryptionScopeProvider;
|
||||
_rvaDataAllocator = rvaDataAllocator;
|
||||
_settings = settings;
|
||||
_delegateTypes = new CachedDictionary<MethodSig, TypeDef>(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<CallInfo> 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<CallInfo> 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<ModuleDelegateProxyAllocator>(mod, () => new ModuleDelegateProxyAllocator(_moduleEntityManager, _encryptionScopeProvider, _rvaDataAllocator, _settings));
|
||||
}
|
||||
|
||||
public void Done()
|
||||
{
|
||||
foreach (var allocator in _moduleEntityManager.GetEntities<ModuleDelegateProxyAllocator>())
|
||||
{
|
||||
allocator.Done();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 02761bacbed8a8b489ae3e7f49f0f84a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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<Instruction> 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<Local> localVars = new List<Local>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1102cd9f03de27c4b9fde3d6a87277c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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<MethodKey>
|
||||
{
|
||||
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<ModuleCallProxyAllocator>(mod, () => new ModuleCallProxyAllocator(_encryptionScopeProvider, _settings));
|
||||
return _moduleEntityManager.GetEntity<ModuleDispatchProxyAllocator>(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<ModuleCallProxyAllocator>())
|
||||
foreach (var allocator in _moduleEntityManager.GetEntities<ModuleDispatchProxyAllocator>())
|
||||
{
|
||||
allocator.Done();
|
||||
}
|
|
@ -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<Instruction> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,15 @@ namespace Obfuz.ObfusPasses.CallObfus
|
|||
{
|
||||
public interface IObfuscator
|
||||
{
|
||||
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions);
|
||||
bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||
|
||||
void Done();
|
||||
}
|
||||
|
||||
public abstract class ObfuscatorBase : IObfuscator
|
||||
{
|
||||
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, bool needCacheCall, List<Instruction> obfuscatedInstructions);
|
||||
public abstract bool Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||
|
||||
public abstract void Done();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
using dnlib.DotNet;
|
||||
using Obfuz.Utils;
|
||||
using System;
|
||||
|
||||
namespace Obfuz.ObfusPasses.CallObfus
|
||||
{
|
||||
class MethodKey : IEquatable<MethodKey>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1193647b317b56f4b83aa080d0a17f7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -5,17 +5,26 @@ using UnityEngine;
|
|||
|
||||
namespace Obfuz.Settings
|
||||
{
|
||||
public enum ProxyMode
|
||||
{
|
||||
Dispatch,
|
||||
Delegate,
|
||||
}
|
||||
|
||||
public class CallObfuscationSettingsFacade
|
||||
{
|
||||
public List<string> ruleFiles;
|
||||
public ProxyMode proxyMode;
|
||||
public int obfuscationLevel;
|
||||
public int maxProxyMethodCountPerDispatchMethod;
|
||||
public bool obfuscateCallToMethodInMscorlib;
|
||||
public List<string> 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<string>(),
|
||||
proxyMode = proxyMode,
|
||||
obfuscationLevel = obfuscationLevel,
|
||||
maxProxyMethodCountPerDispatchMethod = maxProxyMethodCountPerDispatchMethod,
|
||||
obfuscateCallToMethodInMscorlib = obfuscateCallToMethodInMscorlib,
|
||||
ruleFiles = ruleFiles?.ToList() ?? new List<string>(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue