支持部分 AdvancedObfuscator

dev
walon 2025-06-20 16:56:14 +08:00
parent 4bc6cf923f
commit 111d3a7dc1
13 changed files with 350 additions and 100 deletions

View File

@ -1,4 +1,5 @@
using NUnit.Framework; using NUnit.Framework;
using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -14,7 +15,7 @@ namespace Obfuz.EncryptionVM.Instructions
{ {
_multiValue = addValue; _multiValue = addValue;
_opKeyIndex = opKeyIndex; _opKeyIndex = opKeyIndex;
_revertMultiValue = (int)ModInverseOdd((uint)addValue); _revertMultiValue = MathUtil.ModInverse32(addValue);
Verify(); Verify();
} }
@ -24,23 +25,6 @@ namespace Obfuz.EncryptionVM.Instructions
Assert.AreEqual(a, a * _multiValue * _revertMultiValue); Assert.AreEqual(a, a * _multiValue * _revertMultiValue);
} }
public static uint ModInverseOdd(uint a)
{
if (a % 2 == 0)
throw new ArgumentException("Input must be an odd number.", nameof(a));
uint x = 1; // 初始解x₀ = 1 (mod 2)
for (int i = 0; i < 5; i++) // 迭代5次2^1 → 2^32
{
int shift = 2 << i; // 当前模数为 2^(2^(i+1))
ulong mod = 1UL << shift; // 使用 ulong 避免溢出
ulong ax = (ulong)a * x; // 计算 a*x64位避免截断
ulong term = (2 - ax) % mod;
x = (uint)((x * term) % mod); // 更新 x结果截断为 uint
}
return x; // 最终解为 x₅ mod 2^32
}
public override int Encrypt(int value, int[] secretKey, int salt) public override int Encrypt(int value, int[] secretKey, int salt)
{ {
return value * _multiValue + secretKey[_opKeyIndex] + salt; return value * _multiValue + secretKey[_opKeyIndex] + salt;

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
{ {
@ -17,7 +18,7 @@ namespace Obfuz.EncryptionVM.Instructions
public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue) public MultipleRotateXorInstruction(int multipleValue, int index1, int rotateBitNum, int xorValue)
{ {
_multipleValue = multipleValue; _multipleValue = multipleValue;
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue); _revertMultipleValue = MathUtil.ModInverse32(multipleValue);
_index1 = index1; _index1 = index1;
_rotateBitNum = rotateBitNum; _rotateBitNum = rotateBitNum;
_xorValue = xorValue; _xorValue = xorValue;

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
{ {
@ -17,7 +18,7 @@ namespace Obfuz.EncryptionVM.Instructions
public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum) public MultipleXorRotateInstruction(int multipleValue, int index1, int xorValue, int rotateBitNum)
{ {
_multipleValue = multipleValue; _multipleValue = multipleValue;
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue); _revertMultipleValue = MathUtil.ModInverse32(multipleValue);
_index1 = index1; _index1 = index1;
_rotateBitNum = rotateBitNum; _rotateBitNum = rotateBitNum;
_xorValue = xorValue; _xorValue = xorValue;

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using Obfuz.Utils;
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions namespace Obfuz.EncryptionVM.Instructions
{ {
@ -17,7 +18,7 @@ namespace Obfuz.EncryptionVM.Instructions
public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum) public XorMultipleRotateInstruction(int xorValue, int multipleValue, int index1, int rotateBitNum)
{ {
_multipleValue = multipleValue; _multipleValue = multipleValue;
_revertMultipleValue = (int)MultipleInstruction.ModInverseOdd((uint)multipleValue); _revertMultipleValue = MathUtil.ModInverse32(multipleValue);
_index1 = index1; _index1 = index1;
_rotateBitNum = rotateBitNum; _rotateBitNum = rotateBitNum;
_xorValue = xorValue; _xorValue = xorValue;

View File

@ -1,5 +1,6 @@
using dnlib.DotNet; using dnlib.DotNet;
using Obfuz.Conf; using Obfuz.Conf;
using Obfuz.Settings;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -23,12 +24,15 @@ namespace Obfuz.ObfusPasses.ExprObfus
{ {
class ObfuscationRule : IRule<ObfuscationRule> class ObfuscationRule : IRule<ObfuscationRule>
{ {
public bool? obfuscate; public ObfuscationLevel? obfuscationLevel;
public float? obfuscationPercentage;
public void InheritParent(ObfuscationRule parentRule) public void InheritParent(ObfuscationRule parentRule)
{ {
if (obfuscate == null) if (obfuscationLevel == null)
obfuscate = parentRule.obfuscate; obfuscationLevel = parentRule.obfuscationLevel;
if (obfuscationPercentage == null)
obfuscationPercentage = parentRule.obfuscationPercentage;
} }
} }
@ -46,7 +50,8 @@ namespace Obfuz.ObfusPasses.ExprObfus
private static readonly ObfuscationRule s_default = new ObfuscationRule() private static readonly ObfuscationRule s_default = new ObfuscationRule()
{ {
obfuscate = false, obfuscationLevel = ObfuscationLevel.None,
obfuscationPercentage = 0.5f,
}; };
private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser; private readonly XmlAssemblyTypeMethodRuleParser<AssemblySpec, TypeSpec, MethodSpec, ObfuscationRule> _xmlParser;
@ -66,12 +71,21 @@ namespace Obfuz.ObfusPasses.ExprObfus
_xmlParser.InheritParentRules(s_default); _xmlParser.InheritParentRules(s_default);
} }
private ObfuscationLevel ParseObfuscationLevel(string str)
{
return (ObfuscationLevel)Enum.Parse(typeof(ObfuscationLevel), str);
}
private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele) private ObfuscationRule ParseObfuscationRule(string configFile, XmlElement ele)
{ {
var rule = new ObfuscationRule(); var rule = new ObfuscationRule();
if (ele.HasAttribute("obfuscate")) if (ele.HasAttribute("obfuscationLevel"))
{ {
rule.obfuscate = ConfigUtil.ParseBool(ele.GetAttribute("obfuscate")); rule.obfuscationLevel = ParseObfuscationLevel(ele.GetAttribute("obfuscationLevel"));
}
if (ele.HasAttribute("obfuscationPercentage"))
{
rule.obfuscationPercentage = float.Parse(ele.GetAttribute("obfuscationPercentage"));
} }
return rule; return rule;
} }
@ -89,7 +103,7 @@ namespace Obfuz.ObfusPasses.ExprObfus
public override bool NeedObfuscate(MethodDef method) public override bool NeedObfuscate(MethodDef method)
{ {
ObfuscationRule rule = GetMethodObfuscationRule(method); ObfuscationRule rule = GetMethodObfuscationRule(method);
return rule.obfuscate == true; return rule.obfuscationLevel.Value > ObfuscationLevel.None;
} }
} }
} }

View File

@ -1,5 +1,6 @@
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Data;
using Obfuz.Emit; using Obfuz.Emit;
using Obfuz.ObfusPasses.ExprObfus.Obfuscators; using Obfuz.ObfusPasses.ExprObfus.Obfuscators;
using Obfuz.Settings; using Obfuz.Settings;
@ -10,15 +11,27 @@ using UnityEngine;
namespace Obfuz.ObfusPasses.ExprObfus namespace Obfuz.ObfusPasses.ExprObfus
{ {
class ObfusMethodContext
{
public MethodDef method;
public EvalStackCalculator evalStackCalculator;
public LocalVariableAllocator localVariableAllocator;
public IRandom localRandom;
public EncryptionScopeInfo encryptionScope;
public DefaultMetadataImporter importer;
public ModuleConstFieldAllocator constFieldAllocator;
}
class ExprObfusPass : ObfuscationMethodPassBase class ExprObfusPass : ObfuscationMethodPassBase
{ {
private readonly ExprObfuscationSettingsFacade _settings; private readonly ExprObfuscationSettingsFacade _settings;
private readonly IObfuscator _obfuscator;
private IObfuscationPolicy _obfuscationPolicy; private IObfuscationPolicy _obfuscationPolicy;
private IObfuscator _obfuscator;
public ExprObfusPass(ExprObfuscationSettingsFacade settings) public ExprObfusPass(ExprObfuscationSettingsFacade settings)
{ {
_settings = settings; _settings = settings;
_obfuscator = CreateObfuscator(_settings.obfuscationLevel);
} }
public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus; public override ObfuscationPassType Type => ObfuscationPassType.ExprObfus;
@ -29,17 +42,16 @@ namespace Obfuz.ObfusPasses.ExprObfus
_obfuscationPolicy = new ConfigurableObfuscationPolicy( _obfuscationPolicy = new ConfigurableObfuscationPolicy(
ctx.coreSettings.assembliesToObfuscate, ctx.coreSettings.assembliesToObfuscate,
_settings.ruleFiles); _settings.ruleFiles);
_obfuscator = CreateObfuscator(ctx.encryptionScopeProvider, ctx.moduleEntityManager, _settings.obfuscationLevel);
} }
private IObfuscator CreateObfuscator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager, ObfuscationLevel level) private IObfuscator CreateObfuscator(ObfuscationLevel level)
{ {
switch (level) switch (level)
{ {
case ObfuscationLevel.None: return new NoneObfuscator(); case ObfuscationLevel.None: return new NoneObfuscator();
case ObfuscationLevel.Basic:return new BasicObfuscator(encryptionScopeProvider, moduleEntityManager); case ObfuscationLevel.Basic:return new BasicObfuscator();
case ObfuscationLevel.Advanced: return new AdvancedObfuscator(encryptionScopeProvider, moduleEntityManager); case ObfuscationLevel.Advanced: return new AdvancedObfuscator();
case ObfuscationLevel.MostAdvanced: return new MostAdvancedObfuscator(encryptionScopeProvider, moduleEntityManager); case ObfuscationLevel.MostAdvanced: return new MostAdvancedObfuscator();
default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level"); default: throw new System.ArgumentOutOfRangeException(nameof(level), level, "Unknown obfuscation level");
} }
} }
@ -54,14 +66,15 @@ namespace Obfuz.ObfusPasses.ExprObfus
return _settings.obfuscationLevel != ObfuscationLevel.None && _obfuscationPolicy.NeedObfuscate(method); return _settings.obfuscationLevel != ObfuscationLevel.None && _obfuscationPolicy.NeedObfuscate(method);
} }
protected bool TryObfuscateInstruction(MethodDef callingMethod, InstructionParameterInfo pi, LocalVariableAllocator localVariableAllocator, IRandom localRandom, Instruction inst, List<Instruction> outputInstructions) protected bool TryObfuscateInstruction(InstructionParameterInfo pi, Instruction inst, List<Instruction> outputInstructions, ObfusMethodContext ctx)
{ {
Debug.Log($"Obfuscating instruction: {inst} in method: {callingMethod.FullName}"); //Debug.Log($"Obfuscating instruction: {inst} in method: {ctx.method.FullName}");
var localRandom = ctx.localRandom;
switch (inst.OpCode.Code) switch (inst.OpCode.Code)
{ {
case Code.Neg: case Code.Neg:
{ {
return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBasicUnaryOp(callingMethod, inst, pi.op1, pi.retType, localVariableAllocator, outputInstructions); return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBasicUnaryOp(inst, pi.op1, pi.retType, outputInstructions, ctx);
} }
case Code.Add: case Code.Add:
case Code.Sub: case Code.Sub:
@ -71,23 +84,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(callingMethod, inst, pi.op1, pi.op2, pi.retType, localVariableAllocator, outputInstructions); return localRandom.NextInPercentage(_settings.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(callingMethod, inst, pi.op1, pi.op2, pi.retType, localVariableAllocator, outputInstructions); return localRandom.NextInPercentage(_settings.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(callingMethod, inst, pi.op1, pi.retType, localVariableAllocator, outputInstructions); return localRandom.NextInPercentage(_settings.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(callingMethod, inst, pi.op1, pi.op2, pi.retType, localVariableAllocator, outputInstructions); return localRandom.NextInPercentage(_settings.obfuscationPercentage) && _obfuscator.ObfuscateBitShiftOp(inst, pi.op1, pi.op2, pi.retType, outputInstructions, ctx);
} }
} }
return false; return false;
@ -96,13 +109,22 @@ namespace Obfuz.ObfusPasses.ExprObfus
protected override void ObfuscateData(MethodDef method) protected override void ObfuscateData(MethodDef method)
{ {
Debug.Log($"Obfuscating method: {method.FullName} with ExprObfusPass"); Debug.Log($"Obfuscating method: {method.FullName} with ExprObfusPass");
var calc = new EvalStackCalculator(method);
var localVarAllocator = new LocalVariableAllocator(method);
IList<Instruction> instructions = method.Body.Instructions; IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>(); var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>(); var totalFinalInstructions = new List<Instruction>();
var encryptionScope = ObfuscationPassContext.Current.encryptionScopeProvider.GetScope(method.Module);
var localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)); ObfuscationPassContext ctx = ObfuscationPassContext.Current;
var calc = new EvalStackCalculator(method);
var encryptionScope = ctx.encryptionScopeProvider.GetScope(method.Module);
var obfusMethodCtx = new ObfusMethodContext
{
method = method,
evalStackCalculator = calc,
localVariableAllocator = new LocalVariableAllocator(method),
encryptionScope = encryptionScope,
localRandom = encryptionScope.localRandomCreator(MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(method)),
importer = ctx.moduleEntityManager.GetDefaultModuleMetadataImporter(method.Module, ctx.encryptionScopeProvider),
};
for (int i = 0; i < instructions.Count; i++) for (int i = 0; i < instructions.Count; i++)
{ {
Instruction inst = instructions[i]; Instruction inst = instructions[i];
@ -110,7 +132,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(method, pi, localVarAllocator, localRandom, inst, outputInstructions)) if (TryObfuscateInstruction(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

@ -7,23 +7,23 @@ namespace Obfuz.ObfusPasses.ExprObfus
{ {
interface IObfuscator interface IObfuscator
{ {
bool ObfuscateBasicUnaryOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBasicBinOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateUnaryBitwiseOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBinBitwiseOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
bool ObfuscateBitShiftOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
} }
abstract class ObfuscatorBase : IObfuscator abstract class ObfuscatorBase : IObfuscator
{ {
public abstract bool ObfuscateBasicUnaryOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); public abstract bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBasicBinOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); public abstract bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateUnaryBitwiseOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); public abstract bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBinBitwiseOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); public abstract bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
public abstract bool ObfuscateBitShiftOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts); public abstract bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx);
} }
} }

View File

@ -1,12 +1,190 @@
using Obfuz.Emit; using dnlib.DotNet.Emit;
using dnlib.DotNet;
using Obfuz.Emit;
using System.Collections.Generic;
using Obfuz.Utils;
using Obfuz.Data;
using UnityEngine;
namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
class AdvancedObfuscator : BasicObfuscator class AdvancedObfuscator : BasicObfuscator
{ {
public AdvancedObfuscator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
: base(encryptionScopeProvider, moduleEntityManager) private void LoadConstInt(int a, IRandom random, float constProbability, ModuleConstFieldAllocator constFieldAllocator, List<Instruction> outputInsts)
{ {
Instruction inst;
if (random.NextInPercentage(constProbability))
{
inst = Instruction.Create(OpCodes.Ldc_I4, a);
}
else
{
FieldDef field = constFieldAllocator.Allocate(a);
inst = Instruction.Create(OpCodes.Ldsfld, field);
}
outputInsts.Add(inst);
}
private void LoadConstLong(long a, IRandom random, float constProbability, ModuleConstFieldAllocator constFieldAllocator, List<Instruction> outputInsts)
{
Instruction inst;
if (random.NextInPercentage(constProbability))
{
inst = Instruction.Create(OpCodes.Ldc_I8, a);
}
else
{
FieldDef field = constFieldAllocator.Allocate(a);
inst = Instruction.Create(OpCodes.Ldsfld, field);
}
outputInsts.Add(inst);
}
private void LoadConstFloat(float a, IRandom random, float constProbability, ModuleConstFieldAllocator constFieldAllocator, List<Instruction> outputInsts)
{
Instruction inst;
if (random.NextInPercentage(constProbability))
{
inst = Instruction.Create(OpCodes.Ldc_R4, a);
}
else
{
FieldDef field = constFieldAllocator.Allocate(a);
inst = Instruction.Create(OpCodes.Ldsfld, field);
}
outputInsts.Add(inst);
}
private void LoadConstDouble(double a, IRandom random, float constProbability, ModuleConstFieldAllocator constFieldAllocator, List<Instruction> outputInsts)
{
Instruction inst;
if (random.NextInPercentage(constProbability))
{
inst = Instruction.Create(OpCodes.Ldc_R8, a);
}
else
{
FieldDef field = constFieldAllocator.Allocate(a);
inst = Instruction.Create(OpCodes.Ldsfld, field);
}
outputInsts.Add(inst);
}
public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
DefaultMetadataImporter importer = ctx.importer;
EncryptionScopeInfo encryptionScope = ctx.encryptionScope;
IRandom random = ctx.localRandom;
ModuleConstFieldAllocator constFieldAllocator = ctx.constFieldAllocator;
switch (inst.OpCode.Code)
{
case Code.Neg:
{
switch (op)
{
case EvalDataType.Int32:
{
// y = -x = (x * a + b) * (-ra) + b * ra;
int a = random.NextInt() | 0x1;
int ra = MathUtil.ModInverse32(a);
int b = random.NextInt();
int b_ra = b * ra;
float constProbability = 0.5f;
LoadConstInt(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
LoadConstInt(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
LoadConstInt(-ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
LoadConstInt(b_ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case EvalDataType.Int64:
{
// y = -x = (x * a + b) * (-ra) + b * ra;
long a = random.NextLong() | 0x1L;
long ra = MathUtil.ModInverse64(a);
long b = random.NextLong();
long b_ra = b * ra;
float constProbability = 0.5f;
LoadConstLong(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
LoadConstLong(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
LoadConstLong(-ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
LoadConstLong(b_ra, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
return true;
}
case EvalDataType.Float:
{
// y = -x = (x + a) * b; a = 0.0f, b = 1.0f,
float a = 0.0f;
float b = -1.0f;
float constProbability = 0f;
LoadConstFloat(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
LoadConstFloat(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
case EvalDataType.Double:
{
// y = -x = (x + a) * b; a = 0.0, b = -1.0,
double a = 0.0;
double b = -1.0;
float constProbability = 0f;
LoadConstDouble(a, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Add));
LoadConstDouble(b, random, constProbability, constFieldAllocator, outputInsts);
outputInsts.Add(Instruction.Create(OpCodes.Mul));
return true;
}
}
return true;
}
default: return false;
}
}
public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (op1 != op2)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false;
}
return base.ObfuscateBasicBinOp(inst, op1, op2, ret, outputInsts, ctx);
}
public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
return base.ObfuscateUnaryBitwiseOp(inst, op, ret, outputInsts, ctx);
}
public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (op1 != op2)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false;
}
return base.ObfuscateBinBitwiseOp(inst, op1 , op2, ret, outputInsts, ctx);
}
public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{
if (op2 != EvalDataType.Int32)
{
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator.");
return false;
}
return base.ObfuscateBitShiftOp(inst, op1, op2 , ret, outputInsts, ctx);
} }
} }
} }

View File

@ -14,20 +14,6 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
class BasicObfuscator : ObfuscatorBase class BasicObfuscator : ObfuscatorBase
{ {
private readonly EncryptionScopeProvider _encryptionScopeProvider;
private readonly GroupByModuleEntityManager _moduleEntityManager;
public BasicObfuscator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
{
_encryptionScopeProvider = encryptionScopeProvider;
_moduleEntityManager = moduleEntityManager;
}
private DefaultMetadataImporter GetModuleMetadataImporter(ModuleDef module)
{
return _moduleEntityManager.GetDefaultModuleMetadataImporter(module, _encryptionScopeProvider);
}
private IMethod GetMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1) private IMethod GetMethod(DefaultMetadataImporter importer, Code code, EvalDataType op1)
{ {
switch (code) switch (code)
@ -183,10 +169,9 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
} }
} }
public override bool ObfuscateBasicUnaryOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
DefaultMetadataImporter importer = GetModuleMetadataImporter(method.Module); IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op);
IMethod opMethod = GetMethod(importer, inst.OpCode.Code, op);
if (opMethod == null) if (opMethod == null)
{ {
return false; return false;
@ -195,15 +180,14 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
return true; return true;
} }
public override bool ObfuscateBasicBinOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
if (op1 != op2) if (op1 != op2)
{ {
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator."); Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false; return false;
} }
DefaultMetadataImporter importer = GetModuleMetadataImporter(method.Module); IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op1);
IMethod opMethod = GetMethod(importer, inst.OpCode.Code, op1);
if (opMethod == null) if (opMethod == null)
{ {
return false; return false;
@ -212,10 +196,9 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
return true; return true;
} }
public override bool ObfuscateUnaryBitwiseOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
DefaultMetadataImporter importer = GetModuleMetadataImporter(method.Module); IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op);
IMethod opMethod = GetMethod(importer, inst.OpCode.Code, op);
if (opMethod == null) if (opMethod == null)
{ {
return false; return false;
@ -224,15 +207,14 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
return true; return true;
} }
public override bool ObfuscateBinBitwiseOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
if (op1 != op2) if (op1 != op2)
{ {
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator."); Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with different operand types: op1={op1}, op2={op2}, ret={ret}. This is a limitation of the BasicObfuscator.");
return false; return false;
} }
DefaultMetadataImporter importer = GetModuleMetadataImporter(method.Module); IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op1);
IMethod opMethod = GetMethod(importer, inst.OpCode.Code, op1);
if (opMethod == null) if (opMethod == null)
{ {
return false; return false;
@ -241,15 +223,14 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
return true; return true;
} }
public override bool ObfuscateBitShiftOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
if (op2 != EvalDataType.Int32) if (op2 != EvalDataType.Int32)
{ {
Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator."); Debug.LogWarning($"BasicObfuscator: Cannot obfuscate binary operation {inst.OpCode.Code} with operand type {op2}. This is a limitation of the BasicObfuscator.");
return false; return false;
} }
DefaultMetadataImporter importer = GetModuleMetadataImporter(method.Module); IMethod opMethod = GetMethod(ctx.importer, inst.OpCode.Code, op1);
IMethod opMethod = GetMethod(importer, inst.OpCode.Code, op1);
if (opMethod == null) if (opMethod == null)
{ {
return false; return false;

View File

@ -4,9 +4,5 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
class MostAdvancedObfuscator : AdvancedObfuscator class MostAdvancedObfuscator : AdvancedObfuscator
{ {
public MostAdvancedObfuscator(EncryptionScopeProvider encryptionScopeProvider, GroupByModuleEntityManager moduleEntityManager)
: base(encryptionScopeProvider, moduleEntityManager)
{
}
} }
} }

