支持生成 EncryptionVirtualMachine的代码

backup
walon 2025-05-11 19:28:19 +08:00
parent a1f947416d
commit b1a19e9ef7
12 changed files with 339 additions and 13 deletions

View File

@ -1,15 +1,24 @@
namespace Obfuz.EncryptionVM
using System.Collections.Generic;
namespace Obfuz.EncryptionVM
{
public interface IEncryptionInstruction
{
int Encrypt(int value, int[] secretKey, int salt);
int Decrypt(int value, int[] secretKey, int salt);
void GenerateEncryptCode(List<string> lines, string indent);
void GenerateDecryptCode(List<string> lines, string indent);
}
public abstract class EncryptionInstructionBase : IEncryptionInstruction
{
public abstract int Encrypt(int value, int[] secretKey, int salt);
public abstract int Decrypt(int value, int[] secretKey, int salt);
public abstract void GenerateEncryptCode(List<string> lines, string indent);
public abstract void GenerateDecryptCode(List<string> lines, string indent);
}
}

View File

@ -1,4 +1,6 @@
namespace Obfuz.EncryptionVM.Instructions
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions
{
public class AddInstruction : EncryptionInstructionBase
{
@ -19,5 +21,15 @@
{
return value - secretKey[_opKeyIndex] - salt - _addValue;
}
public override void GenerateEncryptCode(List<string> lines, string indent)
{
lines.Add(indent + $"value += _secretKey[{_opKeyIndex}] + salt + {_addValue};");
}
public override void GenerateDecryptCode(List<string> lines, string indent)
{
lines.Add(indent + $"value -= _secretKey[{_opKeyIndex}] + salt + {_addValue};");
}
}
}

View File

@ -1,4 +1,6 @@
namespace Obfuz.EncryptionVM.Instructions
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions
{
public class BitRotateInstruction : EncryptionInstructionBase
{
@ -25,5 +27,20 @@
uint part2 = value2 << (32 - _rotateBitNum);
return (int)(part1 | part2);
}
public override void GenerateEncryptCode(List<string> lines, string indent)
{
lines.Add(indent + $"uint part1 = (uint)value << {_rotateBitNum};");
lines.Add(indent + $"uint part2 = (uint)value >> (32 - {_rotateBitNum});");
lines.Add(indent + $"value = ((int)(part1 | part2) ^ _secretKey[{_opKeyIndex}]) + salt;");
}
public override void GenerateDecryptCode(List<string> lines, string indent)
{
lines.Add(indent + $"uint value2 = (uint)((value - salt) ^ _secretKey[{_opKeyIndex}]);");
lines.Add(indent + $"uint part1 = value2 >> {_rotateBitNum};");
lines.Add(indent + $"uint part2 = value2 << (32 - {_rotateBitNum});");
lines.Add(indent + $"value = (int)(part1 | part2);");
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -32,5 +33,15 @@ namespace Obfuz.EncryptionVM.Instructions
}
return value;
}
public override void GenerateEncryptCode(List<string> lines, string indent)
{
throw new NotImplementedException();
}
public override void GenerateDecryptCode(List<string> lines, string indent)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,4 +1,6 @@
namespace Obfuz.EncryptionVM.Instructions
using System.Collections.Generic;
namespace Obfuz.EncryptionVM.Instructions
{
public class XorInstruction : EncryptionInstructionBase
{
@ -20,5 +22,15 @@
{
return value ^ secretKey[_opKeyIndex] ^ salt ^ _xorValue;
}
public override void GenerateEncryptCode(List<string> lines, string indent)
{
lines.Add(indent + $"value ^= _secretKey[{_opKeyIndex}] ^ salt ^ {_xorValue};");
}
public override void GenerateDecryptCode(List<string> lines, string indent)
{
lines.Add(indent + $"value ^= _secretKey[{_opKeyIndex}] ^ salt ^ {_xorValue};");
}
}
}

View File

