添加DynamicProxyPass

backup
walon 2025-04-24 11:58:22 +08:00
parent 79bf659e65
commit 7eb4b57b16
12 changed files with 332 additions and 1 deletions

View File

@ -0,0 +1,22 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.DynamicProxy
{
public class ConfigDynamicProxyPolicy : DynamicProxyPolicyBase
{
public override bool NeedDynamicProxyCallInMethod(MethodDef method)
{
return true;
}
public override bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir)
{
return true;
}
}
}

View File

@ -0,0 +1,14 @@
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using System.Collections.Generic;
namespace Obfuz.DynamicProxy
{
public class DefaultDynamicProxyObfuscator : DynamicProxyObfuscatorBase
{
public override void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions)
{
// Default implementation does nothing
}
}
}

View File

@ -0,0 +1,11 @@
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using System.Collections.Generic;
namespace Obfuz.DynamicProxy
{
public abstract class DynamicProxyObfuscatorBase : IDynamicProxyObfuscator
{
public abstract void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
}
}

View File

@ -0,0 +1,72 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Virtualization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using UnityEngine.Assertions;
namespace Obfuz.DynamicProxy
{
public class DynamicProxyPass : MethodBodyObfuscationPassBase
{
private readonly IDynamicProxyPolicy _dynamicProxyPolicy;
private readonly IDynamicProxyObfuscator _dynamicProxyObfuscator;
public DynamicProxyPass()
{
_dynamicProxyPolicy = new ConfigDynamicProxyPolicy();
_dynamicProxyObfuscator = new DefaultDynamicProxyObfuscator();
}
public override void Stop(ObfuscatorContext ctx)
{
}
public override void Start(ObfuscatorContext ctx)
{
}
protected override bool NeedObfuscateMethod(MethodDef method)
{
return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method);
}
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> obfuscatedInstructions)
{
switch (inst.OpCode.Code)
{
case Code.Call:
{
IMethod calledMethod = (IMethod)inst.Operand;
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, false))
{
return false;
}
_dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, obfuscatedInstructions);
return true;
}
case Code.Callvirt:
{
if (instructionIndex > 0 && instructions[instructionIndex - 1].OpCode.Code == Code.Constrained)
{
return false;
}
IMethod calledMethod = (IMethod)inst.Operand;
if (!_dynamicProxyPolicy.NeedDynamicProxyCalledMethod(calledMethod, true))
{
return false;
}
_dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, obfuscatedInstructions);
return true;
}
default: return false;
}
}
}
}

View File

@ -0,0 +1,11 @@
using dnlib.DotNet;
namespace Obfuz.DynamicProxy
{
public abstract class DynamicProxyPolicyBase : IDynamicProxyPolicy
{
public abstract bool NeedDynamicProxyCallInMethod(MethodDef method);
public abstract bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir);
}
}

View File

@ -0,0 +1,15 @@
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.DynamicProxy
{
public interface IDynamicProxyObfuscator
{
void Obfuscate(MethodDef callingMethod, IMethod calledMethod, bool callVir, List<Instruction> obfuscatedInstructions);
}
}

View File

@ -0,0 +1,16 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.DynamicProxy
{
public interface IDynamicProxyPolicy
{
bool NeedDynamicProxyCallInMethod(MethodDef method);
bool NeedDynamicProxyCalledMethod(IMethod method, bool callVir);
}
}

View File

@ -0,0 +1,69 @@
using dnlib.DotNet;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.Emit
{
public struct DynamicProxyMethodData
{
public MethodDef proxyMethod;
public int methodId;
}
class ModuleDynamicProxyMethodAllocator
{
private readonly ModuleDef _module;
private readonly IRandom _random;
public ModuleDynamicProxyMethodAllocator(ModuleDef module, IRandom random)
{
_module = module;
_random = random;
}
public DynamicProxyMethodData Allocate(IMethod method)
{
return null;
}
public void Done()
{
}
}
public class DynamicProxyMethodAllocator
{
private readonly IRandom _random;
private readonly Dictionary<ModuleDef, ModuleDynamicProxyMethodAllocator> _moduleAllocators = new Dictionary<ModuleDef, ModuleDynamicProxyMethodAllocator>();
public DynamicProxyMethodAllocator(IRandom random)
{
_random = random;
}
public DynamicProxyMethodData Allocate(ModuleDef mod, IMethod method)
{
if (!_moduleAllocators.TryGetValue(mod, out var allocator))
{
allocator = new ModuleDynamicProxyMethodAllocator(mod, _random);
_moduleAllocators.Add(mod, allocator);
}
return allocator.Allocate(method);
}
public void Done()
{
foreach (var allocator in _moduleAllocators.Values)
{
allocator.Done();
}
_moduleAllocators.Clear();
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.ExprObfuscation
{
public class ExprObfuscationPass : ObfuscationPassBase
{
public override void Process(ObfuscatorContext ctx)
{
}
public override void Start(ObfuscatorContext ctx)
{
}
public override void Stop(ObfuscatorContext ctx)
{
}
}
}

View File

@ -0,0 +1,69 @@
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using System.Collections.Generic;
using System.Linq;
namespace Obfuz
{
public abstract class MethodBodyObfuscationPassBase : ObfuscationPassBase
{
protected abstract bool NeedObfuscateMethod(MethodDef method);
public override void Process(ObfuscatorContext ctx)
{
foreach (var ass in ctx.assemblies)
{
// ToArray to avoid modify list exception
foreach (TypeDef type in ass.module.GetTypes().ToArray())
{
if (type.Name.StartsWith("$Obfuz$"))
{
continue;
}
// ToArray to avoid modify list exception
foreach (MethodDef method in type.Methods.ToArray())
{
if (!method.HasBody || method.Name.StartsWith("$Obfuz$") || !NeedObfuscateMethod(method))
{
continue;
}
// TODO if isGeneratedBy Obfuscator, continue
ObfuscateData(method);
}
}
}
}
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions);
private void ObfuscateData(MethodDef method)
{
IList<Instruction> instructions = method.Body.Instructions;
var outputInstructions = new List<Instruction>();
var totalFinalInstructions = new List<Instruction>();
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
totalFinalInstructions.Add(inst);
if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions))
{
// current instruction may be the target of control flow instruction, so we can't remove it directly.
// we replace it with nop now, then remove it in CleanUpInstructionPass
inst.OpCode = outputInstructions[0].OpCode;
inst.Operand = outputInstructions[0].Operand;
for (int k = 1; k < outputInstructions.Count; k++)
{
totalFinalInstructions.Add(outputInstructions[k]);
}
}
}
instructions.Clear();
foreach (var obInst in totalFinalInstructions)
{
instructions.Add(obInst);
}
}
}
}

View File

@ -1,4 +1,6 @@
namespace Obfuz
using Obfuz.Virtualization;
namespace Obfuz
{
public abstract class ObfuscationPassBase : IObfuscationPass
{

View File

@ -1,4 +1,6 @@
using dnlib.DotNet;
using Obfuz.DynamicProxy;
using Obfuz.ExprObfuscation;
using Obfuz.Rename;
using Obfuz.Virtualization;
using System;
@ -44,6 +46,8 @@ namespace Obfuz
_obfuscationAssemblyNames = options.obfuscationAssemblyNames;
_assemblyCache = new AssemblyCache(new PathAssemblyResolver(options.assemblySearchDirs.ToArray()));
_pipeline.AddPass(new DynamicProxyPass());
_pipeline.AddPass(new ExprObfuscationPass());
_pipeline.AddPass(new DataVirtualizationPass());
_pipeline.AddPass(new RenameSymbolPass());
_pipeline.AddPass(new CleanUpInstructionPass());