支持常量加密和字符串缓存

backup
walon 2025-05-08 09:33:35 +08:00
parent fda0e5c66d
commit 3a13c12594
2 changed files with 113 additions and 54 deletions

View File

@ -1,19 +1,23 @@
using dnlib.DotNet; using dnlib.DotNet;
using dnlib.DotNet.Emit; using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Assertions; 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 IRandom _random;
private readonly IEncryptor _encryptor;
private readonly RvaDataAllocator _rvaDataAllocator;
private TypeDef _holderTypeDef; private TypeDef _holderTypeDef;
@ -28,10 +32,16 @@ namespace Obfuz.Emit
private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>(); private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>();
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; _module = mod;
_random = random;
} }
const int maxFieldCount = 1000; const int maxFieldCount = 1000;
@ -116,6 +126,21 @@ namespace Obfuz.Emit
// throw new NotImplementedException(); // 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) private void CreateCCtorOfRvaTypeDef(TypeDef type)
{ {
var cctor = new MethodDefUser(".cctor", 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) })); //IMethod method = _module.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
//Assert.IsNotNull(method); //Assert.IsNotNull(method);
DefaultModuleMetadataImporter importer = GetModuleMetadataImporter();
// TODO. obfuscate init codes // TODO. obfuscate init codes
foreach (var field in type.Fields) foreach (var field in type.Fields)
{ {
ConstFieldInfo constInfo = _field2Fields[field]; ConstFieldInfo constInfo = _field2Fields[field];
int ops = GenerateEncryptionOperations();
int salt = GenerateSalt();
switch (constInfo.value) switch (constInfo.value)
{ {
case int i: case int i:
ins.Add(Instruction.Create(OpCodes.Ldc_I4, i)); {
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; break;
}
case long l: case long l:
ins.Add(Instruction.Create(OpCodes.Ldc_I8, l)); {
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; break;
}
case float f: case float f:
ins.Add(Instruction.Create(OpCodes.Ldc_R4, f)); {
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; break;
}
case double d: case double d:
ins.Add(Instruction.Create(OpCodes.Ldc_R8, d)); {
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; break;
}
case string s: case string s:
ins.Add(Instruction.Create(OpCodes.Ldstr, s)); {
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; break;
}
//case byte[] b: //case byte[] b:
// ins.Add(Instruction.Create(OpCodes.Ldlen, b.Length)); // ins.Add(Instruction.Create(OpCodes.Ldlen, b.Length));
// break; // break;
@ -173,23 +245,20 @@ namespace Obfuz.Emit
public class ConstFieldAllocator public class ConstFieldAllocator
{ {
private readonly IEncryptor _encryptor;
private readonly IRandom _random; private readonly IRandom _random;
private readonly RvaDataAllocator _rvaDataAllocator;
private readonly Dictionary<ModuleDef, ModuleConstFieldAllocator> _moduleAllocators = new Dictionary<ModuleDef, ModuleConstFieldAllocator>(); public ConstFieldAllocator(IEncryptor encryptor, IRandom random, RvaDataAllocator rvaDataAllocator)
public ConstFieldAllocator(IRandom random)
{ {
_encryptor = encryptor;
_random = random; _random = random;
_rvaDataAllocator = rvaDataAllocator;
} }
private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod) private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod)
{ {
if (!_moduleAllocators.TryGetValue(mod, out var moduleAllocator)) return EmitManager.Ins.GetEmitManager<ModuleConstFieldAllocator>(mod, m => new ModuleConstFieldAllocator(_encryptor, _random, _rvaDataAllocator));
{
moduleAllocator = new ModuleConstFieldAllocator(mod, _random);
_moduleAllocators[mod] = moduleAllocator;
}
return moduleAllocator;
} }
public FieldDef Allocate(ModuleDef mod, int value) public FieldDef Allocate(ModuleDef mod, int value)
@ -219,7 +288,7 @@ namespace Obfuz.Emit
public void Done() public void Done()
{ {
foreach (var moduleAllocator in _moduleAllocators.Values) foreach (var moduleAllocator in EmitManager.Ins.GetEmitManagers<ModuleConstFieldAllocator>())
{ {
moduleAllocator.Done(); moduleAllocator.Done();
} }

View File

@ -13,7 +13,6 @@ namespace Obfuz.ObfusPasses.ConstObfus
public class DefaultConstObfuscator : IDataObfuscator public class DefaultConstObfuscator : IDataObfuscator
{ {
private readonly IRandom _random; private readonly IRandom _random;
private readonly RandomDataNodeCreator _nodeCreator;
private readonly RvaDataAllocator _rvaDataAllocator; private readonly RvaDataAllocator _rvaDataAllocator;
private readonly ConstFieldAllocator _constFieldAllocator; private readonly ConstFieldAllocator _constFieldAllocator;
private readonly IEncryptor _encryptor; private readonly IEncryptor _encryptor;
@ -22,21 +21,8 @@ namespace Obfuz.ObfusPasses.ConstObfus
{ {
_random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5); _random = new RandomWithKey(new byte[] { 0x1, 0x2, 0x3, 0x4 }, 0x5);
_encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D }); _encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D });
_nodeCreator = new RandomDataNodeCreator(_random);
_rvaDataAllocator = new RvaDataAllocator(_random, _encryptor); _rvaDataAllocator = new RvaDataAllocator(_random, _encryptor);
_constFieldAllocator = new ConstFieldAllocator(_random); _constFieldAllocator = new ConstFieldAllocator(_encryptor, _random, _rvaDataAllocator);
}
private void CompileNode(IDataNode node, MethodDef method, List<Instruction> obfuscatedInstructions)
{
var ctx = new CompileContext
{
method = method,
output = obfuscatedInstructions,
rvaDataAllocator = _rvaDataAllocator,
constFieldAllocator = _constFieldAllocator,
};
node.Compile(ctx);
} }
private int GenerateEncryptionOperations() private int GenerateEncryptionOperations()
@ -134,21 +120,25 @@ namespace Obfuz.ObfusPasses.ConstObfus
public void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions) public void ObfuscateString(MethodDef method, string value, List<Instruction> obfuscatedInstructions)
{ {
int ops = GenerateEncryptionOperations(); //int ops = GenerateEncryptionOperations();
int salt = GenerateSalt(); //int salt = GenerateSalt();
int stringByteLength = Encoding.UTF8.GetByteCount(value); //int stringByteLength = Encoding.UTF8.GetByteCount(value);
byte[] encryptedValue = _encryptor.Encrypt(value, ops, salt); //byte[] encryptedValue = _encryptor.Encrypt(value, ops, salt);
Assert.IsTrue(encryptedValue.Length % 4 == 0); //Assert.IsTrue(encryptedValue.Length % 4 == 0);
RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue); //RvaData rvaData = _rvaDataAllocator.Allocate(method.Module, encryptedValue);
DefaultModuleMetadataImporter importer = GetModuleMetadataImporter(method); //DefaultModuleMetadataImporter importer = GetModuleMetadataImporter(method);
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); //obfuscatedInstructions.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(rvaData.offset)); //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. //// 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(stringByteLength));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops)); //obfuscatedInstructions.Add(Instruction.CreateLdcI4(ops));
obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt)); //obfuscatedInstructions.Add(Instruction.CreateLdcI4(salt));
obfuscatedInstructions.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); //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() public void Done()