obfuz/Editor/EncryptionVM/VirtualMachineCodeGenerator.cs

204 lines
5.9 KiB
C#
Raw Normal View History

using Obfuz.Utils;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Obfuz.EncryptionVM
{
public class VirtualMachineCodeGenerator
{
private readonly int _opCodeCount;
private readonly int _opCodeBits;
private readonly VirtualMachine _vm;
public VirtualMachineCodeGenerator(string vmCodeGenerateSecretKey, int opCodeCount)
{
_opCodeCount = opCodeCount;
_opCodeBits = EncryptionUtil.GetBitCount(opCodeCount - 1);
_vm = new VirtualMachineCreator(vmCodeGenerateSecretKey).CreateVirtualMachine(opCodeCount);
}
public VirtualMachineCodeGenerator(VirtualMachine vm)
{
_opCodeCount = vm.opCodes.Length;
_opCodeBits = EncryptionUtil.GetBitCount(_opCodeCount - 1);
_vm = vm;
}
public bool ValidateMatch(string outputFile)
{
if (!File.Exists(outputFile))
{
return false;
}
string oldCode = NormalizeText(File.ReadAllText(outputFile, Encoding.UTF8));
string newCode = NormalizeText(GenerateCode());
return oldCode == newCode;
}
private static string NormalizeText(string input)
{
return Regex.Replace(input, @"\s+", string.Empty);
}
public void Generate(string outputFile)
{
FileUtil.CreateParentDir(outputFile);
string code = GenerateCode();
File.WriteAllText(outputFile, code, Encoding.UTF8);
Debug.Log($"Generate EncryptionVM code to {outputFile}");
}
private string GenerateCode()
{
var lines = new List<string>();
AppendHeader(lines);
AppendEncryptCodes(lines);
AppendDecryptCodes(lines);
AppendTailer(lines);
return string.Join("\n", lines);
}
private void AppendEncryptCodes(List<string> lines)
{
lines.Add(@"
private int ExecuteEncrypt(int value, int opCode, int salt)
{
switch (opCode)
{");
foreach (var opCode in _vm.opCodes)
{
lines.Add($@" case {opCode.code}:
{{
// {opCode.function.GetType().Name}");
AppendEncryptCode(lines, opCode.function);
lines.Add(@" return value;
}");
}
lines.Add(@"
default:
throw new System.Exception($""Invalid opCode:{opCode}"");
}
}");
}
private void AppendDecryptCodes(List<string> lines)
{
lines.Add(@"
private int ExecuteDecrypt(int value, int opCode, int salt)
{
switch (opCode)
{");
foreach (var opCode in _vm.opCodes)
{
lines.Add($@" case {opCode.code}:
{{
// {opCode.function.GetType().Name}");
AppendDecryptCode(lines, opCode.function);
lines.Add(@" return value;
}");
}
lines.Add(@"
default:
throw new System.Exception($""Invalid opCode:{opCode}"");
}
}");
}
private void AppendHeader(List<string> lines)
{
lines.Add($"/// This file is auto-generated by Obfuz. Do not modify it.");
lines.Add($"///");
//lines.Add($"/// Created Time: {DateTime.Now}");
lines.Add($"/// Version: {_vm.version}");
lines.Add($"/// SecretKey: {_vm.codeGenerationSecretKey}");
lines.Add($"/// OpCodeCount: {_vm.opCodes.Length}");
lines.Add(@"
namespace Obfuz.EncryptionVM
{
public class GeneratedEncryptionVirtualMachine : Obfuz.EncryptorBase
{");
lines.Add($@"
private const int kOpCodeBits = {_opCodeBits};
private const int kOpCodeCount = {_opCodeCount};
private const int kOpCodeMask = {_opCodeCount - 1};
");
lines.Add(@"
private readonly int[] _secretKey;
public GeneratedEncryptionVirtualMachine(byte[] secretKey)
{
this._secretKey = ConvertToIntKey(secretKey);
}
public override int OpCodeCount => kOpCodeCount;
public override int Encrypt(int value, int opts, int salt)
{
uint uopts = (uint)opts;
uint revertOps = 0;
while (uopts != 0)
{
uint opCode = uopts & kOpCodeMask;
revertOps <<= kOpCodeBits;
revertOps |= opCode;
uopts >>= kOpCodeBits;
}
while (revertOps != 0)
{
uint opCode = revertOps & kOpCodeMask;
value = ExecuteEncrypt(value, (int)opCode, salt);
revertOps >>= kOpCodeBits;
}
return value;
}
public override int Decrypt(int value, int opts, int salt)
{
uint uopts = (uint)opts;
while (uopts != 0)
{
uint opCode = uopts & kOpCodeMask;
value = ExecuteDecrypt(value, (int)opCode, salt);
uopts >>= kOpCodeBits;
}
return value;
}
");
}
private void AppendTailer(List<string> lines)
{
lines.Add(@"
}
}
");
}
private void AppendEncryptCode(List<string> lines, IEncryptionInstruction instruction)
{
instruction.GenerateEncryptCode(lines, " ");
}
private void AppendDecryptCode(List<string> lines, IEncryptionInstruction instruction)
{
instruction.GenerateDecryptCode(lines, " ");
}
}
}