From 79c81e234c06612a807aa307e24b740dbedf9980 Mon Sep 17 00:00:00 2001 From: walon Date: Mon, 7 Sep 2026 22:26:01 +0800 Subject: [PATCH] fix: remove RuntimeHelpers.InitializeArray dependency from ConstEncrypt DecryptInitializeArray DecryptInitializeArray now takes encrypted byte[] + offset instead of RuntimeFieldHandle, copies via Buffer.BlockCopy, and loads payload through RvaDataAllocator. Avoids Unity 6000.5+ IL2CPP C2664 on RuntimeFieldHandle vs Il2CppFieldRvaData. see issue-34 --- Editor/Emit/DefaultMetadataImporter.cs | 2 +- Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs | 3 +++ .../ConstEncrypt/DefaultConstEncryptor.cs | 13 +++++++++---- Runtime/EncryptionService.cs | 4 ++-- Runtime/EncryptorBase.cs | 6 ++---- Runtime/IEncryptor.cs | 2 +- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Editor/Emit/DefaultMetadataImporter.cs b/Editor/Emit/DefaultMetadataImporter.cs index 4290f47..7411b51 100644 --- a/Editor/Emit/DefaultMetadataImporter.cs +++ b/Editor/Emit/DefaultMetadataImporter.cs @@ -124,7 +124,7 @@ namespace Obfuz.Emit Assert.IsNotNull(_decryptFromRvaBytes); _decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); Assert.IsNotNull(_decryptFromRvaString); - _decryptInitializeArray = mod.Import(encryptionServiceType.GetMethod("DecryptInitializeArray", new[] { typeof(System.Array), typeof(System.RuntimeFieldHandle), typeof(int), typeof(int), typeof(int) })); + _decryptInitializeArray = mod.Import(encryptionServiceType.GetMethod("DecryptInitializeArray", new[] { typeof(System.Array), typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); Assert.IsNotNull(_decryptInitializeArray); } } diff --git a/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs b/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs index 2b75239..92595ea 100644 --- a/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs +++ b/Editor/ObfusPasses/ConstEncrypt/ConstEncryptPass.cs @@ -143,6 +143,9 @@ namespace Obfuz.ObfusPasses.ConstEncrypt { // don't need cache for byte array obfuscation needCache = false; + // Drop ldtoken RuntimeFieldHandle; DecryptInitializeArray now loads from RvaDataAllocator byte[]. + prevInst.OpCode = OpCodes.Nop; + prevInst.Operand = null; _dataObfuscator.ObfuscateBytes(method, needCache, ravFieldDef, data, outputInstructions); return true; } diff --git a/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs b/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs index 93ce401..12faf05 100644 --- a/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs +++ b/Editor/ObfusPasses/ConstEncrypt/DefaultConstEncryptor.cs @@ -266,15 +266,15 @@ namespace Obfuz.ObfusPasses.ConstEncrypt class EncryptedRvaDataInfo { - public readonly FieldDef fieldDef; + public readonly RvaData rvaData; public readonly byte[] originalBytes; public readonly byte[] encryptedBytes; public readonly int opts; public readonly int salt; - public EncryptedRvaDataInfo(FieldDef fieldDef, byte[] originalBytes, byte[] encryptedBytes, int opts, int salt) + public EncryptedRvaDataInfo(RvaData rvaData, byte[] originalBytes, byte[] encryptedBytes, int opts, int salt) { - this.fieldDef = fieldDef; + this.rvaData = rvaData; this.originalBytes = originalBytes; this.encryptedBytes = encryptedBytes; this.opts = opts; @@ -296,8 +296,11 @@ namespace Obfuz.ObfusPasses.ConstEncrypt byte[] encryptedBytes = (byte[])originalBytes.Clone(); encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt); Assert.AreNotEqual(originalBytes, encryptedBytes, "Original bytes should not be the same as encrypted bytes."); - encryptedRvaData = new EncryptedRvaDataInfo(fieldDef, originalBytes, encryptedBytes, ops, salt); + RvaDataAllocator rvaDataAllocator = _moduleEntityManager.GetEntity(fieldDef.Module); + RvaData rvaData = rvaDataAllocator.Allocate(encryptedBytes); + encryptedRvaData = new EncryptedRvaDataInfo(rvaData, originalBytes, encryptedBytes, ops, salt); _encryptedRvaFields.Add(fieldDef, encryptedRvaData); + // Keep ciphertext in the original RVA field so plaintext is not shipped; runtime loads via RvaDataAllocator. fieldDef.InitialValue = encryptedBytes; byte[] decryptedBytes = (byte[])encryptedBytes.Clone(); encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt); @@ -313,6 +316,8 @@ namespace Obfuz.ObfusPasses.ConstEncrypt Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length); DefaultMetadataImporter importer = GetModuleMetadataImporter(method); + obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, encryptedData.rvaData.field)); + obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.rvaData.offset)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.encryptedBytes.Length)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt)); diff --git a/Runtime/EncryptionService.cs b/Runtime/EncryptionService.cs index 29cc5d4..da51590 100644 --- a/Runtime/EncryptionService.cs +++ b/Runtime/EncryptionService.cs @@ -139,9 +139,9 @@ namespace Obfuz return Decrypt(data, offset, bytesLength, ops, salt); } - public static void DecryptInitializeArray(System.Array arr, System.RuntimeFieldHandle field, int length, int ops, int salt) + public static void DecryptInitializeArray(System.Array arr, byte[] data, int offset, int length, int ops, int salt) { - _encryptor.DecryptInitializeArray(arr, field, length, ops, salt); + _encryptor.DecryptInitializeArray(arr, data, offset, length, ops, salt); } } } diff --git a/Runtime/EncryptorBase.cs b/Runtime/EncryptorBase.cs index 53de69c..6e4c66c 100644 --- a/Runtime/EncryptorBase.cs +++ b/Runtime/EncryptorBase.cs @@ -19,7 +19,6 @@ // SOFTWARE. using System; -using System.Runtime.CompilerServices; using System.Text; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Assertions; @@ -291,10 +290,9 @@ namespace Obfuz } } - public virtual unsafe void DecryptInitializeArray(System.Array arr, System.RuntimeFieldHandle field, int length, int ops, int salt) + public virtual unsafe void DecryptInitializeArray(System.Array arr, byte[] data, int offset, int length, int ops, int salt) { - //Assert.AreEqual(Marshal.SizeOf(arr.GetType().GetElementType()), arr.Length); - RuntimeHelpers.InitializeArray(arr, field); + Buffer.BlockCopy(data, offset, arr, 0, length); if (arr is byte[] byteArr) { fixed (byte* dataPtr = &byteArr[0]) diff --git a/Runtime/IEncryptor.cs b/Runtime/IEncryptor.cs index 45694e8..32a1a15 100644 --- a/Runtime/IEncryptor.cs +++ b/Runtime/IEncryptor.cs @@ -45,6 +45,6 @@ byte[] Encrypt(string value, int ops, int salt); string DecryptString(byte[] value, int offset, int stringBytesLength, int ops, int salt); - void DecryptInitializeArray(System.Array arr, System.RuntimeFieldHandle field, int length, int ops, int salt); + void DecryptInitializeArray(System.Array arr, byte[] data, int offset, int length, int ops, int salt); } }