EncryptionVM
parent
ebce42a8d6
commit
5e45a684aa
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Obfuz.Encryption
|
||||
{
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Obfuz.ObfusPasses.ConstObfus
|
||||
{
|
||||
public interface IConstObfuscationPolicy
|
||||
public interface IObfuscationPolicy
|
||||
{
|
||||
bool NeedObfuscateMethod(MethodDef method);
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue