From 3a13c12594c9c78c66eba1723b89cd4e11b80a3a Mon Sep 17 00:00:00 2001 From: walon Date: Thu, 8 May 2025 09:33:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B8=B8=E9=87=8F=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=92=8C=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/{Emit => Data}/ConstFieldAllocator.cs | 119 ++++++++++++++---- .../ConstObfus/DefaultConstObfuscator.cs | 48 +++---- 2 files changed, 113 insertions(+), 54 deletions(-) rename Editor/{Emit => Data}/ConstFieldAllocator.cs (56%) diff --git a/Editor/Emit/ConstFieldAllocator.cs b/Editor/Data/ConstFieldAllocator.cs similarity index 56% rename from Editor/Emit/ConstFieldAllocator.cs rename to Editor/Data/ConstFieldAllocator.cs index a3c2894..2b221bd 100644 --- a/Editor/Emit/ConstFieldAllocator.cs +++ b/Editor/Data/ConstFieldAllocator.cs @@ -1,19 +1,23 @@ using dnlib.DotNet; using dnlib.DotNet.Emit; +using Obfuz.Emit; using Obfuz.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; using UnityEngine.Assertions; -namespace Obfuz.Emit +namespace Obfuz.Data { - public class ModuleConstFieldAllocator + public class ModuleConstFieldAllocator : IModuleEmitManager { - private readonly ModuleDef _module; + private ModuleDef _module; private readonly IRandom _random; + private readonly IEncryptor _encryptor; + private readonly RvaDataAllocator _rvaDataAllocator; private TypeDef _holderTypeDef; @@ -28,10 +32,16 @@ namespace Obfuz.Emit private readonly List _holderTypeDefs = new List(); - public ModuleConstFieldAllocator(ModuleDef mod, IRandom random) + public ModuleConstFieldAllocator(IEncryptor encryptor, IRandom random, RvaDataAllocator rvaDataAllocator) + { + _encryptor = encryptor; + _random = random; + _rvaDataAllocator = rvaDataAllocator; + } + + public void Init(ModuleDef mod) { _module = mod; - _random = random; } const int maxFieldCount = 1000; @@ -116,6 +126,21 @@ namespace Obfuz.Emit // throw new NotImplementedException(); //} + private int GenerateEncryptionOperations() + { + return _random.NextInt(); + } + + public int GenerateSalt() + { + return _random.NextInt(); + } + + private DefaultModuleMetadataImporter GetModuleMetadataImporter() + { + return MetadataImporter.Instance.GetDefaultModuleMetadataImporter(_module); + } + private void CreateCCtorOfRvaTypeDef(TypeDef type) { var cctor = new MethodDefUser(".cctor", @@ -131,27 +156,74 @@ namespace Obfuz.Emit //IMethod method = _module.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) })); //Assert.IsNotNull(method); + + DefaultModuleMetadataImporter importer = GetModuleMetadataImporter(); // TODO. obfuscate init codes foreach (var field in type.Fields) { ConstFieldInfo constInfo = _field2Fields[field]; + int ops = GenerateEncryptionOperations(); + int salt = GenerateSalt(); switch (constInfo.value) { case int i: - ins.Add(Instruction.Create(OpCodes.Ldc_I4, i)); - break; + { + int encryptedValue = _encryptor.Encrypt(i, ops, salt); + RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); + ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + ins.Add(Instruction.CreateLdcI4(rvaData.offset)); + ins.Add(Instruction.CreateLdcI4(ops)); + ins.Add(Instruction.CreateLdcI4(salt)); + ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaInt)); + break; + } case long l: - ins.Add(Instruction.Create(OpCodes.Ldc_I8, l)); - break; + { + long encryptedValue = _encryptor.Encrypt(l, ops, salt); + RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); + ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + ins.Add(Instruction.CreateLdcI4(rvaData.offset)); + ins.Add(Instruction.CreateLdcI4(ops)); + ins.Add(Instruction.CreateLdcI4(salt)); + ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaLong)); + break; + } case float f: - ins.Add(Instruction.Create(OpCodes.Ldc_R4, f)); - break; + { + float encryptedValue = _encryptor.Encrypt(f, ops, salt); + RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); + ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + ins.Add(Instruction.CreateLdcI4(rvaData.offset)); + ins.Add(Instruction.CreateLdcI4(ops)); + ins.Add(Instruction.CreateLdcI4(salt)); + ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaFloat)); + break; + } case double d: - ins.Add(Instruction.Create(OpCodes.Ldc_R8, d)); - break; + { + double encryptedValue = _encryptor.Encrypt(d, ops, salt); + RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); + ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + ins.Add(Instruction.CreateLdcI4(rvaData.offset)); + ins.Add(Instruction.CreateLdcI4(ops)); + ins.Add(Instruction.CreateLdcI4(salt)); + ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaDouble)); + break; + } case string s: - ins.Add(Instruction.Create(OpCodes.Ldstr, s)); - break; + { + int stringByteLength = Encoding.UTF8.GetByteCount(s); + byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt); + RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); + ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + ins.Add(Instruction.CreateLdcI4(rvaData.offset)); + //// should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length. + ins.Add(Instruction.CreateLdcI4(stringByteLength)); + ins.Add(Instruction.CreateLdcI4(ops)); + ins.Add(Instruction.CreateLdcI4(salt)); + ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); + break; + } //case byte[] b: // ins.Add(Instruction.Create(OpCodes.Ldlen, b.Length)); // break; @@ -173,23 +245,20 @@ namespace Obfuz.Emit public class ConstFieldAllocator { + private readonly IEncryptor _encryptor; private readonly IRandom _random; + private readonly RvaDataAllocator _rvaDataAllocator; - private readonly Dictionary _moduleAllocators = new Dictionary(); - - public ConstFieldAllocator(IRandom random) + public ConstFieldAllocator(IEncryptor encryptor, IRandom random, RvaDataAllocator rvaDataAllocator) { + _encryptor = encryptor; _random = random; + _rvaDataAllocator = rvaDataAllocator; } private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod) { - if (!_moduleAllocators.TryGetValue(mod, out var moduleAllocator)) - { - moduleAllocator = new ModuleConstFieldAllocator(mod, _random); - _moduleAllocators[mod] = moduleAllocator; - } - return moduleAllocator; + return EmitManager.Ins.GetEmitManager(mod, m => new ModuleConstFieldAllocator(_encryptor, _random, _rvaDataAllocator)); } public FieldDef Allocate(ModuleDef mod, int value) @@ -219,7 +288,7 @@ namespace Obfuz.Emit public void Done() { - foreach (var moduleAllocator in _moduleAllocators.Values) + foreach (var moduleAllocator in EmitManager.Ins.GetEmitManagers()) { moduleAllocator.Done(); } diff --git a/Editor/ObfusPasses/ConstObfus/DefaultConstObfuscator.cs b/Editor/ObfusPasses/ConstObfus/DefaultConstObfuscator.cs index 34e8292..d4fe772 100644 --- a/Editor/ObfusPasses/ConstObfus/DefaultConstObfuscator.cs +++ b/Editor/ObfusPasses/ConstObfus/DefaultConstObfuscator.cs @@ -13,7 +13,6 @@ namespace Obfuz.ObfusPasses.ConstObfus public class DefaultConstObfuscator : IDataObfuscator { private readonly IRandom _random; - private readonly RandomDataNodeCreator _nodeCreator; private readonly RvaDataAllocator _rvaDataAllocator; private readonly ConstFieldAllocator _constFieldAllocator; private readonly IEncryptor _encryptor; @@ -22,21 +21,8 @@ namespace Obfuz.ObfusPasses.ConstObfus { _random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5); _encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D }); - _nodeCreator = new RandomDataNodeCreator(_random); _rvaDataAllocator = new RvaDataAllocator(_random, _encryptor); - _constFieldAllocator = new ConstFieldAllocator(_random); - } - - private void CompileNode(IDataNode node, MethodDef method, List obfuscatedInstructions) - { - var ctx = new CompileContext - { - method = method, - output = obfuscatedInstructions, - rvaDataAllocator = _rvaDataAllocator, - constFieldAllocator = _constFieldAllocator, - }; - node.Compile(ctx); + _constFieldAllocator = new ConstFieldAllocator(_encryptor, _random, _rvaDataAllocator); } private int GenerateEncryptionOperations() @@ -134,21 +120,25 @@ namespace Obfuz.ObfusPasses.ConstObfus public void ObfuscateString(MethodDef method, string value, List obfuscatedInstructions) { - int ops = GenerateEncryptionOperations(); - int salt = GenerateSalt(); - int stringByteLength = Encoding.UTF8.GetByteCount(value); - byte[] encryptedValue = _encryptor.Encrypt(value, ops, salt); - Assert.IsTrue(encryptedValue.Length % 4 == 0); - RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); + //int ops = GenerateEncryptionOperations(); + //int salt = GenerateSalt(); + //int stringByteLength = Encoding.UTF8.GetByteCount(value); + //byte[] encryptedValue = _encryptor.Encrypt(value, ops, salt); + //Assert.IsTrue(encryptedValue.Length % 4 == 0); + //RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); - DefaultModuleMetadataImporter importer = GetModuleMetadataImporter(method); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); - // should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length. - obfuscatedInstructions.Add(Instruction.CreateLdcI4(stringByteLength)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); - obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); - obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); + //DefaultModuleMetadataImporter importer = GetModuleMetadataImporter(method); + //obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); + //obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); + //// should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length. + //obfuscatedInstructions.Add(Instruction.CreateLdcI4(stringByteLength)); + //obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); + //obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); + //obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); + + // to avoid gc, use a cached string + FieldDef cacheField = _constFieldAllocator.Allocate(method.Module, value); + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, cacheField)); } public void Done()