View File

@ -7,27 +7,27 @@ namespace Obfuz.ObfusPasses.ExprObfus.Obfuscators
{ {
class NoneObfuscator : ObfuscatorBase class NoneObfuscator : ObfuscatorBase
{ {
public override bool ObfuscateBasicUnaryOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBasicUnaryOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
return false; return false;
} }
public override bool ObfuscateBasicBinOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBasicBinOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
return false; return false;
} }
public override bool ObfuscateUnaryBitwiseOp(MethodDef method, Instruction inst, EvalDataType op, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateUnaryBitwiseOp(Instruction inst, EvalDataType op, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
return false; return false;
} }
public override bool ObfuscateBinBitwiseOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBinBitwiseOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
return false; return false;
} }
public override bool ObfuscateBitShiftOp(MethodDef method, Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, LocalVariableAllocator localVariableAllocator, List<Instruction> outputInsts) public override bool ObfuscateBitShiftOp(Instruction inst, EvalDataType op1, EvalDataType op2, EvalDataType ret, List<Instruction> outputInsts, ObfusMethodContext ctx)
{ {
return false; return false;
} }

61
Editor/Utils/MathUtil.cs Normal file
View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.Utils
{
internal static class MathUtil
{
//public static int ModInverseOdd32(int sa)
//{
// uint a = (uint)sa;
// if (a % 2 == 0)
// throw new ArgumentException("Input must be an odd number.", nameof(a));
// uint x = 1; // 初始解x₀ = 1 (mod 2)
// for (int i = 0; i < 5; i++) // 迭代5次2^1 → 2^32
// {
// int shift = 2 << i; // 当前模数为 2^(2^(i+1))
// ulong mod = 1UL << shift; // 使用 ulong 避免溢出
// ulong ax = (ulong)a * x; // 计算 a*x64位避免截断
// ulong term = (2 - ax) % mod;
// x = (uint)((x * term) % mod); // 更新 x结果截断为 uint
// }
// return (int)x; // 最终解为 x₅ mod 2^32
//}
public static int ModInverse32(int sa)
{
uint x = (uint)sa;
if ((x & 1) == 0)
throw new ArgumentException("x must be odd (coprime with 2^32)");
uint inv = x;
inv = inv * (2 - x * inv); // 1
inv = inv * (2 - x * inv); // 2
inv = inv * (2 - x * inv); // 3
inv = inv * (2 - x * inv); // 4
inv = inv * (2 - x * inv); // 5
return (int)inv;
}
public static long ModInverse64(long sx)
{
ulong x = (ulong)sx;
if ((x & 1) == 0)
throw new ArgumentException("x must be odd (coprime with 2^64)");
ulong inv = x;
inv *= 2 - x * inv; // 1
inv *= 2 - x * inv; // 2
inv *= 2 - x * inv; // 3
inv *= 2 - x * inv; // 4
inv *= 2 - x * inv; // 5
inv *= 2 - x * inv; // 6
return (long)inv;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d5962b5e88adac40a2b1c65a8d304bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: