添加int相关混淆算法

backup
walon 2025-04-22 08:13:58 +08:00
parent 35df6e520d
commit e10a42f8dd
14 changed files with 211 additions and 34 deletions

View File

@ -1,9 +1,11 @@
namespace Obfuz.Virtualization
namespace Obfuz.Utils
{
public interface IRandom
{
int NextInt(int min, int max);
int NextInt(int max);
int NextInt();
}
}

View File

@ -0,0 +1,58 @@
using Obfuz.Virtualization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.Utils
{
public class RandomWithKey : IRandom
{
private readonly byte[] _key;
private readonly Random _random;
private int _nextIndex;
public RandomWithKey(byte[] key, int seed)
{
_key = key;
// TODO use key and seed to generate a random number
_random = new Random(GenerateSeed(key, seed));
}
private int GenerateSeed(byte[] key, int seed)
{
foreach (var b in key)
{
seed = seed * 31 + b;
}
return seed;
}
public int NextInt(int min, int max)
{
return min + NextInt(max - min);
}
public int NextInt(int max)
{
return (int)((uint)NextInt() % (uint)max);
}
private int GetNextKeyByte()
{
if (_nextIndex >= _key.Length)
{
_nextIndex = 0;
}
return _key[_nextIndex++];
}
public int NextInt()
{
return _random.Next() ^ GetNextKeyByte();
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -8,5 +9,34 @@ namespace Obfuz.Virtualization
{
public class ConfigDataObfuscationPolicy : DataObfuscationPolicyBase
{
public override bool NeedObfuscateMethod(MethodDef method)
{
return true;
}
public override bool NeedObfuscateInt(MethodDef method, int value)
{
return value > 10000;
}
public override bool NeedObfuscateLong(MethodDef method, long value)
{
return value > 10000;
}
public override bool NeedObfuscateFloat(MethodDef method, float value)
{
return true;
}
public override bool NeedObfuscateDouble(MethodDef method, double value)
{
return true;
}
public override bool NeedObfuscateString(MethodDef method, string value)
{
return true;
}
}
}

View File

@ -1,4 +1,6 @@
namespace Obfuz.Virtualization
using Obfuz.Utils;
namespace Obfuz.Virtualization
{
public struct CreateExpressionOptions
{

View File

@ -0,0 +1,7 @@
namespace Obfuz.Virtualization
{
public abstract class DataNodeCreatorBase : IDataNodeCreator
{
public abstract IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options);
}
}

View File

@ -2,11 +2,9 @@
{
public abstract class DataNodeBase : IDataNode
{
public DataNodeType Type { get; protected set; }
public DataNodeType Type { get; set; }
public IDataNode Expr { get; protected set; }
public abstract object Value { get; protected set; }
public abstract object Value { get; set; }
public abstract void Compile(CompileContext ctx);
}
@ -14,12 +12,12 @@
public abstract class DataNodeBase<T> : DataNodeBase
{
public T Value2 { get; protected set; }
public T Value2 { get; set; }
public override object Value
{
get => Value2;
protected set => Value2 = (T)value;
set => Value2 = (T)value;
}
}
@ -31,7 +29,7 @@
public override object Value
{
get => _value;
protected set => _value = value;
set => _value = value;
}
}
}

View File

@ -34,7 +34,7 @@ namespace Obfuz.Virtualization
{
foreach (MethodDef method in type.Methods)
{
if (!method.HasBody && !_dataObfuscatorPolicy.NeedObfuscateMethod(method))
if (!method.HasBody || !_dataObfuscatorPolicy.NeedObfuscateMethod(method))
{
continue;
}
@ -50,7 +50,7 @@ namespace Obfuz.Virtualization
IList<Instruction> instructions = method.Body.Instructions;
var obfuscatedInstructions = new List<Instruction>();
var resultInstructions = new List<Instruction>();
for (int i = 0; i < instructions.Count; )
for (int i = 0; i < instructions.Count; i++)
{
Instruction inst = instructions[i];
bool obfuscated = false;
@ -130,10 +130,8 @@ namespace Obfuz.Virtualization
}
break;
}
default: throw new NotSupportedException($"Unsupported operand type: {inst.OpCode.OperandType} for instruction: {inst}");
}
resultInstructions.Add(inst);
i++;
if (obfuscated)
{
// current instruction may be the target of control flow instruction, so we can't remove it directly.
@ -141,9 +139,14 @@ namespace Obfuz.Virtualization
inst.OpCode = OpCodes.Nop;
inst.Operand = null;
resultInstructions.AddRange(obfuscatedInstructions);
i += obfuscatedInstructions.Count + 1;
}
}
instructions.Clear();
foreach (var obInst in obfuscatedInstructions)
{
instructions.Add(obInst);
}
}
}
}

View File