@ -1,27 +1,204 @@
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 string _vmCodeGenerateSecretKey;
private readonly IRandom _random;
private VirtualMachine _vm;
private readonly int _opCodeCount;
private readonly int _opCodeBits;
private readonly VirtualMachine _vm;
public VirtualMachineCodeGenerator(string vmCodeGenerateSecretKey, int opCount)
public VirtualMachineCodeGenerator(string vmCodeGenerateSecretKey, int opCodeCount)
{
_vmCodeGenerateSecretKey = vmCodeGenerateSecretKey;
_vm = new VirtualMachineCreator(_vmCodeGenerateSecretKey).CreateVirtualMachine(opCount);
_opCodeCount = opCodeCount;
_opCodeBits = GetBitCount(opCodeCount - 1);
_vm = new VirtualMachineCreator(vmCodeGenerateSecretKey).CreateVirtualMachine(opCodeCount);
}
public VirtualMachineCodeGenerator(VirtualMachine vm)
{
_opCodeCount = vm.opCodes.Length;
_opCodeBits = GetBitCount(_opCodeCount - 1);
_vm = vm;
}
private static int GetBitCount(int value)
{
int count = 0;
while (value > 0)
{
count++;
value >>= 1;
}
return count;
}
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<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}:
{{");
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}:
{{");
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 OpCodeBits = {_opCodeBits};
private const int OpCodeCount = {_opCodeCount};
private const int OpCodeMask = {_opCodeCount - 1};
");
lines.Add(@"
private readonly int[] _secretKey;
public GeneratedEncryptionVirtualMachine(byte[] secretKey)
{
this._secretKey = ConvertToIntKey(secretKey);
}
public override int Encrypt(int value, int opts, int salt)
{
while (opts > 0)
{
int opCode = opts & OpCodeMask;
value = ExecuteEncrypt(value, opCode, salt);
opts >>= OpCodeBits;
}
return value;
}
public override int Decrypt(int value, int opts, int salt)
{
while (opts > 0)
{
int opCode = opts & OpCodeMask;
value = ExecuteDecrypt(value, opCode, salt);
opts >>= OpCodeBits;
}
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, " ");
}
}
}

View File

@ -33,6 +33,7 @@ namespace Obfuz
private readonly int _globalRandomSeed;
private readonly string _encryptionVmGenerationSecretKey;
private readonly int _encryptionVmOpCodeCount;
private readonly string _encryptionVmCodeFile;
private ObfuscationPassContext _ctx;
@ -42,6 +43,7 @@ namespace Obfuz
_globalRandomSeed = builder.GlobalRandomSeed;
_encryptionVmGenerationSecretKey = builder.EncryptionVmGenerationSecretKey;
_encryptionVmOpCodeCount = builder.EncryptionVmOpCodeCount;
_encryptionVmCodeFile = builder.EncryptionVmCodeFile;
_toObfuscatedAssemblyNames = builder.ToObfuscatedAssemblyNames;
_notObfuscatedAssemblyNamesReferencingObfuscated = builder.NotObfuscatedAssemblyNamesReferencingObfuscated;
@ -67,7 +69,55 @@ namespace Obfuz
{
var vmCreator = new VirtualMachineCreator(_encryptionVmGenerationSecretKey);
var vm = vmCreator.CreateVirtualMachine(_encryptionVmOpCodeCount);
return new VirtualMachineSimulator(vm, _secretKey);
var vmGenerator = new VirtualMachineCodeGenerator(vm);
if (!File.Exists(_encryptionVmCodeFile))
{
throw new Exception($"EncryptionVm CodeFile:`{_encryptionVmCodeFile}` not exists! Please run `Obfuz/GenerateVm` to generate it!");
}
if (!vmGenerator.ValidateMatch(_encryptionVmCodeFile))
{
throw new Exception($"EncryptionVm CodeFile:`{_encryptionVmCodeFile}` not match with encryptionVM settings! Please run `Obfuz/GenerateVm` to update it!");
}
var vms = new VirtualMachineSimulator(vm, _secretKey);
var generatedVmTypes = AppDomain.CurrentDomain.GetAssemblies()
.Select(assembly => assembly.GetType("Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine"))
.Where(type => type != null)
.ToList();
if (generatedVmTypes.Count == 0)
{
throw new Exception($"class Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine not found in any assembly! Please run `Obfuz/GenerateVm` to generate it!");
}
if (generatedVmTypes.Count > 1)
{
throw new Exception($"class Obfuz.EncryptionVM.GeneratedEncryptionVirtualMachine found in multiple assemblies! Please retain only one!");
}
var gvmInstance = (IEncryptor)Activator.CreateInstance(generatedVmTypes[0], new object[] { _secretKey } );
int testValue = 11223344;
for (int i = 0; i < vm.opCodes.Length; i++)
{
int encryptedValueOfVms = vms.Encrypt(testValue, i, i);
int decryptedValueOfVms = vms.Decrypt(encryptedValueOfVms, i, i);
if (decryptedValueOfVms != testValue)
{
throw new Exception($"VirtualMachineSimulator decrypt failed! opCode:{i}, originalValue:{testValue} decryptedValue:{decryptedValueOfVms}");
}
int encryptedValueOfGvm = gvmInstance.Encrypt(testValue, i, i);
int decryptedValueOfGvm = gvmInstance.Decrypt(encryptedValueOfGvm, i, i);
if (encryptedValueOfGvm != encryptedValueOfVms)
{
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testValue} encryptedValue VirtualMachineSimulator:{encryptedValueOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
}
if (decryptedValueOfGvm != testValue)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testValue} decryptedValue:{decryptedValueOfGvm}");
}
}
return vms;
}
private void OnPreObfuscation()

