支持配置 obfuscationLevel和 obfuscationPercentage,支持advancedObfuscation::neg

dev
walon 2025-06-20 17:34:25 +08:00
parent 111d3a7dc1
commit 9c445213b5
9 changed files with 89 additions and 77 deletions

View File

@ -294,7 +294,7 @@ namespace Obfuz.Data
_moduleEntityManager = moduleEntityManager; _moduleEntityManager = moduleEntityManager;
} }
private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod) public ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod)
{ {
return _moduleEntityManager.GetEntity<ModuleConstFieldAllocator>(mod, () => new ModuleConstFieldAllocator(_encryptionScopeProvider, _rvaDataAllocator, _moduleEntityManager)); return _moduleEntityManager.GetEntity<ModuleConstFieldAllocator>(mod, () => new ModuleConstFieldAllocator(_encryptionScopeProvider, _rvaDataAllocator, _moduleEntityManager));
} }

View File

@ -6,21 +6,36 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
using UnityEditor.VersionControl;
namespace Obfuz.ObfusPasses.ExprObfus namespace Obfuz.ObfusPasses.ExprObfus
{ {
struct ObfuscationRuleData
{
public readonly ObfuscationLevel obfuscationLevel;
public readonly float obfuscationPercentage;
public ObfuscationRuleData(ObfuscationLevel level, float percentage)
{
obfuscationLevel = level;
obfuscationPercentage = percentage;
}
}
public interface IObfuscationPolicy interface IObfuscationPolicy
{ {
bool NeedObfuscate(MethodDef method); bool NeedObfuscate(MethodDef method);
ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
} }
public abstract class ObfuscationPolicyBase : IObfuscationPolicy abstract class ObfuscationPolicyBase : IObfuscationPolicy
{ {
public abstract bool NeedObfuscate(MethodDef method); public abstract bool NeedObfuscate(MethodDef method);
public abstract ObfuscationRuleData GetObfuscationRuleData(MethodDef method);
} }
public class ConfigurableObfuscationPolicy : ObfuscationPolicyBase class ConfigurableObfuscationPolicy : ObfuscationPolicyBase
{ {
class ObfuscationRule : IRule<ObfuscationRule> class ObfuscationRule : IRule<ObfuscationRule>
{ {
@ -54,6 +69,8 @@ namespace Obfuz.ObfusPasses.ExprObfus
obfuscationPercentage = 0.5f, obfuscationPercentage = 0.5f,
}; };
private ObfuscationRule _global;
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser; private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>(); private readonly Dictionary<MethodDef, ObfuscationRule> _methodRuleCache = new Dictionary<MethodDef, ObfuscationRule>();
@ -61,14 +78,32 @@ namespace Obfuz.ObfusPasses.ExprObfus
public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles) public ConfigurableObfuscationPolicy(List<string> toObfuscatedAssemblyNames, List<string> xmlConfigFiles)
{ {
_xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>( _xmlParser = new XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule>(
toObfuscatedAssemblyNames, ParseObfuscationRule, null); toObfuscatedAssemblyNames, ParseObfuscationRule, ParseGlobal);
LoadConfigs(xmlConfigFiles); LoadConfigs(xmlConfigFiles);
} }
private void LoadConfigs(List<string> configFiles) private void LoadConfigs(List<string> configFiles)
{ {
_xmlParser.LoadConfigs(configFiles); _xmlParser.LoadConfigs(configFiles);
_xmlParser.InheritParentRules(s_default);
if (_global == null)
{
_global = s_default;
}
else
{
_global.InheritParent(s_default);
}
_xmlParser.InheritParentRules(_global);
}
private void ParseGlobal(string configFile, XmlElement ele)
{
switch (ele.Name)
{
case "global": _global = ParseObfuscationRule(configFile, ele); break;
default: throw new Exception($"Invalid xml file {configFile}, unknown node {ele.Name}");
}
} }
private ObfuscationLevel ParseObfuscationLevel(string str) private ObfuscationLevel ParseObfuscationLevel(string str)
@ -105,5 +140,11 @@ namespace Obfuz.ObfusPasses.ExprObfus
ObfuscationRule rule = GetMethodObfuscationRule(method); ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscationLevel.Value > ObfuscationLevel.None; return rule.obfuscationLevel.Value > ObfuscationLevel.None;
} }
public override ObfuscationRuleData GetObfuscationRuleData(MethodDef method)
{
var rule = GetMethodObfuscationRule(method);
return new ObfuscationRuleData(rule.obfuscationLevel.Value, rule.obfuscationPercentage.Value);
}
} }
} }

View File

@ -20,18 +20,24 @@ namespace Obfuz.ObfusPasses.ExprObfus
public EncryptionScopeInfo encryptionScope; public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer; public DefaultMetadataImporter importer;
public ModuleConstFieldAllocator constFieldAllocator; public ModuleConstFieldAllocator constFieldAllocator;
public float obfuscationPercentage;
} }
class ExprObfusPass : ObfuscationMethodPassBase class ExprObfusPass : ObfuscationMethodPassBase
{ {
private readonly ExprObfuscationSettingsFacade _settings; private readonly ExprObfuscationSettingsFacade _settings;
private readonly IObfuscator _obfuscator; private readonly IObfuscator _basicObfuscator;
private readonly IObfuscator _advancedObfuscator;
private readonly IObfuscator _mostAdvancedObfuscator;
private IObfuscationPolicy _obfuscationPolicy; private IObfuscationPolicy _obfuscationPolicy;
public ExprObfusPass(ExprObfuscationSettingsFacade settings) public ExprObfusPass(ExprObfuscationSettingsFacade settings)
{ {
_settings = settings; _settings = settings;
_obfuscator = CreateObfuscator(_settings.obfuscationLevel); _basicObfuscator = new BasicObfuscator();
_advancedObfuscator = new AdvancedObfuscator();
_mostAdvancedObfuscator = new MostAdvancedObfuscator();
} }
public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus; public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus;
@ -44,14 +50,14 @@ namespace Obfuz.ObfusPasses.ExprObfus
_settings.ruleFiles); _settings.ruleFiles);
} }
private IObfuscator CreateObfuscator(ObfuscationLevel level) private IObfuscator GetObfuscator(ObfuscationLevel level)
{ {
switch (level) switch (level)
{ {
case ObfuscationLevel.None: return new NoneObfuscator(); case ObfuscationLevel.None: return null;
case ObfuscationLevel.Basic:return new BasicObfuscator(); case ObfuscationLevel.Basic: return _basicObfuscator;
case ObfuscationLevel.Advanced: return new AdvancedObfuscator(); case ObfuscationLevel.Advanced: return _advancedObfuscator;
case ObfuscationLevel.MostAdvanced: return new MostAdvancedObfuscator(); case ObfuscationLevel.MostAdvanced: return _mostAdvancedObfuscator;
default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level"); default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level");
} }
} }
@ -63,18 +69,19 @@ namespace Obfuz.ObfusPasses.ExprObfus
protected override bool NeedObfuscateMethod(MethodDef method) protected override bool NeedObfuscateMethod(MethodDef method)
{ {
return _settings.obfuscationLevel != ObfuscationLevel.None && _obfuscationPolicy.NeedObfuscate(method); return _obfuscationPolicy.NeedObfuscate(method);
} }
protected bool TryObfuscateInstruction(InstructionParameterInfo pi, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx) protected bool TryObfuscateInstruction(IObfuscator obfuscator, InstructionParameterInfo pi, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{ {
//Debug.Log($"Obfuscating instruction: {inst} in method: {ctx.method.FullName}"); //Debug.Log($"Obfuscating instruction: {inst} in method: {ctx.method.FullName}");
var localRandom = ctx.localRandom; IRandom localRandom = ctx.localRandom;
float obfuscationPercentage = ctx.obfuscationPercentage;
switch (inst.OpCode.Code) switch (inst.OpCode.Code)
{ {
case Code.Neg: case Code.Neg:
{ {
return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBasicUnaryOp(inst, pi.op1, pi.retType, outputInstructions, ctx); return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicUnaryOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
} }
case Code.Add: case Code.Add:
case Code.Sub: case Code.Sub:
@ -84,23 +91,23 @@ namespace Obfuz.ObfusPasses.ExprObfus
case Code.Rem: case Code.Rem:
case Code.Rem_Un: case Code.Rem_Un:
{ {
return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBasicBinOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx); return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBasicBinOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
} }
case Code.And: case Code.And:
case Code.Or: case Code.Or:
case Code.Xor: case Code.Xor:
{ {
return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBinBitwiseOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx); return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBinBitwiseOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
} }
case Code.Not: case Code.Not:
{ {
return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateUnaryBitwiseOp(inst, pi.op1, pi.retType, outputInstructions, ctx); return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateUnaryBitwiseOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
} }
case Code.Shl: case Code.Shl:
case Code.Shr: case Code.Shr:
case Code.Shr_Un: case Code.Shr_Un:
{ {
return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBitShiftOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx); return localRandom.NextInPercentage(obfuscationPercentage) && obfuscator.ObfuscateBitShiftOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
} }
} }
return false; return false;
@ -116,14 +123,18 @@ namespace Obfuz.ObfusPasses.ExprObfus
ObfuscationPassContext ctx = ObfuscationPassContext.Current; ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method); var calc = new EvalStackCalculator(method);
var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module); var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module);
var ruleData = _obfuscationPolicy.GetObfuscationRuleData(method);
var obfuscator = GetObfuscator(ruleData.obfuscationLevel);
var obfusMethodCtx = new ObfusMethodContext var obfusMethodCtx = new ObfusMethodContext
{ {
method = method, method = method,
evalStackCalculator = calc, evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method), localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope, encryptionScope = encryptionScope,
constFieldAllocator = ctx.constFieldAllocator.GetModuleAllocator(method.Module),
localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)), localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)),
importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, ctx.encryptionScopeProvider), importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, ctx.encryptionScopeProvider),
obfuscationPercentage = ruleData.obfuscationPercentage,
}; };
for (int i = 0; i < instructions.Count; i++) for (int i = 0; i < instructions.Count; i++)
{ {
@ -132,7 +143,7 @@ namespace Obfuz.ObfusPasses.ExprObfus
if (calc.TryGetParameterInfo(inst, out InstructionParameterInfo pi)) if (calc.TryGetParameterInfo(inst, out InstructionParameterInfo pi))
{ {
outputInstructions.Clear(); outputInstructions.Clear();
if (TryObfuscateInstruction(pi, inst, outputInstructions, obfusMethodCtx)) if (TryObfuscateInstruction(obfuscator, pi, inst, outputInstructions, obfusMethodCtx))
{ {
// 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

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using Obfuz.Utils; using Obfuz.Utils;
using Obfuz.Data; using Obfuz.Data;
using UnityEngine; using UnityEngine;
using UnityEngine.Assertions;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
@ -89,6 +90,7 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
// y = -x = (x * a + b) * (-ra) + b * ra; // y = -x = (x * a + b) * (-ra) + b * ra;
int a = random.NextInt() | 0x1; int a = random.NextInt() | 0x1;
int ra = MathUtil.ModInverse32(a); int ra = MathUtil.ModInverse32(a);
Assert.AreEqual(1, a * ra);
int b = random.NextInt(); int b = random.NextInt();
int b_ra = b * ra; int b_ra = b * ra;
float constProbability = 0.5f; float constProbability = 0.5f;
@ -107,6 +109,7 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
// y = -x = (x * a + b) * (-ra) + b * ra; // y = -x = (x * a + b) * (-ra) + b * ra;
long a = random.NextLong() | 0x1L; long a = random.NextLong() | 0x1L;
long ra = MathUtil.ModInverse64(a); long ra = MathUtil.ModInverse64(a);
Assert.AreEqual(1L, a * ra);
long b = random.NextLong(); long b = random.NextLong();
long b_ra = b * ra; long b_ra = b * ra;
float constProbability = 0.5f; float constProbability = 0.5f;

View File

@ -1,35 +0,0 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System.Collections.Generic;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{
class NoneObfuscator : ObfuscatorBase
{
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return false;
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return false;
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return false;
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return false;
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return false;
}
}
}

View File

@ -4,31 +4,15 @@ using UnityEngine;
namespace Obfuz.Settings namespace Obfuz.Settings
{ {
public enum ObfuscationLevel
{
None = 0,
Basic = 1,
Advanced = 2,
MostAdvanced = 3
}
public class ExprObfuscationSettingsFacade public class ExprObfuscationSettingsFacade
{ {
public ObfuscationLevel obfuscationLevel;
public float obfuscationPercentage;
public List<string> ruleFiles; public List<string> ruleFiles;
} }
[Serializable] [Serializable]
public class ExprObfuscationSettings public class ExprObfuscationSettings
{ {
[Tooltip("Obfuscation level")]
public ObfuscationLevel obfuscationLevel = ObfuscationLevel.Basic;
[Tooltip("percentage of obfuscation, 0.0 - 1.0, 0.5 means 50% of expressions will be obfuscated")]
[Range(0.1f, 1.0f)]
public float obfuscationPercentage = 0.5f;
[Tooltip("rule config xml files")] [Tooltip("rule config xml files")]
public string[] ruleFiles; public string[] ruleFiles;
@ -36,8 +20,6 @@ namespace Obfuz.Settings
{ {
return new ExprObfuscationSettingsFacade return new ExprObfuscationSettingsFacade
{ {
obfuscationLevel = obfuscationLevel,
obfuscationPercentage = obfuscationPercentage,
ruleFiles = new List<string>(ruleFiles), ruleFiles = new List<string>(ruleFiles),
}; };
} }

View File

@ -0,0 +1,10 @@
namespace Obfuz.Settings
{
public enum ObfuscationLevel
{
None = 0,
Basic = 1,
Advanced = 2,
MostAdvanced = 3
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: ca85b81393732984a9019bdbe5d9e9a7 guid: dd8e1281c6c9bcd419fecc67980cb673
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -50,7 +50,7 @@
public float NextFloat() public float NextFloat()
{ {
return (float)((double)NextInt() / int.MaxValue); return (float)((double)(uint)NextInt() / uint.MaxValue);
} }
public bool NextInPercentage(float percentage) public bool NextInPercentage(float percentage)