EncryptionVM

backup
walon 2025-05-06 09:13:24 +08:00
parent ebce42a8d6
commit 5e45a684aa
11 changed files with 423 additions and 61 deletions

View File

@ -0,0 +1,118 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.Encryption
{
public interface IEncryptInstruction
{
int Encrypt(int value, int[] secretKey, int salt);
int Decrypt(int value, int[] secretKey, int salt);
}
public abstract class EncryptInstructionBase : IEncryptInstruction
{
public abstract int Encrypt(int value, int[] secretKey, int salt);
public abstract int Decrypt(int value, int[] secretKey, int salt);
}
public class AddInstruction : EncryptInstructionBase
{
private readonly int _addValue;
private readonly int _opKeyIndex;
public AddInstruction(int addValue, int opKeyIndex)
{
_addValue = addValue;
_opKeyIndex = opKeyIndex;
}
public override int Encrypt(int value, int[] secretKey, int salt)
{
return value + secretKey[_opKeyIndex] + salt + _addValue;
}
public override int Decrypt(int value, int[] secretKey, int salt)
{
return value - secretKey[_opKeyIndex] - salt - _addValue;
}
}
public class XorInstruction : EncryptInstructionBase
{
private readonly int _xorValue;
private readonly int _opKeyIndex;
public XorInstruction(int xorValue, int opKeyIndex)
{
_xorValue = xorValue;
_opKeyIndex = opKeyIndex;
}
public override int Encrypt(int value, int[] secretKey, int salt)
{
return value ^ secretKey[_opKeyIndex] ^ salt ^ _xorValue;
}
public override int Decrypt(int value, int[] secretKey, int salt)
{
return value ^ secretKey[_opKeyIndex] ^ salt ^ _xorValue;
}
}
public class BitRotateInstruction : EncryptInstructionBase
{
private readonly int _rotateBitNum;
private readonly int _opKeyIndex;
public BitRotateInstruction(int rotateBitNum, int opKeyIndex)
{
_rotateBitNum = rotateBitNum;
_opKeyIndex = opKeyIndex;
}
public override int Encrypt(int value, int[] secretKey, int salt)
{
uint part1 = (uint)value << _rotateBitNum;
uint part2 = (uint)value >> (32 - _rotateBitNum);
return ((int)(part1 | part2) ^ secretKey[_opKeyIndex]) + salt;
}
public override int Decrypt(int value, int[] secretKey, int salt)
{
uint value2 = (uint)((value - salt) ^ secretKey[_opKeyIndex]);
uint part1 = value2 >> _rotateBitNum;
uint part2 = value2 << (32 - _rotateBitNum);
return (int)(part1 | part2);
}
}
public class EncryptFunction : EncryptInstructionBase
{
private readonly IEncryptInstruction[] _instructions;
public EncryptFunction(IEncryptInstruction[] instructions)
{
_instructions = instructions;
}
public override int Encrypt(int value, int[] secretKey, int salt)
{
foreach (var instruction in _instructions)
{
value = instruction.Encrypt(value, secretKey, salt);
}
return value;
}
public override int Decrypt(int value, int[] secretKey, int salt)
{
for (int i = _instructions.Length - 1; i >= 0; i--)
{
value = _instructions[i].Decrypt(value, secretKey, salt);
}
return value;
}
}
}

View File

@ -0,0 +1,25 @@
namespace Obfuz.Encryption
{
public class EncryptOpCode
{
public readonly ushort code;
public readonly EncryptFunction function;
public EncryptOpCode(ushort code, EncryptFunction function)
{
this.code = code;
this.function = function;
}
public int Encrypt(int value, int[] secretKey, int salt)
{
return function.Encrypt(value, secretKey, salt);
}
public int Decrypt(int value, int[] secretKey, int salt)
{
return function.Decrypt(value, secretKey, salt);
}
}
}

View File

@ -0,0 +1,240 @@
using Obfuz.Utils;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Assertions;
namespace Obfuz.Encryption
{
public class VirtualMachine
{
public readonly int vmSeed;
public readonly EncryptOpCode[] opCodes;
public VirtualMachine(int vmSeed, EncryptOpCode[] opCodes)
{
this.vmSeed = vmSeed;
this.opCodes = opCodes;
}
}
public interface IVirtualMachineCreator
{
VirtualMachine CreateVirtualMachine(int opCodeCount, int vmSeed);
}
public class RandomVirtualMachineCreator : IVirtualMachineCreator
{
public RandomVirtualMachineCreator()
{
}
private IEncryptInstruction CreateRandomInstruction(IRandom random, int opCodeCount)
{
switch (random.NextInt(3))
{
case 0:
return new AddInstruction(random.NextInt(), random.NextInt(opCodeCount));
case 1:
return new XorInstruction(random.NextInt(), random.NextInt(opCodeCount));
case 2:
return new BitRotateInstruction(random.NextInt(32), random.NextInt(opCodeCount));
default:
throw new System.Exception("Invalid instruction type");
}
}
private EncryptOpCode CreateEncryptOpCode(ushort code, IRandom r, int opCodeCount)
{
Assert.IsTrue(code < opCodeCount);
var insts = new IEncryptInstruction[opCodeCount];
for (int i = 0; i < insts.Length; i++)
{
insts[i] = CreateRandomInstruction(r, opCodeCount);
}
var function = new EncryptFunction(insts);
return new EncryptOpCode(code, function);
}
public VirtualMachine CreateVirtualMachine(int opCodeCount, int vmSeed)
{
Assert.IsTrue(opCodeCount > 0);
Assert.AreEqual(0, opCodeCount ^ (opCodeCount - 1));
IRandom r = new RandomWithKey(new byte[] {1,2,3,4,5,6}, vmSeed);
var opCodes = new EncryptOpCode[opCodeCount];
for (int i = 0; i < opCodes.Length; i++)
{
opCodes[i] = CreateEncryptOpCode((ushort)i, r, opCodeCount);
}
return new VirtualMachine(vmSeed, opCodes);
}
}
public class EncryptVirtualMachineSimulator
{
private readonly EncryptOpCode[] _opCodes;
private readonly int[] _secretKey;
public EncryptVirtualMachineSimulator(EncryptOpCode[] opCodes, int[] secretKey)
{
_opCodes = opCodes;
// should be power of 2
Assert.AreEqual(0, opCodes.Length ^ (opCodes.Length - 1));
_secretKey = secretKey;
}
private List<ushort> DecodeOps(int ops)
{
var codes = new List<ushort>();
while (ops > 0)
{
var code = (ushort)(ops % _opCodes.Length);
codes.Add(code);
ops >>= 16;
}
return codes;
}
public int Encrypt(int value, int ops, int salt)
{
var codes = DecodeOps(ops);
foreach (var code in codes)
{
var opCode = _opCodes[code];
value = opCode.Encrypt(value, _secretKey, salt);
}
return value;
}
public int Decrypt(int value, int ops, int salt)
{
var codes = DecodeOps(ops);
for (int i = codes.Count - 1; i >= 0; i--)
{
var opCode = _opCodes[codes[i]];
value = opCode.Decrypt(value, _secretKey, salt);
}
return value;
}
public long Encrypt(long value, int ops, int salt)
{
int low = (int)(value & 0xFFFFFFFF);
int high = (int)((value >> 32) & 0xFFFFFFFF);
var codes = DecodeOps(ops);
// TODO we should encrypt high with encLow
int encLow = Encrypt(low, ops, salt);
int encHigh = Encrypt(high, ops, salt);
return ((long)encHigh << 32) | (long)(uint)(encLow);
}
public long Decrypt(long value, int ops, int salt)
{
int low = (int)(value & 0xFFFFFFFF);
int high = (int)((value >> 32) & 0xFFFFFFFF);
var codes = DecodeOps(ops);
// TODO we should encrypt high with encLow
int decLow = Decrypt(low, ops, salt);
int decHigh = Decrypt(high, ops, salt);
return ((long)decHigh << 32) | (long)(uint)(decLow);
}
public float Encrypt(float value, int ops, int salt)
{
int intValue = UnsafeUtility.As<float, int>(ref value);
int encValue = Encrypt(intValue, ops, salt);
return UnsafeUtility.As<int, float>(ref encValue);
}
public float Decrypt(float value, int ops, int salt)
{
int intValue = UnsafeUtility.As<float, int>(ref value);
int decValue = Decrypt(intValue, ops, salt);
return UnsafeUtility.As<int, float>(ref decValue);
}
public double Encrypt(double value, int ops, int salt)
{
long longValue = UnsafeUtility.As<double, long>(ref value);
long encValue = Encrypt(longValue, ops, salt);
return UnsafeUtility.As<long, double>(ref encValue);
}
public double Decrypt(double value, int ops, int salt)
{
long longValue = UnsafeUtility.As<double, long>(ref value);
long decValue = Decrypt(longValue, ops, salt);
return UnsafeUtility.As<long, double>(ref decValue);
}
public int[] Encrypt(byte[] bytes, int offset, int length, int ops, int salt)
{
if (length == 0)
{
return Array.Empty<int>();
}
int intLength = (length + 3) / 4;
int[] encInts = new int[intLength];
Buffer.BlockCopy(bytes, offset, encInts, 0, length);
for (int i = 0; i < intLength; i++)
{
encInts[i] = Encrypt(encInts[i], ops, salt);
}
return encInts;
}
public byte[] Decrypt(int[] value, int offset, int byteLength, int ops, int salt)
{
if (byteLength == 0)
{
return Array.Empty<byte>();
}
int intLength = (byteLength + 3) / 4;
int[] decValue = new int[intLength];
for (int i = 0; i < intLength; i++)
{
decValue[i] = Decrypt(value[i], ops, salt);
}
byte[] bytes = new byte[byteLength];
Buffer.BlockCopy(decValue, 0, bytes, 0, byteLength);
return bytes;
}
public int[] Encrypt(string value, int ops, int salt)
{
if (value.Length == 0)
{
return Array.Empty<int>();
}
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
return Encrypt(bytes, 0, bytes.Length, ops, salt);
}
public string DecryptString(int[] value, int offset, int stringBytesLength, int ops, int salt)
{
if (stringBytesLength == 0)
{
return string.Empty;
}
int intLength = (stringBytesLength + 3) / 4;
int[] intValue = new int[intLength];
for (int i = 0; i < intLength; i++)
{
intValue[i] = Decrypt(value[i], ops, salt);
}
byte[] bytes = new byte[stringBytesLength];
Buffer.BlockCopy(intValue, 0, bytes, 0, stringBytesLength);
return System.Text.Encoding.UTF8.GetString(bytes);
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.Encryption
{
}

View File

@ -1,5 +1,6 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.ObfusPasses.ConstObfus.Policies;
using System;
using System.Collections.Generic;
using System.Linq;
@ -13,7 +14,7 @@ namespace Obfuz.ObfusPasses.ConstObfus
public class ConstObfusPass : InstructionObfuscationPassBase
{
private IConstObfuscationPolicy _dataObfuscatorPolicy;
private IObfuscationPolicy _dataObfuscatorPolicy;
private IDataObfuscator _dataObfuscator;
public override void Start(ObfuscationPassContext ctx)

View File

@ -1,42 +0,0 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ConstObfus
{
public abstract class ConstObfuscationPolicyBase : IConstObfuscationPolicy
{
public virtual bool NeedObfuscateMethod(MethodDef method)
{
return true;
}
public virtual bool NeedObfuscateInt(MethodDef method, int value)
{
return true;
}
public virtual bool NeedObfuscateLong(MethodDef method, long value)
{
return true;
}
public virtual bool NeedObfuscateFloat(MethodDef method, float value)
{
return true;
}
public virtual bool NeedObfuscateDouble(MethodDef method, double value)
{
return true;
}
public virtual bool NeedObfuscateString(MethodDef method, string value)
{
return true;
}
public virtual bool NeedObfuscateArray(MethodDef method, byte[] array)
{
return true;
}
}
}

View File

@ -7,7 +7,6 @@ namespace Obfuz.ObfusPasses.ConstObfus
{
public interface IDataObfuscator
{
void ObfuscateInt(MethodDef method, int value, List<Instruction> obfuscatedInstructions);
void ObfuscateLong(MethodDef method, long value, List<Instruction> obfuscatedInstructions);

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace Obfuz.ObfusPasses.ConstObfus
{
public interface IConstObfuscationPolicy
public interface IObfuscationPolicy
{
bool NeedObfuscateMethod(MethodDef method);

View File

@ -0,0 +1,15 @@
using dnlib.DotNet;
namespace Obfuz.ObfusPasses.ConstObfus.Policies
{
public abstract class ObfuscationPolicyBase : IObfuscationPolicy
{
public abstract bool NeedObfuscateArray(MethodDef method, byte[] array);
public abstract bool NeedObfuscateDouble(MethodDef method, double value);
public abstract bool NeedObfuscateFloat(MethodDef method, float value);
public abstract bool NeedObfuscateInt(MethodDef method, int value);
public abstract bool NeedObfuscateLong(MethodDef method, long value);
public abstract bool NeedObfuscateMethod(MethodDef method);
public abstract bool NeedObfuscateString(MethodDef method, string value);
}
}

View File

@ -5,9 +5,9 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.ObfusPasses.ConstObfus
namespace Obfuz.ObfusPasses.ConstObfus.Policies
{
public class RuleBasedObfuscationPolicy : ConstObfuscationPolicyBase
public class RuleBasedObfuscationPolicy : ObfuscationPolicyBase
{
public override bool NeedObfuscateMethod(MethodDef method)
{

View File

@ -9,26 +9,21 @@ namespace Obfuz.Utils
{
public class RandomWithKey : IRandom
{
// LCG 参数(使用经典的数值)
private const long a = 1664525;
private const long c = 1013904223;
private const long m = 4294967296; // 2^32
private readonly byte[] _key;
private readonly Random _random;
private int _nextIndex;
private int _seed;
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;
_seed = seed;
}
public int NextInt(int min, int max)
@ -52,7 +47,8 @@ namespace Obfuz.Utils
public int NextInt()
{
return _random.Next() ^ GetNextKeyByte();
_seed = (int)((a * _seed + c) % m);
return _seed ^ GetNextKeyByte();
}
public long NextLong()