View File

@ -1,4 +1,5 @@
using Obfuz.ObfusPasses;
using Obfuz.EncryptionVM;
using Obfuz.ObfusPasses;
using Obfuz.ObfusPasses.CallObfus;
using Obfuz.ObfusPasses.ConstEncrypt;
using Obfuz.ObfusPasses.ExprObfus;
@ -6,6 +7,7 @@ using Obfuz.ObfusPasses.FieldEncrypt;
using Obfuz.ObfusPasses.SymbolObfus;
using Obfuz.Settings;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
@ -17,6 +19,8 @@ namespace Obfuz
private int _globalRandomSeed;
private string _encryptionVmGenerationSecretKey;
private int _encryptionVmOpCodeCount;
public string _encryptionVmCodeFile;
private List<string> _toObfuscatedAssemblyNames = new List<string>();
private List<string> _notObfuscatedAssemblyNamesReferencingObfuscated = new List<string>();
private List<string> _assemblySearchDirs = new List<string>();
@ -48,6 +52,12 @@ namespace Obfuz
set => _encryptionVmOpCodeCount = value;
}
public string EncryptionVmCodeFile
{
get => _encryptionVmCodeFile;
set => _encryptionVmCodeFile = value;
}
public List<string> ToObfuscatedAssemblyNames
{
get => _toObfuscatedAssemblyNames;
@ -98,6 +108,7 @@ namespace Obfuz
_globalRandomSeed = settings.globalRandomSeed,
_encryptionVmGenerationSecretKey = settings.encryptionVMSettings.codeGenerationSecretKey,
_encryptionVmOpCodeCount = settings.encryptionVMSettings.encryptionOpCodeCount,
_encryptionVmCodeFile = settings.encryptionVMSettings.CodeOutputPath,
_toObfuscatedAssemblyNames = settings.toObfuscatedAssemblyNames.ToList(),
_notObfuscatedAssemblyNamesReferencingObfuscated = settings.notObfuscatedAssemblyNamesReferencingObfuscated.ToList(),
_assemblySearchDirs = settings.extraAssemblySearchDirs.ToList(),

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -18,5 +19,7 @@ namespace Obfuz.Settings
[Tooltip("encryption virtual machine source code output dir")]
public string codeOutputDir = "Assets/Obfuz";
public string CodeOutputPath { get => Path.Combine(codeOutputDir, "GeneratedEncryptionVirtualMachine.cs"); }
}
}

View File

@ -1,3 +1,5 @@
using Obfuz.EncryptionVM;
using Obfuz.Settings;
using UnityEditor;
using UnityEngine;
@ -6,9 +8,17 @@ namespace Obfuz.Unity
public static class ObfuzMenu
{
[MenuItem("Obfuz/Settings...", priority = 61)]
[MenuItem("Obfuz/Settings...", priority = 1)]
public static void OpenSettings() => SettingsService.OpenProjectSettings("Project/Obfuz");
[MenuItem("Obfuz/GenerateVM", priority = 62)]
public static void GenerateEncryptionVM()
{
EncryptionVMSettings settings = ObfuzSettings.Instance.encryptionVMSettings;
var generator = new VirtualMachineCodeGenerator(settings.codeGenerationSecretKey, settings.encryptionOpCodeCount);
generator.Generate(settings.CodeOutputPath);
}
[MenuItem("Obfuz/Documents/Quick Start")]
public static void OpenQuickStart() => Application.OpenURL("https://obfuz.doc.code-philosophy.com/docs/beginner/quickstart");

View File

@ -10,6 +10,10 @@ namespace Obfuz.Utils
{
public static class FileUtil
{
public static void CreateParentDir(string path)
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
public static void RemoveDir(string dir, bool log = false)
{

View File

@ -1,11 +1,21 @@
using System;
using System.Text;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Assertions;
namespace Obfuz
{
public abstract class EncryptorBase : IEncryptor
{
public static int[] ConvertToIntKey(byte[] key)
{
Assert.AreEqual(0, key.Length % 4);
int align4Length = key.Length / 4;
int[] intKey = new int[align4Length];
Buffer.BlockCopy(key, 0, intKey, 0, key.Length);
return intKey;
}
public abstract int Encrypt(int value, int opts, int salt);
public abstract int Decrypt(int value, int opts, int salt);