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
main
walon 2026-09-07 22:26:01 +08:00
parent fa2345017a
commit 79c81e234c
6 changed files with 18 additions and 12 deletions

View File

@ -124,7 +124,7 @@ namespace Obfuz.Emit
Assert.IsNotNull(_decryptFromRvaBytes); Assert.IsNotNull(_decryptFromRvaBytes);
_decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) })); _decryptFromRvaString = mod.Import(encryptionServiceType.GetMethod("DecryptFromRvaString", new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int) }));
Assert.IsNotNull(_decryptFromRvaString); 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); Assert.IsNotNull(_decryptInitializeArray);
} }
} }

View File

@ -143,6 +143,9 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
{ {
// don't need cache for byte array obfuscation // don't need cache for byte array obfuscation
needCache = false; 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); _dataObfuscator.ObfuscateBytes(method, needCache, ravFieldDef, data, outputInstructions);
return true; return true;
} }

View File

@ -266,15 +266,15 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
class EncryptedRvaDataInfo class EncryptedRvaDataInfo
{ {
public readonly FieldDef fieldDef; public readonly RvaData rvaData;
public readonly byte[] originalBytes; public readonly byte[] originalBytes;
public readonly byte[] encryptedBytes; public readonly byte[] encryptedBytes;
public readonly int opts; public readonly int opts;
public readonly int salt; 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.originalBytes = originalBytes;
this.encryptedBytes = encryptedBytes; this.encryptedBytes = encryptedBytes;
this.opts = opts; this.opts = opts;
@ -296,8 +296,11 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
byte[] encryptedBytes = (byte[])originalBytes.Clone(); byte[] encryptedBytes = (byte[])originalBytes.Clone();
encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt); encryptionScope.encryptor.EncryptBlock(encryptedBytes, ops, salt);
Assert.AreNotEqual(originalBytes, encryptedBytes, "Original bytes should not be the same as encrypted bytes."); 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<RvaDataAllocator>(fieldDef.Module);
RvaData rvaData = rvaDataAllocator.Allocate(encryptedBytes);
encryptedRvaData = new EncryptedRvaDataInfo(rvaData, originalBytes, encryptedBytes, ops, salt);
_encryptedRvaFields.Add(fieldDef, encryptedRvaData); _encryptedRvaFields.Add(fieldDef, encryptedRvaData);
// Keep ciphertext in the original RVA field so plaintext is not shipped; runtime loads via RvaDataAllocator.
fieldDef.InitialValue = encryptedBytes; fieldDef.InitialValue = encryptedBytes;
byte[] decryptedBytes = (byte[])encryptedBytes.Clone(); byte[] decryptedBytes = (byte[])encryptedBytes.Clone();
encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt); encryptionScope.encryptor.DecryptBlock(decryptedBytes, ops, salt);
@ -313,6 +316,8 @@ namespace Obfuz.ObfusPasses.ConstEncrypt
Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length); Assert.AreEqual(value.Length, encryptedData.encryptedBytes.Length);
DefaultMetadataImporter importer = GetModuleMetadataImporter(method); 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.encryptedBytes.Length));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.opts));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt)); obfuscatedInstructions.Add(Instruction.CreateLdcI4(encryptedData.salt));

View File

@ -139,9 +139,9 @@ namespace Obfuz
return Decrypt(data, offset, bytesLength, ops, salt); 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);
} }
} }
} }

View File

@ -19,7 +19,6 @@
// SOFTWARE. // SOFTWARE.
using System; using System;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using Unity.Collections.LowLevel.Unsafe; using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Assertions; 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); Buffer.BlockCopy(data, offset, arr, 0, length);
RuntimeHelpers.InitializeArray(arr, field);
if (arr is byte[] byteArr) if (arr is byte[] byteArr)
{ {
fixed (byte* dataPtr = &byteArr[0]) fixed (byte* dataPtr = &byteArr[0])

View File

@ -45,6 +45,6 @@
byte[] Encrypt(string value, int ops, int salt); byte[] Encrypt(string value, int ops, int salt);
string DecryptString(byte[] value, int offset, int stringBytesLength, 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);
} }
} }