支持常量加密和字符串缓存
parent
fda0e5c66d
commit
3a13c12594
|
@ -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<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;
|
||||
_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<ModuleDef, ModuleConstFieldAllocator> _moduleAllocators = new Dictionary<ModuleDef, ModuleConstFieldAllocator>();
|
||||
|
||||
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<ModuleConstFieldAllocator>(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<ModuleConstFieldAllocator>())
|
||||
{
|
||||
moduleAllocator.Done();
|
||||
}
|
|
@ -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<Instruction> 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<Instruction> 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()
|
||||
|
|
Loading…
Reference in New Issue