@ -7,34 +7,38 @@ namespace Obfuz.Virtualization
{
public class DefaultDataObfuscator : IDataObfuscator
{
public bool ObfuscateInt(MethodDef method, int value, List<Instruction> obfuscatedInstructions)
private readonly RandomDataNodeCreator _nodeCreator = new RandomDataNodeCreator();
public void ObfuscateInt(MethodDef method, int value, List<Instruction> obfuscatedInstructions)
{
return false;
IDataNode node = _nodeCreator.CreateRandom(DataNodeType.Int32, value);
obfuscatedInstructions.Add(Instruction.CreateLdcI4(value));
}
public bool TryObfuscateLong(MethodDef method, long value, List<Instruction> obfuscatedInstructions)
public void ObfuscateLong(MethodDef method, long value, List<Instruction> obfuscatedInstructions)
{
return false;
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_I8, value));
}
public bool TryObfuscateFloat(MethodDef method, float value, List<Instruction> obfuscatedInstructions)
public void ObfuscateFloat(MethodDef method, float value, List<Instruction> obfuscatedInstructions)
{
return false;
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_R4, value));
}
public bool TryObfuscateDouble(MethodDef method, double value, List<Instruction> obfuscatedInstructions)
public void ObfuscateDouble(MethodDef method, double value, List<Instruction> obfuscatedInstructions)
{
return false;
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_R8, value));
}
public bool TryObfuscateBytes(MethodDef method, Array value, List<Instruction> obfuscatedInstructions)
public void ObfuscateBytes(MethodDef method, Array value, List<Instruction> obfuscatedInstructions)
{
return false;
throw new NotSupportedException();
//obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldc_I4, value.Length));
}
public bool TryObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions)
public void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions)
{
return false;
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldstr, value));
}
}
}

View File

@ -11,10 +11,10 @@ namespace Obfuz.Virtualization
public abstract void CreateArguments(DataNodeType type, object value, CreateExpressionOptions options, List<ConstValue> args);
public ConstExpression CreateCallable(IDataNode result, CreateExpressionOptions options)
public ConstExpression CreateCallable(DataNodeType type, object value, CreateExpressionOptions options)
{
var args = new List<ConstValue>();
CreateArguments(result.Type, result.Value, options, args);
CreateArguments(type, value, options, args);
options.depth += 1;
var argNodes = new List<IDataNode>();
@ -24,7 +24,7 @@ namespace Obfuz.Virtualization
argNodes.Add(argNode);
}
return new ConstExpression(this, args.Select(a => options.expressionCreator.CreateRandom(a.type, a.value, options)).ToList(), new ConstValue(result.Type, result.Value));
return new ConstExpression(this, args.Select(a => options.expressionCreator.CreateRandom(a.type, a.value, options)).ToList(), new ConstValue(type, value));
}
}
}

View File

@ -16,7 +16,7 @@ namespace Obfuz.Virtualization.Functions
{
int value = (int)v;
int op1 = value >= 0 ? options.random.NextInt(value) : -options.random.NextInt(-value);
int op1 = options.random.NextInt();
int op2 = value - op1;
args.Add(new ConstValue(DataNodeType.Int32, op1));
args.Add(new ConstValue(DataNodeType.Int32, op2));

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static UnityEngine.Networking.UnityWebRequest;
namespace Obfuz.Virtualization.Functions
{
public class Int32FunctionXor : Int32FunctionBase
{
public override DataNodeType ReturnType => DataNodeType.Int32;
public override void CreateArguments(DataNodeType type, object v, CreateExpressionOptions options, List<ConstValue> args)
{
int value = (int)v;
int op1 = options.random.NextInt();
int op2 = value ^ op1;
args.Add(new ConstValue(DataNodeType.Int32, op1));
args.Add(new ConstValue(DataNodeType.Int32, op2));
}
}
}

View File

@ -13,8 +13,6 @@ namespace Obfuz.Virtualization
object Value { get; }
IDataNode Expr { get; }
void Compile(CompileContext ctx);
}
}

View File

@ -4,6 +4,6 @@
{
DataNodeType ReturnType { get; }
ConstExpression CreateCallable(IDataNode result, CreateExpressionOptions options);
ConstExpression CreateCallable(DataNodeType type, object value, CreateExpressionOptions options);
}
}

View File

@ -0,0 +1,50 @@

using Obfuz.Utils;
using Obfuz.Virtualization.Functions;
using System.Collections.Generic;
namespace Obfuz.Virtualization
{
public class RandomDataNodeCreator : DataNodeCreatorBase
{
private readonly Dictionary<DataNodeType, List<IFunction>> _functions = new Dictionary<DataNodeType, List<IFunction>>();
private readonly IRandom _random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
public RandomDataNodeCreator()
{
var int32Funcs = new List<IFunction>()
{
new Int32FunctionAdd(),
new Int32FunctionXor(),
};
_functions.Add(DataNodeType.Int32, int32Funcs);
}
public override IDataNode CreateRandom(DataNodeType type, object value, CreateExpressionOptions options)
{
if (!_functions.TryGetValue(type, out var funcs))
{
throw new System.Exception($"No functions available for type {type}");
}
if (options.depth >= 2)
{
return new ConstDataNode() { Type = type, Value = value };
}
var func = funcs[options.random.NextInt(funcs.Count)];
++options.depth;
return func.CreateCallable(type, value, options);
}
public IDataNode CreateRandom(DataNodeType type, object value)
{
var options = new CreateExpressionOptions
{
depth = 0,
random = _random,
expressionCreator = this,
};
return CreateRandom(type, value, options);
}
}
}