完善CallObfus
parent
83c0b921e3
commit
8c48e6bf61
|
@ -37,7 +37,7 @@ namespace Obfuz.ObfusPasses
|
||||||
|
|
||||||
|
|
||||||
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex,
|
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, BasicBlock block, int instructionIndex,
|
||||||
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
|
IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
|
||||||
|
|
||||||
private void ObfuscateData(MethodDef method)
|
private void ObfuscateData(MethodDef method)
|
||||||
{
|
{
|
||||||
|
@ -52,7 +52,7 @@ namespace Obfuz.ObfusPasses
|
||||||
Instruction inst = instructions[i];
|
Instruction inst = instructions[i];
|
||||||
BasicBlock block = bbc.GetBasicBlockByInstruction(inst);
|
BasicBlock block = bbc.GetBasicBlockByInstruction(inst);
|
||||||
outputInstructions.Clear();
|
outputInstructions.Clear();
|
||||||
if (TryObfuscateInstruction(method, inst, block, i, outputInstructions, totalFinalInstructions))
|
if (TryObfuscateInstruction(method, inst, block, i, instructions, outputInstructions, totalFinalInstructions))
|
||||||
{
|
{
|
||||||
// current instruction may be the target of control flow instruction, so we can't remove it directly.
|
// 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
|
// we replace it with nop now, then remove it in CleanUpInstructionPass
|
||||||
|
|
|
@ -13,19 +13,20 @@ using Obfuz.Settings;
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
public class CallObfusPass : InstructionObfuscationPassBase
|
public class CallObfusPass : BasicBlockObfuscationPassBase
|
||||||
{
|
{
|
||||||
|
private readonly List<string> _configFiles;
|
||||||
private readonly IRandom _random;
|
private readonly IRandom _random;
|
||||||
private readonly IEncryptor _encryptor;
|
private readonly IEncryptor _encryptor;
|
||||||
private readonly ICallObfusPolicy _dynamicProxyPolicy;
|
private readonly IObfuscator _dynamicProxyObfuscator;
|
||||||
private readonly ICallObfuscator _dynamicProxyObfuscator;
|
private IObfuscationPolicy _dynamicProxyPolicy;
|
||||||
|
|
||||||
public CallObfusPass(CallObfusSettings settings)
|
public CallObfusPass(CallObfusSettings settings)
|
||||||
{
|
{
|
||||||
|
_configFiles = settings.configFiles.ToList();
|
||||||
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
|
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
|
||||||
_encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D });
|
_encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D });
|
||||||
_dynamicProxyPolicy = new ConfigurableCallObfusPolicy();
|
_dynamicProxyObfuscator = new DefaultCallProxyObfuscator(_random, _encryptor);
|
||||||
_dynamicProxyObfuscator = new DefaultProxyCallObfuscator(_random, _encryptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Stop(ObfuscationPassContext ctx)
|
public override void Stop(ObfuscationPassContext ctx)
|
||||||
|
@ -35,7 +36,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
|
||||||
public override void Start(ObfuscationPassContext ctx)
|
public override void Start(ObfuscationPassContext ctx)
|
||||||
{
|
{
|
||||||
|
_dynamicProxyPolicy = new ConfigurableObfuscationPolicy(ctx.toObfuscatedAssemblyNames, _configFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool NeedObfuscateMethod(MethodDef method)
|
protected override bool NeedObfuscateMethod(MethodDef method)
|
||||||
|
@ -43,8 +44,8 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method);
|
return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex,
|
protected override bool TryObfuscateInstruction(MethodDef callerMethod, Instruction inst, BasicBlock block,
|
||||||
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
int instructionIndex, IList<Instruction> globalInstructions, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
{
|
{
|
||||||
IMethod calledMethod = inst.Operand as IMethod;
|
IMethod calledMethod = inst.Operand as IMethod;
|
||||||
if (calledMethod == null || !calledMethod.IsMethod)
|
if (calledMethod == null || !calledMethod.IsMethod)
|
||||||
|
@ -56,32 +57,35 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool callVir;
|
||||||
switch (inst.OpCode.Code)
|
switch (inst.OpCode.Code)
|
||||||
{
|
{
|
||||||
case Code.Call:
|
case Code.Call:
|
||||||
{
|
{
|
||||||
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, false))
|
callVir = false;
|
||||||
{
|
break;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, outputInstructions);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
case Code.Callvirt:
|
case Code.Callvirt:
|
||||||
{
|
{
|
||||||
if (instructionIndex > 0 && instructions[instructionIndex - 1].OpCode.Code == Code.Constrained)
|
if (instructionIndex > 0 && globalInstructions[instructionIndex - 1].OpCode.Code == Code.Constrained)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, true))
|
callVir = true;
|
||||||
{
|
break;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, outputInstructions);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObfuscationCachePolicy cachePolicy = _dynamicProxyPolicy.GetMethodObfuscationCachePolicy(callerMethod);
|
||||||
|
bool cachedCallIndex = block.inLoop ? cachePolicy.cacheInLoop : cachePolicy.cacheNotInLoop;
|
||||||
|
|
||||||
|
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(callerMethod, calledMethod, callVir, cachedCallIndex))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_dynamicProxyObfuscator.Obfuscate(callerMethod, calledMethod, callVir, outputInstructions);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
|
||||||
{
|
|
||||||
public abstract class CallObfusPolicyBase : ICallObfusPolicy
|
|
||||||
{
|
|
||||||
public abstract bool NeedDynamicProxyCallInMethod(MethodDef method);
|
|
||||||
|
|
||||||
public abstract bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -138,7 +138,7 @@ namespace Obfuz.ObfusPasses.CallObfus
|
||||||
}
|
}
|
||||||
case ThisArgType.ValueType:
|
case ThisArgType.ValueType:
|
||||||
{
|
{
|
||||||
methodSig.Params.Insert(0, _module.CorLibTypes.UIntPtr);
|
methodSig.Params.Insert(0, _module.CorLibTypes.IntPtr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
|
||||||
{
|
|
||||||
public class ConfigurableCallObfusPolicy : CallObfusPolicyBase
|
|
||||||
{
|
|
||||||
public override bool NeedDynamicProxyCallInMethod(MethodDef method)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir)
|
|
||||||
{
|
|
||||||
|
|
||||||
ITypeDefOrRef declaringType = method.DeclaringType;
|
|
||||||
TypeDef typeDef = declaringType.ResolveTypeDef();
|
|
||||||
// doesn't proxy call if the method is a delegate
|
|
||||||
if (typeDef != null)
|
|
||||||
{
|
|
||||||
// need configurable
|
|
||||||
if (typeDef.Module.IsCoreLibraryModule == true)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (typeDef.IsDelegate)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// doesn't proxy call if the method is a constructor
|
|
||||||
if (method.Name == ".ctor")
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// special handle
|
|
||||||
// don't proxy call for List<T>.Enumerator GetEnumerator()
|
|
||||||
if (method.Name == "GetEnumerator")
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,524 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using Obfuz.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
|
||||||
|
{
|
||||||
|
private readonly List<string> _toObfuscatedAssemblyNames;
|
||||||
|
|
||||||
|
|
||||||
|
class WhiteListAssembly
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public bool? obfuscateNone;
|
||||||
|
public List<WhiteListType> types = new List<WhiteListType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WhiteListType
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public bool? obfuscateNone;
|
||||||
|
public List<WhiteListMethod> methods = new List<WhiteListMethod>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class WhiteListMethod
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObfuscationRule
|
||||||
|
{
|
||||||
|
public bool? disableObfuscation;
|
||||||
|
public bool? obfuscateCallInLoop;
|
||||||
|
public bool? cacheCallIndexInLoop;
|
||||||
|
public bool? cacheCallIndexNotLoop;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class AssemblySpec
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public ObfuscationRule rule;
|
||||||
|
public List<TypeSpec> types = new List<TypeSpec>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeSpec
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public ObfuscationRule rule;
|
||||||
|
public List<MethodSpec> methods = new List<MethodSpec>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodSpec
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public NameMatcher nameMatcher;
|
||||||
|
public ObfuscationRule rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
||||||
|
{
|
||||||
|
disableObfuscation = false,
|
||||||
|
obfuscateCallInLoop = true,
|
||||||
|
cacheCallIndexInLoop = true,
|
||||||
|
cacheCallIndexNotLoop = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
private ObfuscationRule _global;
|
||||||
|
private readonly List<WhiteListAssembly> _whiteListAssemblies = new List<WhiteListAssembly>();
|
||||||
|
private readonly Dictionary<string, AssemblySpec> _assemblySpecs = new Dictionary<string, AssemblySpec>();
|
||||||
|
|
||||||
|
private readonly Dictionary<IMethod, bool> _whiteListMethodCache = new Dictionary<IMethod, bool>(MethodEqualityComparer.CompareDeclaringTypes);
|
||||||
|
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
||||||
|
|
||||||
|
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
|
||||||
|
{
|
||||||
|
_toObfuscatedAssemblyNames = toObfuscatedAssemblyNames;
|
||||||
|
LoadConfigs(xmlConfigFiles);
|
||||||
|
InheritParentRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConfigs(List<string> configFiles)
|
||||||
|
{
|
||||||
|
if (configFiles == null || configFiles.Count == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"ConfigurableObfuscationPolicy::LoadConfigs configFiles is empty, using default policy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var configFile in configFiles)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(configFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"ObfusSettings.callObfusSettings.configFiles contains empty file name");
|
||||||
|
}
|
||||||
|
LoadConfig(configFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadConfig(string configFile)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(configFile))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"ConfigurableObfuscationPolicy::LoadConfig configFile is empty, using default policy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Log($"ConfigurableObfuscationPolicy::LoadConfig {configFile}");
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
doc.Load(configFile);
|
||||||
|
var root = doc.DocumentElement;
|
||||||
|
if (root.Name != "obfuz")
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, root name should be 'obfuz'");
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in root.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "global": _global = ParseObfuscationRule(ele, true); break;
|
||||||
|
case "whitelist": ParseWhitelist(ele); break;
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
AssemblySpec assSpec = ParseAssembly(ele);
|
||||||
|
string name = assSpec.name;
|
||||||
|
if (!_toObfuscatedAssemblyNames.Contains(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames");
|
||||||
|
}
|
||||||
|
if (_assemblySpecs.ContainsKey(name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} is duplicated");
|
||||||
|
}
|
||||||
|
_assemblySpecs.Add(name, assSpec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InheritParentRules()
|
||||||
|
{
|
||||||
|
if (_global == null)
|
||||||
|
{
|
||||||
|
_global = s_default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_global.InheritParent(s_default);
|
||||||
|
}
|
||||||
|
foreach (AssemblySpec assSpec in _assemblySpecs.Values)
|
||||||
|
{
|
||||||
|
assSpec.rule.InheritParent(_global);
|
||||||
|
foreach (TypeSpec typeSpec in assSpec.types)
|
||||||
|
{
|
||||||
|
typeSpec.rule.InheritParent(assSpec.rule);
|
||||||
|
foreach (MethodSpec methodSpec in typeSpec.methods)
|
||||||
|
{
|
||||||
|
methodSpec.rule.InheritParent(typeSpec.rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule ParseObfuscationRule(XmlElement ele, bool parseWhitelist)
|
||||||
|
{
|
||||||
|
var rule = new ObfuscationRule();
|
||||||
|
if (ele.HasAttribute("disableObfuscation"))
|
||||||
|
{
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseWhitelist(XmlElement ruleEle)
|
||||||
|
{
|
||||||
|
foreach (XmlNode xmlNode in ruleEle.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(xmlNode is XmlElement childEle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (childEle.Name)
|
||||||
|
{
|
||||||
|
case "assembly":
|
||||||
|
{
|
||||||
|
var ass = ParseWhiteListtAssembly(childEle);
|
||||||
|
_whiteListAssemblies.Add(ass);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {childEle.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhiteListAssembly ParseWhiteListtAssembly(XmlElement element)
|
||||||
|
{
|
||||||
|
var ass = new WhiteListAssembly();
|
||||||
|
ass.name = element.GetAttribute("name");
|
||||||
|
ass.nameMatcher = new NameMatcher(ass.name);
|
||||||
|
if (element.HasAttribute("obfuscateNone"))
|
||||||
|
{
|
||||||
|
ass.obfuscateNone = ConfigUtil.ParseBool(element.GetAttribute("obfuscateNone"));
|
||||||
|
}
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
ass.types.Add(ParseWhiteListType(ele));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhiteListType ParseWhiteListType(XmlElement element)
|
||||||
|
{
|
||||||
|
var type = new WhiteListType();
|
||||||
|
type.name = element.GetAttribute("name");
|
||||||
|
type.nameMatcher = new NameMatcher(type.name);
|
||||||
|
if (element.HasAttribute("obfuscateNone"))
|
||||||
|
{
|
||||||
|
type.obfuscateNone = ConfigUtil.ParseBool(element.GetAttribute("obfuscateNone"));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "method":
|
||||||
|
{
|
||||||
|
type.methods.Add(ParseWhiteListMethod(ele));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WhiteListMethod ParseWhiteListMethod(XmlElement element)
|
||||||
|
{
|
||||||
|
var method = new WhiteListMethod();
|
||||||
|
method.name = element.GetAttribute("name");
|
||||||
|
method.nameMatcher = new NameMatcher(method.name);
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AssemblySpec ParseAssembly(XmlElement element)
|
||||||
|
{
|
||||||
|
var assemblySpec = new AssemblySpec();
|
||||||
|
assemblySpec.name = element.GetAttribute("name");
|
||||||
|
if (string.IsNullOrEmpty(assemblySpec.name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, assembly name is empty");
|
||||||
|
}
|
||||||
|
assemblySpec.rule = ParseObfuscationRule(element, false);
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
assemblySpec.types.Add(ParseType(ele));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assemblySpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSpec ParseType(XmlElement element)
|
||||||
|
{
|
||||||
|
var typeSpec = new TypeSpec();
|
||||||
|
typeSpec.name = element.GetAttribute("name");
|
||||||
|
typeSpec.nameMatcher = new NameMatcher(typeSpec.name);
|
||||||
|
if (string.IsNullOrEmpty(typeSpec.name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, type name is empty");
|
||||||
|
}
|
||||||
|
typeSpec.rule = ParseObfuscationRule(element, false);
|
||||||
|
foreach (XmlNode node in element.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement ele))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ele.Name)
|
||||||
|
{
|
||||||
|
case "method":
|
||||||
|
typeSpec.methods.Add(ParseMethod(ele));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSpec ParseMethod(XmlElement element)
|
||||||
|
{
|
||||||
|
var methodSpec = new MethodSpec();
|
||||||
|
methodSpec.name = element.GetAttribute("name");
|
||||||
|
methodSpec.nameMatcher = new NameMatcher(methodSpec.name);
|
||||||
|
if (string.IsNullOrEmpty(methodSpec.name))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid xml file, method name is empty");
|
||||||
|
}
|
||||||
|
methodSpec.rule = ParseObfuscationRule(element, false);
|
||||||
|
return methodSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule ComputeMethodObfuscationRule(MethodDef method)
|
||||||
|
{
|
||||||
|
var assemblyName = method.DeclaringType.Module.Assembly.Name;
|
||||||
|
if (!_assemblySpecs.TryGetValue(assemblyName, out var assSpec))
|
||||||
|
{
|
||||||
|
return _global;
|
||||||
|
}
|
||||||
|
string declaringTypeName = method.DeclaringType.FullName;
|
||||||
|
foreach (var typeSpec in assSpec.types)
|
||||||
|
{
|
||||||
|
if (typeSpec.nameMatcher.IsMatch(declaringTypeName))
|
||||||
|
{
|
||||||
|
foreach (var methodSpec in typeSpec.methods)
|
||||||
|
{
|
||||||
|
if (methodSpec.nameMatcher.IsMatch(method.Name))
|
||||||
|
{
|
||||||
|
return methodSpec.rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeSpec.rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assSpec.rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObfuscationRule GetMethodObfuscationRule(MethodDef method)
|
||||||
|
{
|
||||||
|
if (!_methodRuleCache.TryGetValue(method, out var rule))
|
||||||
|
{
|
||||||
|
rule = ComputeMethodObfuscationRule(method);
|
||||||
|
_methodRuleCache[method] = rule;
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedDynamicProxyCallInMethod(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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ComputeIsInWhiteList(IMethod calledMethod)
|
||||||
|
{
|
||||||
|
ITypeDefOrRef declaringType = calledMethod.DeclaringType;
|
||||||
|
TypeSig declaringTypeSig = calledMethod.DeclaringType.ToTypeSig();
|
||||||
|
declaringTypeSig = declaringTypeSig.RemovePinnedAndModifiers();
|
||||||
|
switch (declaringTypeSig.ElementType)
|
||||||
|
{
|
||||||
|
case ElementType.ValueType:
|
||||||
|
case ElementType.Class:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ElementType.GenericInst:
|
||||||
|
{
|
||||||
|
if (MetaUtil.ContainsContainsGenericParameter(calledMethod))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDef typeDef = declaringType.ResolveTypeDef();
|
||||||
|
|
||||||
|
if (typeDef.IsDelegate || typeDef.IsEnum)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
string assName = typeDef.Module.Assembly.Name;
|
||||||
|
string typeFullName = typeDef.FullName;
|
||||||
|
string methodName = calledMethod.Name;
|
||||||
|
|
||||||
|
// doesn't proxy call if the method is a constructor
|
||||||
|
if (methodName == ".ctor")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// special handle
|
||||||
|
// don't proxy call for List<T>.Enumerator GetEnumerator()
|
||||||
|
if (methodName == "GetEnumerator")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var ass in _whiteListAssemblies)
|
||||||
|
{
|
||||||
|
if (!ass.nameMatcher.IsMatch(assName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ass.obfuscateNone == true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach (var type in ass.types)
|
||||||
|
{
|
||||||
|
if (!type.nameMatcher.IsMatch(typeFullName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type.obfuscateNone == true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach (var method in type.methods)
|
||||||
|
{
|
||||||
|
if (method.nameMatcher.IsMatch(methodName))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsInWhiteList(IMethod method)
|
||||||
|
{
|
||||||
|
if (!_whiteListMethodCache.TryGetValue(method, out var isWhiteList))
|
||||||
|
{
|
||||||
|
isWhiteList = ComputeIsInWhiteList(method);
|
||||||
|
_whiteListMethodCache.Add(method, isWhiteList);
|
||||||
|
}
|
||||||
|
return isWhiteList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool NeedDynamicProxyCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop)
|
||||||
|
{
|
||||||
|
if (IsInWhiteList(calledMethod))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ObfuscationRule rule = GetMethodObfuscationRule(callerMethod);
|
||||||
|
if (currentInLoop && rule.obfuscateCallInLoop == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,13 +6,13 @@ using Obfuz.Emit;
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
public class DefaultProxyCallObfuscator : CallObfuscatorBase
|
public class DefaultCallProxyObfuscator : ObfuscatorBase
|
||||||
{
|
{
|
||||||
private readonly IRandom _random;
|
private readonly IRandom _random;
|
||||||
private readonly IEncryptor _encryptor;
|
private readonly IEncryptor _encryptor;
|
||||||
private readonly CallProxyAllocator _proxyCallAllocator;
|
private readonly CallProxyAllocator _proxyCallAllocator;
|
||||||
|
|
||||||
public DefaultProxyCallObfuscator(IRandom random, IEncryptor encryptor)
|
public DefaultCallProxyObfuscator(IRandom random, IEncryptor encryptor)
|
||||||
{
|
{
|
||||||
_random = random;
|
_random = random;
|
||||||
_encryptor = encryptor;
|
_encryptor = encryptor;
|
|
@ -1,16 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
|
||||||
{
|
|
||||||
public interface ICallObfusPolicy
|
|
||||||
{
|
|
||||||
bool NeedDynamicProxyCallInMethod(MethodDef method);
|
|
||||||
|
|
||||||
bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
|
||||||
|
public struct ObfuscationCachePolicy
|
||||||
|
{
|
||||||
|
public bool cacheInLoop;
|
||||||
|
public bool cacheNotInLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IObfuscationPolicy
|
||||||
|
{
|
||||||
|
bool NeedDynamicProxyCallInMethod(MethodDef method);
|
||||||
|
|
||||||
|
ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method);
|
||||||
|
|
||||||
|
bool NeedDynamicProxyCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
public interface ICallObfuscator
|
public interface IObfuscator
|
||||||
{
|
{
|
||||||
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
|
||||||
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
|
{
|
||||||
|
public abstract class ObfuscationPolicyBase : IObfuscationPolicy
|
||||||
|
{
|
||||||
|
public abstract bool NeedDynamicProxyCallInMethod(MethodDef method);
|
||||||
|
|
||||||
|
public abstract ObfuscationCachePolicy GetMethodObfuscationCachePolicy(MethodDef method);
|
||||||
|
|
||||||
|
public abstract bool NeedDynamicProxyCalledMethod(MethodDef callerMethod, IMethod calledMethod, bool callVir, bool currentInLoop);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Obfuz.ObfusPasses.CallObfus
|
namespace Obfuz.ObfusPasses.CallObfus
|
||||||
{
|
{
|
||||||
public abstract class CallObfuscatorBase : ICallObfuscator
|
public abstract class ObfuscatorBase : IObfuscator
|
||||||
{
|
{
|
||||||
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
|
||||||
public abstract void Done();
|
public abstract void Done();
|
|
@ -109,14 +109,14 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
public string name;
|
public string name;
|
||||||
public NameMatcher nameMatcher;
|
public NameMatcher nameMatcher;
|
||||||
public ObfuscationRule rule;
|
public ObfuscationRule rule;
|
||||||
public List<MethodSpec> methodSpecs = new List<MethodSpec>();
|
public List<MethodSpec> methods = new List<MethodSpec>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssemblySpec
|
class AssemblySpec
|
||||||
{
|
{
|
||||||
public string name;
|
public string name;
|
||||||
public ObfuscationRule rule;
|
public ObfuscationRule rule;
|
||||||
public List<TypeSpec> typeSpecs = new List<TypeSpec>();
|
public List<TypeSpec> types = new List<TypeSpec>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
private static readonly ObfuscationRule s_default = new ObfuscationRule()
|
||||||
|
@ -140,17 +140,35 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
private readonly Dictionary<string, AssemblySpec> _assemblySpecs = new Dictionary<string, AssemblySpec>();
|
private readonly Dictionary<string, AssemblySpec> _assemblySpecs = new Dictionary<string, AssemblySpec>();
|
||||||
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
|
||||||
|
|
||||||
public ConfigurableEncryptPolicy(List<string> toObfuscatedAssemblyNames, string xmlConfigFile)
|
public ConfigurableEncryptPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
|
||||||
{
|
{
|
||||||
_toObfuscatedAssemblyNames = toObfuscatedAssemblyNames;
|
_toObfuscatedAssemblyNames = toObfuscatedAssemblyNames;
|
||||||
LoadConfig(xmlConfigFile);
|
LoadConfigs(xmlConfigFiles);
|
||||||
InheritParentRules();
|
InheritParentRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadConfigs(List<string> configFiles)
|
||||||
|
{
|
||||||
|
if (configFiles == null || configFiles.Count == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"ConfigurableObfuscationPolicy::LoadConfigs configFiles is empty, using default policy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var configFile in configFiles)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(configFile))
|
||||||
|
{
|
||||||
|
throw new Exception($"ObfuzSettings.constEncryptSettings.configFiles contains empty file name");
|
||||||
|
}
|
||||||
|
LoadConfig(configFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadConfig(string configFile)
|
private void LoadConfig(string configFile)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(configFile))
|
if (string.IsNullOrEmpty(configFile))
|
||||||
{
|
{
|
||||||
|
Debug.LogWarning($"ConfigurableObfuscationPolicy::LoadConfig configFile is empty, using default policy");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Debug.Log($"ConfigurableObfuscationPolicy::LoadConfig {configFile}");
|
Debug.Log($"ConfigurableObfuscationPolicy::LoadConfig {configFile}");
|
||||||
|
@ -176,7 +194,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
string name = assSpec.name;
|
string name = assSpec.name;
|
||||||
if (!_toObfuscatedAssemblyNames.Contains(name))
|
if (!_toObfuscatedAssemblyNames.Contains(name))
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file {configFile}, assembly name {name} is in toObfuscatedAssemblyNames");
|
throw new Exception($"Invalid xml file {configFile}, assembly name {name} isn't in toObfuscatedAssemblyNames");
|
||||||
}
|
}
|
||||||
if (_assemblySpecs.ContainsKey(name))
|
if (_assemblySpecs.ContainsKey(name))
|
||||||
{
|
{
|
||||||
|
@ -203,10 +221,10 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
foreach (AssemblySpec assSpec in _assemblySpecs.Values)
|
foreach (AssemblySpec assSpec in _assemblySpecs.Values)
|
||||||
{
|
{
|
||||||
assSpec.rule.InheritParent(_global);
|
assSpec.rule.InheritParent(_global);
|
||||||
foreach (TypeSpec typeSpec in assSpec.typeSpecs)
|
foreach (TypeSpec typeSpec in assSpec.types)
|
||||||
{
|
{
|
||||||
typeSpec.rule.InheritParent(assSpec.rule);
|
typeSpec.rule.InheritParent(assSpec.rule);
|
||||||
foreach (MethodSpec methodSpec in typeSpec.methodSpecs)
|
foreach (MethodSpec methodSpec in typeSpec.methods)
|
||||||
{
|
{
|
||||||
methodSpec.rule.InheritParent(typeSpec.rule);
|
methodSpec.rule.InheritParent(typeSpec.rule);
|
||||||
}
|
}
|
||||||
|
@ -214,109 +232,61 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ParseBool(string str)
|
|
||||||
{
|
|
||||||
switch (str.ToLowerInvariant())
|
|
||||||
{
|
|
||||||
case "1":
|
|
||||||
case "true": return true;
|
|
||||||
case "0":
|
|
||||||
case "false": return false;
|
|
||||||
default: throw new Exception($"Invalid bool value {str}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int? ParseNullableInt(string str)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return int.Parse(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long? ParseNullableLong(string str)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return long.Parse(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float? ParseNullableFloat(string str)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return float.Parse(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double? ParseNullableDouble(string str)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return double.Parse(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ObfuscationRule ParseObfuscationRule(XmlElement ele, bool parseWhitelist)
|
private ObfuscationRule ParseObfuscationRule(XmlElement ele, bool parseWhitelist)
|
||||||
{
|
{
|
||||||
var rule = new ObfuscationRule();
|
var rule = new ObfuscationRule();
|
||||||
if (ele.HasAttribute("disableEncrypt"))
|
if (ele.HasAttribute("disableEncrypt"))
|
||||||
{
|
{
|
||||||
rule.disableEncrypt = ParseBool(ele.GetAttribute("disableEncrypt"));
|
rule.disableEncrypt = ConfigUtil.ParseBool(ele.GetAttribute("disableEncrypt"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptInt"))
|
if (ele.HasAttribute("encryptInt"))
|
||||||
{
|
{
|
||||||
rule.encryptInt = ParseBool(ele.GetAttribute("encryptInt"));
|
rule.encryptInt = ConfigUtil.ParseBool(ele.GetAttribute("encryptInt"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptLong"))
|
if (ele.HasAttribute("encryptLong"))
|
||||||
{
|
{
|
||||||
rule.encryptLong = ParseBool(ele.GetAttribute("encryptLong"));
|
rule.encryptLong = ConfigUtil.ParseBool(ele.GetAttribute("encryptLong"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptFloat"))
|
if (ele.HasAttribute("encryptFloat"))
|
||||||
{
|
{
|
||||||
rule.encryptFloat = ParseBool(ele.GetAttribute("encryptFloat"));
|
rule.encryptFloat = ConfigUtil.ParseBool(ele.GetAttribute("encryptFloat"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptDouble"))
|
if (ele.HasAttribute("encryptDouble"))
|
||||||
{
|
{
|
||||||
rule.encryptDouble = ParseBool(ele.GetAttribute("encryptDouble"));
|
rule.encryptDouble = ConfigUtil.ParseBool(ele.GetAttribute("encryptDouble"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptBytes"))
|
if (ele.HasAttribute("encryptBytes"))
|
||||||
{
|
{
|
||||||
rule.encryptArray = ParseBool(ele.GetAttribute("encryptArray"));
|
rule.encryptArray = ConfigUtil.ParseBool(ele.GetAttribute("encryptArray"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptString"))
|
if (ele.HasAttribute("encryptString"))
|
||||||
{
|
{
|
||||||
rule.encryptString = ParseBool(ele.GetAttribute("encryptString"));
|
rule.encryptString = ConfigUtil.ParseBool(ele.GetAttribute("encryptString"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ele.HasAttribute("encryptConstInLoop"))
|
if (ele.HasAttribute("encryptConstInLoop"))
|
||||||
{
|
{
|
||||||
rule.encryptConstInLoop = ParseBool(ele.GetAttribute("encryptConstInLoop"));
|
rule.encryptConstInLoop = ConfigUtil.ParseBool(ele.GetAttribute("encryptConstInLoop"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("encryptStringInLoop"))
|
if (ele.HasAttribute("encryptStringInLoop"))
|
||||||
{
|
{
|
||||||
rule.encryptStringInLoop = ParseBool(ele.GetAttribute("encryptStringInLoop"));
|
rule.encryptStringInLoop = ConfigUtil.ParseBool(ele.GetAttribute("encryptStringInLoop"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("cacheConstInLoop"))
|
if (ele.HasAttribute("cacheConstInLoop"))
|
||||||
{
|
{
|
||||||
rule.cacheConstInLoop = ParseBool(ele.GetAttribute("cacheConstInLoop"));
|
rule.cacheConstInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheConstInLoop"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("cacheConstNotInLoop"))
|
if (ele.HasAttribute("cacheConstNotInLoop"))
|
||||||
{
|
{
|
||||||
rule.cacheConstNotInLoop = ParseBool(ele.GetAttribute("cacheConstNotInLoop"));
|
rule.cacheConstNotInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheConstNotInLoop"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("cacheStringInLoop"))
|
if (ele.HasAttribute("cacheStringInLoop"))
|
||||||
{
|
{
|
||||||
rule.cacheStringInLoop = ParseBool(ele.GetAttribute("cacheStringInLoop"));
|
rule.cacheStringInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheStringInLoop"));
|
||||||
}
|
}
|
||||||
if (ele.HasAttribute("cacheStringNotInLoop"))
|
if (ele.HasAttribute("cacheStringNotInLoop"))
|
||||||
{
|
{
|
||||||
rule.cacheStringNotInLoop = ParseBool(ele.GetAttribute("cacheStringNotInLoop"));
|
rule.cacheStringNotInLoop = ConfigUtil.ParseBool(ele.GetAttribute("cacheStringNotInLoop"));
|
||||||
}
|
}
|
||||||
if (parseWhitelist)
|
if (parseWhitelist)
|
||||||
{
|
{
|
||||||
|
@ -367,7 +337,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file, int-range {value} is invalid");
|
throw new Exception($"Invalid xml file, int-range {value} is invalid");
|
||||||
}
|
}
|
||||||
rule.notEncryptIntRanges.Add(new NumberRange<int>(ParseNullableInt(parts[0]), ParseNullableInt(parts[1])));
|
rule.notEncryptIntRanges.Add(new NumberRange<int>(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "long-range":
|
case "long-range":
|
||||||
|
@ -377,7 +347,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file, long-range {value} is invalid");
|
throw new Exception($"Invalid xml file, long-range {value} is invalid");
|
||||||
}
|
}
|
||||||
rule.notEncryptLongRanges.Add(new NumberRange<long>(ParseNullableLong(parts[0]), ParseNullableLong(parts[1])));
|
rule.notEncryptLongRanges.Add(new NumberRange<long>(ConfigUtil.ParseNullableLong(parts[0]), ConfigUtil.ParseNullableLong(parts[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "float-range":
|
case "float-range":
|
||||||
|
@ -387,7 +357,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file, float-range {value} is invalid");
|
throw new Exception($"Invalid xml file, float-range {value} is invalid");
|
||||||
}
|
}
|
||||||
rule.notEncryptFloatRanges.Add(new NumberRange<float>(ParseNullableFloat(parts[0]), ParseNullableFloat(parts[1])));
|
rule.notEncryptFloatRanges.Add(new NumberRange<float>(ConfigUtil.ParseNullableFloat(parts[0]), ConfigUtil.ParseNullableFloat(parts[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "double-range":
|
case "double-range":
|
||||||
|
@ -397,7 +367,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file, double-range {value} is invalid");
|
throw new Exception($"Invalid xml file, double-range {value} is invalid");
|
||||||
}
|
}
|
||||||
rule.notEncryptDoubleRanges.Add(new NumberRange<double>(ParseNullableDouble(parts[0]), ParseNullableDouble(parts[1])));
|
rule.notEncryptDoubleRanges.Add(new NumberRange<double>(ConfigUtil.ParseNullableDouble(parts[0]), ConfigUtil.ParseNullableDouble(parts[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "string-length-range":
|
case "string-length-range":
|
||||||
|
@ -407,7 +377,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file, string-length-range {value} is invalid");
|
throw new Exception($"Invalid xml file, string-length-range {value} is invalid");
|
||||||
}
|
}
|
||||||
rule.notEncryptStringLengthRanges.Add(new NumberRange<int>(ParseNullableInt(parts[0]), ParseNullableInt(parts[1])));
|
rule.notEncryptStringLengthRanges.Add(new NumberRange<int>(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "array-length-range":
|
case "array-length-range":
|
||||||
|
@ -417,7 +387,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid xml file, array-length-range {value} is invalid");
|
throw new Exception($"Invalid xml file, array-length-range {value} is invalid");
|
||||||
}
|
}
|
||||||
rule.notEncryptArrayLengthRanges.Add(new NumberRange<int>(ParseNullableInt(parts[0]), ParseNullableInt(parts[1])));
|
rule.notEncryptArrayLengthRanges.Add(new NumberRange<int>(ConfigUtil.ParseNullableInt(parts[0]), ConfigUtil.ParseNullableInt(parts[1])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: throw new Exception($"Invalid xml file, unknown whitelist type {type} in {childEle.Name} node");
|
default: throw new Exception($"Invalid xml file, unknown whitelist type {type} in {childEle.Name} node");
|
||||||
|
@ -447,7 +417,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
switch (ele.Name)
|
switch (ele.Name)
|
||||||
{
|
{
|
||||||
case "type":
|
case "type":
|
||||||
assemblySpec.typeSpecs.Add(ParseType(ele));
|
assemblySpec.types.Add(ParseType(ele));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
@ -475,7 +445,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
switch (ele.Name)
|
switch (ele.Name)
|
||||||
{
|
{
|
||||||
case "method":
|
case "method":
|
||||||
typeSpec.methodSpecs.Add(ParseMethod(ele));
|
typeSpec.methods.Add(ParseMethod(ele));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
throw new Exception($"Invalid xml file, unknown node {ele.Name}");
|
||||||
|
@ -506,11 +476,11 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
return _global;
|
return _global;
|
||||||
}
|
}
|
||||||
string declaringTypeName = method.DeclaringType.FullName;
|
string declaringTypeName = method.DeclaringType.FullName;
|
||||||
foreach (var typeSpec in assSpec.typeSpecs)
|
foreach (var typeSpec in assSpec.types)
|
||||||
{
|
{
|
||||||
if (typeSpec.nameMatcher.IsMatch(declaringTypeName))
|
if (typeSpec.nameMatcher.IsMatch(declaringTypeName))
|
||||||
{
|
{
|
||||||
foreach (var methodSpec in typeSpec.methodSpecs)
|
foreach (var methodSpec in typeSpec.methods)
|
||||||
{
|
{
|
||||||
if (methodSpec.nameMatcher.IsMatch(method.Name))
|
if (methodSpec.nameMatcher.IsMatch(method.Name))
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,18 +15,18 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
|
|
||||||
public class ConstEncryptPass : BasicBlockObfuscationPassBase
|
public class ConstEncryptPass : BasicBlockObfuscationPassBase
|
||||||
{
|
{
|
||||||
private readonly string _configFile;
|
private readonly List<string> _configFiles;
|
||||||
private IEncryptPolicy _dataObfuscatorPolicy;
|
private IEncryptPolicy _dataObfuscatorPolicy;
|
||||||
private IConstEncryptor _dataObfuscator;
|
private IConstEncryptor _dataObfuscator;
|
||||||
|
|
||||||
public ConstEncryptPass(ConstEncryptSettings settings)
|
public ConstEncryptPass(ConstEncryptSettings settings)
|
||||||
{
|
{
|
||||||
_configFile = settings.configFile;
|
_configFiles = settings.configFiles.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Start(ObfuscationPassContext ctx)
|
public override void Start(ObfuscationPassContext ctx)
|
||||||
{
|
{
|
||||||
_dataObfuscatorPolicy = new ConfigurableEncryptPolicy(ctx.toObfuscatedAssemblyNames, _configFile);
|
_dataObfuscatorPolicy = new ConfigurableEncryptPolicy(ctx.toObfuscatedAssemblyNames, _configFiles);
|
||||||
_dataObfuscator = new DefaultConstEncryptor();
|
_dataObfuscator = new DefaultConstEncryptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
return _dataObfuscatorPolicy.NeedObfuscateMethod(method);
|
return _dataObfuscatorPolicy.NeedObfuscateMethod(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, BasicBlock block, int instructionIndex,
|
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, BasicBlock block, int instructionIndex, IList<Instruction> globalInstructions,
|
||||||
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
|
||||||
{
|
{
|
||||||
bool currentInLoop = block.inLoop;
|
bool currentInLoop = block.inLoop;
|
||||||
|
@ -127,7 +127,7 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
|
||||||
{
|
{
|
||||||
if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)")
|
if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)")
|
||||||
{
|
{
|
||||||
Instruction prevInst = block.instructions[instructionIndex - 1];
|
Instruction prevInst = globalInstructions[instructionIndex - 1];
|
||||||
if (prevInst.OpCode.Code == Code.Ldtoken)
|
if (prevInst.OpCode.Code == Code.Ldtoken)
|
||||||
{
|
{
|
||||||
IField rvaField = (IField)prevInst.Operand;
|
IField rvaField = (IField)prevInst.Operand;
|
||||||
|
|
|
@ -3,11 +3,14 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Obfuz.Settings
|
namespace Obfuz.Settings
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CallObfusSettings
|
public class CallObfusSettings
|
||||||
{
|
{
|
||||||
|
[Tooltip("config xml files")]
|
||||||
|
public string[] configFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace Obfuz.Settings
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ConstEncryptSettings
|
public class ConstEncryptSettings
|
||||||
{
|
{
|
||||||
[Tooltip("config xml file")]
|
[Tooltip("config xml files")]
|
||||||
public string configFile;
|
public string[] configFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Obfuz.Utils
|
||||||
|
{
|
||||||
|
public static class ConfigUtil
|
||||||
|
{
|
||||||
|
|
||||||
|
public static bool ParseBool(string str)
|
||||||
|
{
|
||||||
|
switch (str.ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "1":
|
||||||
|
case "true": return true;
|
||||||
|
case "0":
|
||||||
|
case "false": return false;
|
||||||
|
default: throw new Exception($"Invalid bool value {str}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int? ParseNullableInt(string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return int.Parse(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long? ParseNullableLong(string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return long.Parse(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float? ParseNullableFloat(string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return float.Parse(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double? ParseNullableDouble(string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return double.Parse(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue