using Obfuz.Utils; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; 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}"); UnityEditor.AssetDatabase.Refresh(); } private string GenerateCode() { var lines = new List(); AppendHeader(lines); AppendEncryptCodes(lines); AppendDecryptCodes(lines); AppendTailer(lines); return string.Join("\n", lines); } private void AppendEncryptCodes(List 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 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 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 lines) { lines.Add(@" } } "); } private void AppendEncryptCode(List lines, IEncryptionInstruction instruction) { instruction.GenerateEncryptCode(lines, " "); } private void AppendDecryptCode(List lines, IEncryptionInstruction instruction) { instruction.GenerateDecryptCode(lines, " "); } } }