支持常量加密和字符串缓存
parent
fda0e5c66d
commit
3a13c12594
|
@ -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();
|
||||||
}
|
}
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue