重构 DataVirtualizationPass,移除重复代码

backup
walon 2025-04-24 12:10:15 +08:00
parent 7eb4b57b16
commit b604810171
5 changed files with 114 additions and 143 deletions

View File

@ -37,8 +37,10 @@ namespace Obfuz.DynamicProxy
return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method); return _dynamicProxyPolicy.NeedDynamicProxyCallInMethod(method);
} }
protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> obfuscatedInstructions) protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex,
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
{ {
return false;
switch (inst.OpCode.Code) switch (inst.OpCode.Code)
{ {
case Code.Call: case Code.Call:
@ -48,7 +50,7 @@ namespace Obfuz.DynamicProxy
{ {
return false; return false;
} }
_dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, obfuscatedInstructions); _dynamicProxyObfuscator.Obfuscate(method, calledMethod, false, outputInstructions);
return true; return true;
} }
case Code.Callvirt: case Code.Callvirt:
@ -62,7 +64,7 @@ namespace Obfuz.DynamicProxy
{ {
return false; return false;
} }
_dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, obfuscatedInstructions); _dynamicProxyObfuscator.Obfuscate(method, calledMethod, true, outputInstructions);
return true; return true;
} }
default: return false; default: return false;

View File

@ -27,7 +27,7 @@ namespace Obfuz.Emit
public DynamicProxyMethodData Allocate(IMethod method) public DynamicProxyMethodData Allocate(IMethod method)
{ {
return null; return default;
} }
public void Done() public void Done()

View File

@ -1,4 +1,6 @@
using System; using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -6,12 +8,9 @@ using System.Threading.Tasks;
namespace Obfuz.ExprObfuscation namespace Obfuz.ExprObfuscation
{ {
public class ExprObfuscationPass : ObfuscationPassBase public class ExprObfuscationPass : MethodBodyObfuscationPassBase
{ {
public override void Process(ObfuscatorContext ctx)
{
}
public override void Start(ObfuscatorContext ctx) public override void Start(ObfuscatorContext ctx)
{ {
@ -22,5 +21,15 @@ namespace Obfuz.ExprObfuscation
{ {
} }
protected override bool NeedObfuscateMethod(MethodDef method)
{
return false;
}
protected override bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
{
return false;
}
} }
} }

View File

@ -35,7 +35,8 @@ namespace Obfuz
} }
protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex, List<Instruction> outputInstructions); protected abstract bool TryObfuscateInstruction(MethodDef callingMethod, Instruction inst, IList<Instruction> instructions, int instructionIndex,
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions);
private void ObfuscateData(MethodDef method) private void ObfuscateData(MethodDef method)
{ {
@ -45,18 +46,23 @@ namespace Obfuz
for (int i = 0; i < instructions.Count; i++) for (int i = 0; i < instructions.Count; i++)
{ {
Instruction inst = instructions[i]; Instruction inst = instructions[i];
totalFinalInstructions.Add(inst); outputInstructions.Clear();
if (TryObfuscateInstruction(method, inst, instructions, i, outputInstructions)) if (TryObfuscateInstruction(method, inst, instructions, i, 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
inst.OpCode = outputInstructions[0].OpCode; inst.OpCode = outputInstructions[0].OpCode;
inst.Operand = outputInstructions[0].Operand; inst.Operand = outputInstructions[0].Operand;
totalFinalInstructions.Add(inst);
for (int k = 1; k < outputInstructions.Count; k++) for (int k = 1; k < outputInstructions.Count; k++)
{ {
totalFinalInstructions.Add(outputInstructions[k]); totalFinalInstructions.Add(outputInstructions[k]);
} }
} }
else
{
totalFinalInstructions.Add(inst);
}
} }
instructions.Clear(); instructions.Clear();

View File

@ -11,7 +11,7 @@ using UnityEngine.Assertions;
namespace Obfuz.Virtualization namespace Obfuz.Virtualization
{ {
public class DataVirtualizationPass : ObfuscationPassBase public class DataVirtualizationPass : MethodBodyObfuscationPassBase
{ {
private IDataObfuscationPolicy _dataObfuscatorPolicy; private IDataObfuscationPolicy _dataObfuscatorPolicy;
private IDataObfuscator _dataObfuscator; private IDataObfuscator _dataObfuscator;
@ -27,159 +27,113 @@ namespace Obfuz.Virtualization
_dataObfuscator.Stop(); _dataObfuscator.Stop();
} }
public override void Process(ObfuscatorContext ctx) protected override bool NeedObfuscateMethod(MethodDef method)
{ {
foreach (var ass in ctx.assemblies) return _dataObfuscatorPolicy.NeedObfuscateMethod(method);
{
// 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$") || !_dataObfuscatorPolicy.NeedObfuscateMethod(method))
{
continue;
}
// TODO if isGeneratedBy Obfuscator, continue
ObfuscateData(method);
}
}
}
} }
private void ObfuscateData(MethodDef method) protected override bool TryObfuscateInstruction(MethodDef method, Instruction inst, IList<Instruction> instructions, int instructionIndex,
List<Instruction> outputInstructions, List<Instruction> totalFinalInstructions)
{ {
IList<Instruction> instructions = method.Body.Instructions; switch (inst.OpCode.OperandType)
var obfuscatedInstructions = new List<Instruction>();
var resultInstructions = new List<Instruction>();
for (int i = 0; i < instructions.Count; i++)
{ {
Instruction inst = instructions[i]; case OperandType.InlineI:
bool obfuscated = false; case OperandType.InlineI8:
switch (inst.OpCode.OperandType) case OperandType.ShortInlineI:
case OperandType.ShortInlineR:
case OperandType.InlineR:
{ {
case OperandType.InlineI: object operand = inst.Operand;
case OperandType.InlineI8: if (operand is int)
case OperandType.ShortInlineI:
case OperandType.ShortInlineR:
case OperandType.InlineR:
{ {
obfuscatedInstructions.Clear(); int value = (int)operand;
object operand = inst.Operand; if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value))
if (operand is int)
{ {
int value = (int)operand; _dataObfuscator.ObfuscateInt(method, value, outputInstructions);
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value)) return true;
{
_dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions);
obfuscated = true;
}
} }
else if (operand is sbyte)
{
int value = (sbyte)operand;
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value))
{
_dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions);
obfuscated = true;
}
}
else if (operand is byte)
{
int value = (byte)operand;
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value))
{
_dataObfuscator.ObfuscateInt(method, value, obfuscatedInstructions);
obfuscated = true;
}
}
else if (operand is long)
{
long value = (long)operand;
if (_dataObfuscatorPolicy.NeedObfuscateLong(method, value))
{
_dataObfuscator.ObfuscateLong(method, value, obfuscatedInstructions);
obfuscated = true;
}
}
else if (operand is float)
{
float value = (float)operand;
if (_dataObfuscatorPolicy.NeedObfuscateFloat(method, value))
{
_dataObfuscator.ObfuscateFloat(method, value, obfuscatedInstructions);
obfuscated = true;
}
}
else if (operand is double)
{
double value = (double)operand;
if (_dataObfuscatorPolicy.NeedObfuscateDouble(method, value))
{
_dataObfuscator.ObfuscateDouble(method, value, obfuscatedInstructions);
obfuscated = true;
}
}
break;
} }
case OperandType.InlineString: else if (operand is sbyte)
{ {
obfuscatedInstructions.Clear(); int value = (sbyte)operand;
//RuntimeHelpers.InitializeArray if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value))
string value = (string)inst.Operand;
if (_dataObfuscatorPolicy.NeedObfuscateString(method, value))
{ {
_dataObfuscator.ObfuscateString(method, value, obfuscatedInstructions); _dataObfuscator.ObfuscateInt(method, value, outputInstructions);
obfuscated = true; return true;
} }
break;
} }
case OperandType.InlineMethod: else if (operand is byte)
{ {
if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") int value = (byte)operand;
if (_dataObfuscatorPolicy.NeedObfuscateInt(method, value))
{ {
Instruction prevInst = instructions[i - 1]; _dataObfuscator.ObfuscateInt(method, value, outputInstructions);
if (prevInst.OpCode.Code == Code.Ldtoken) return true;
{
IField rvaField = (IField)prevInst.Operand;
FieldDef ravFieldDef = rvaField.ResolveFieldDefThrow();
byte[] data = ravFieldDef.InitialValue;
if (data != null && _dataObfuscatorPolicy.NeedObfuscateArray(method, data))
{
// remove prev ldtoken instruction
Assert.AreEqual(Code.Ldtoken, resultInstructions[resultInstructions.Count - 1].OpCode.Code);
resultInstructions.RemoveAt(resultInstructions.Count - 1);
_dataObfuscator.ObfuscateBytes(method, data, obfuscatedInstructions);
obfuscated = true;
}
}
} }
break;
} }
else if (operand is long)
{
long value = (long)operand;
if (_dataObfuscatorPolicy.NeedObfuscateLong(method, value))
{
_dataObfuscator.ObfuscateLong(method, value, outputInstructions);
return true;
}
}
else if (operand is float)
{
float value = (float)operand;
if (_dataObfuscatorPolicy.NeedObfuscateFloat(method, value))
{
_dataObfuscator.ObfuscateFloat(method, value, outputInstructions);
return true;
}
}
else if (operand is double)
{
double value = (double)operand;
if (_dataObfuscatorPolicy.NeedObfuscateDouble(method, value))
{
_dataObfuscator.ObfuscateDouble(method, value, outputInstructions);
return true;
}
}
return false;
} }
resultInstructions.Add(inst); case OperandType.InlineString:
if (obfuscated)
{ {
// current instruction may be the target of control flow instruction, so we can't remove it directly. //RuntimeHelpers.InitializeArray
// we replace it with nop now, then remove it in CleanUpInstructionPass string value = (string)inst.Operand;
inst.OpCode = obfuscatedInstructions[0].OpCode; if (_dataObfuscatorPolicy.NeedObfuscateString(method, value))
inst.Operand = obfuscatedInstructions[0].Operand;
for (int k = 1; k < obfuscatedInstructions.Count; k++)
{ {
resultInstructions.Add(obfuscatedInstructions[k]); _dataObfuscator.ObfuscateString(method, value, outputInstructions);
return true;
} }
return false;
} }
} case OperandType.InlineMethod:
{
instructions.Clear(); if (((IMethod)inst.Operand).FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)")
foreach (var obInst in resultInstructions) {
{ Instruction prevInst = instructions[instructionIndex - 1];
instructions.Add(obInst); if (prevInst.OpCode.Code == Code.Ldtoken)
{
IField rvaField = (IField)prevInst.Operand;
FieldDef ravFieldDef = rvaField.ResolveFieldDefThrow();
byte[] data = ravFieldDef.InitialValue;
if (data != null && _dataObfuscatorPolicy.NeedObfuscateArray(method, data))
{
// remove prev ldtoken instruction
Assert.AreEqual(Code.Ldtoken, totalFinalInstructions[totalFinalInstructions.Count - 1].OpCode.Code);
totalFinalInstructions.RemoveAt(totalFinalInstructions.Count - 1);
_dataObfuscator.ObfuscateBytes(method, data, outputInstructions);
return true;
}
}
}
return false;
}
default: return false;
} }
} }
} }