重构 MetadataImporter

backup
walon 2025-05-07 19:39:09 +08:00
parent 3ee44663fb
commit 0ca1f8fe41
11 changed files with 194 additions and 81 deletions

View File

@ -2,6 +2,7 @@
using dnlib.DotNet.Emit;
using NUnit.Framework;
using Obfuz.Emit;
using Obfuz.Encryption;
using System.Collections.Generic;
namespace Obfuz.Emit

View File

@ -9,6 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using static UnityEngine.Networking.UnityWebRequest;
using UnityEngine.UIElements;
using Obfuz.Encryption;
namespace Obfuz.Emit
{

View File

@ -9,6 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using static UnityEngine.Networking.UnityWebRequest;
using UnityEngine.UIElements;
using Obfuz.Encryption;
namespace Obfuz.Emit
{

View File

@ -0,0 +1,69 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Obfuz.Emit
{
public interface IModuleEmitManager
{
void Init(ModuleDef mod);
}
public abstract class ModuleEmitManagerBase : IModuleEmitManager
{
public abstract void Init(ModuleDef mod);
}
public class EmitManager
{
public static EmitManager Ins { get; private set; }
private readonly Dictionary<(ModuleDef, Type), IModuleEmitManager> _moduleEmitManagers = new System.Collections.Generic.Dictionary<(ModuleDef, Type), IModuleEmitManager>();
public static void Reset()
{
Ins = new EmitManager();
}
public T GetEmitManager<T>(ModuleDef mod, Func<ModuleDef, T> creator = null) where T : IModuleEmitManager
{
var key = (mod, typeof(T));
if (_moduleEmitManagers.TryGetValue(key, out var emitManager))
{
return (T)emitManager;
}
else
{
T newEmitManager;
if (creator != null)
{
newEmitManager = creator(mod);
}
else
{
newEmitManager = (T)Activator.CreateInstance(typeof(T));
}
newEmitManager.Init(mod);
_moduleEmitManagers[key] = newEmitManager;
return newEmitManager;
}
}
public List<T> GetEmitManagers<T>() where T: IModuleEmitManager
{
var managers = new List<T>();
foreach (var kv in _moduleEmitManagers)
{
if (kv.Key.Item2 == typeof(T))
{
managers.Add((T)kv.Value);
}
}
return managers;
}
}
}

View File

@ -8,64 +8,67 @@ using UnityEngine.Assertions;
namespace Obfuz.Emit
{
public class ModuleMetadataImporter
public interface IModuleMetadataImporter
{
private readonly ModuleDef _module;
public ModuleMetadataImporter(ModuleDef module)
{
_module = module;
_module = module;
InitMetadatas(module);
void Init(ModuleDef mod);
}
private static IMethod s_castIntAsFloat;
private static IMethod s_castLongAsDouble;
private static IMethod s_castFloatAsInt;
private static IMethod s_castDoubleAsLong;
private void InitMetadatas(ModuleDef mod)
public abstract class ModuleMetadataImporterBase : IModuleMetadataImporter
{
if (s_castFloatAsInt != null)
{
return;
public abstract void Init(ModuleDef mod);
}
public class DefaultModuleMetadataImporter : ModuleMetadataImporterBase
{
public override void Init(ModuleDef mod)
{
_module = mod;
var constUtilityType = typeof(ConstUtility);
s_castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat"));
Assert.IsNotNull(s_castIntAsFloat, "CastIntAsFloat not found");
s_castLongAsDouble = mod.Import(constUtilityType.GetMethod("CastLongAsDouble"));
Assert.IsNotNull(s_castLongAsDouble, "CastLongAsDouble not found");
s_castFloatAsInt = mod.Import(constUtilityType.GetMethod("CastFloatAsInt"));
Assert.IsNotNull(s_castFloatAsInt, "CastFloatAsInt not found");
s_castDoubleAsLong = mod.Import(constUtilityType.GetMethod("CastDoubleAsLong"));
Assert.IsNotNull(s_castDoubleAsLong, "CastDoubleAsLong not found");
_castIntAsFloat = mod.Import(constUtilityType.GetMethod("CastIntAsFloat"));
Assert.IsNotNull(_castIntAsFloat, "CastIntAsFloat not found");
_castLongAsDouble = mod.Import(constUtilityType.GetMethod("CastLongAsDouble"));
Assert.IsNotNull(_castLongAsDouble, "CastLongAsDouble not found");
_castFloatAsInt = mod.Import(constUtilityType.GetMethod("CastFloatAsInt"));
Assert.IsNotNull(_castFloatAsInt, "CastFloatAsInt not found");
_castDoubleAsLong = mod.Import(constUtilityType.GetMethod("CastDoubleAsLong"));
Assert.IsNotNull(_castDoubleAsLong, "CastDoubleAsLong not found");
_initializeArray = mod.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
Assert.IsNotNull(_initializeArray);
_encryptBlock = mod.Import(typeof(EncryptionService).GetMethod("EncryptBlock", new[] { typeof(byte[]), typeof(long), typeof(int) }));
Assert.IsNotNull(_encryptBlock);
_decryptBlock = mod.Import(typeof(EncryptionService).GetMethod("DecryptBlock", new[] { typeof(byte[]), typeof(long), typeof(int) }));
Assert.IsNotNull(_decryptBlock);
}
public IMethod GetCastIntAsFloat()
{
return s_castIntAsFloat;
}
private ModuleDef _module;
private IMethod _castIntAsFloat;
private IMethod _castLongAsDouble;
private IMethod _castFloatAsInt;
private IMethod _castDoubleAsLong;
private IMethod _initializeArray;
private IMethod _encryptBlock;
private IMethod _decryptBlock;
public IMethod GetCastLongAsDouble()
{
return s_castLongAsDouble;
}
public IMethod CastIntAsFloat => _castIntAsFloat;
public IMethod GetCastFloatAsInt()
{
return s_castFloatAsInt;
}
public IMethod CastLongAsDouble => _castLongAsDouble;
public IMethod GetCastDoubleAsLong()
{
return s_castDoubleAsLong;
}
public IMethod CastFloatAsInt => _castFloatAsInt;
public IMethod CastDoubleAsLong => _castDoubleAsLong;
public IMethod InitializedArrayMethod => _initializeArray;
public IMethod EncryptBlock => _encryptBlock;
public IMethod DecryptBlock => _decryptBlock;
}
public class MetadataImporter
{
private readonly Dictionary<ModuleDef, ModuleMetadataImporter> _moduleMetadataImporters = new Dictionary<ModuleDef, ModuleMetadataImporter>();
private readonly Dictionary<(ModuleDef, Type), IModuleMetadataImporter> _customModuleMetadataImporters = new Dictionary<(ModuleDef, Type), IModuleMetadataImporter>();
public static MetadataImporter Instance { get; private set; }
@ -74,14 +77,46 @@ namespace Obfuz.Emit
Instance = new MetadataImporter();
}
public ModuleMetadataImporter GetModuleMetadataImporter(ModuleDef module)
public DefaultModuleMetadataImporter GetDefaultModuleMetadataImporter(ModuleDef module)
{
if (!_moduleMetadataImporters.TryGetValue(module, out var importer))
{
importer = new ModuleMetadataImporter(module);
_moduleMetadataImporters[module] = importer;
return GetCustomModuleMetadataImporter<DefaultModuleMetadataImporter>(module);
}
return importer;
public List<DefaultModuleMetadataImporter> GetDefaultModuleMetadataImporters()
{
return GetCustomModuleMetadataImporters<DefaultModuleMetadataImporter>();
}
public T GetCustomModuleMetadataImporter<T>(ModuleDef module, Func<ModuleDef, T> creator = null) where T : IModuleMetadataImporter
{
var key = (module, typeof(T));
if (!_customModuleMetadataImporters.TryGetValue(key, out var importer))
{
if (creator != null)
{
importer = creator(module);
}
else
{
importer = (IModuleMetadataImporter)Activator.CreateInstance(typeof(T), module);
}
importer.Init(module);
_customModuleMetadataImporters[key] = importer;
}
return (T)importer;
}
public List<T> GetCustomModuleMetadataImporters<T>()
{
var result = new List<T>();
foreach (var kvp in _customModuleMetadataImporters)
{
if (kvp.Key.Item2 == typeof(T))
{
result.Add((T)kvp.Value);
}
}
return result;
}
}
}

View File

@ -13,6 +13,8 @@ namespace Obfuz.Emit
public class EncryptionCompileContext
{
public ModuleDef module;
public DefaultModuleMetadataImporter DefaultModuleMetadataImporter => MetadataImporter.Instance.GetDefaultModuleMetadataImporter(module);
}
public interface IVariableTransformer
@ -234,10 +236,10 @@ namespace Obfuz.Emit
switch (_outputType)
{
case DataNodeType.Int32:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastFloatAsInt()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastFloatAsInt));
break;
case DataNodeType.Int64:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastDoubleAsLong()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastDoubleAsLong));
break;
default: throw new NotSupportedException($"Unsupported type: {_outputType}");
}
@ -248,10 +250,10 @@ namespace Obfuz.Emit
switch (_outputType)
{
case DataNodeType.Int32:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastIntAsFloat()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastIntAsFloat));
break;
case DataNodeType.Int64:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastLongAsDouble()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastLongAsDouble));
break;
default: throw new NotSupportedException($"Unsupported type: {_outputType}");
}
@ -312,10 +314,10 @@ namespace Obfuz.Emit
switch (_outputType)
{
case DataNodeType.Float32:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastIntAsFloat()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastIntAsFloat));
break;
case DataNodeType.Float64:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastLongAsDouble()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastLongAsDouble));
break;
default: throw new NotSupportedException($"Unsupported type: {_outputType}");
}
@ -326,10 +328,10 @@ namespace Obfuz.Emit
switch (_outputType)
{
case DataNodeType.Float32:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastFloatAsInt()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastFloatAsInt));
break;
case DataNodeType.Float64:
output.Add(Instruction.Create(OpCodes.Call, MetadataImporter.Instance.GetModuleMetadataImporter(ctx.module).GetCastDoubleAsLong()));
output.Add(Instruction.Create(OpCodes.Call, ctx.DefaultModuleMetadataImporter.CastDoubleAsLong));
break;
default: throw new NotSupportedException($"Unsupported type: {_outputType}");
}

View File

@ -1,5 +1,6 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Utils;
using System;
using System.Collections.Generic;
@ -8,7 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using UnityEngine.Assertions;
namespace Obfuz.Emit
namespace Obfuz.Encryption
{
public struct RvaData
{
@ -24,7 +25,7 @@ namespace Obfuz.Emit
}
}
public class ModuleRvaDataAllocator
public class ModuleRvaDataAllocator : ModuleEmitManagerBase
{
// randomized
const int maxRvaDataSize = 0x100;
@ -33,7 +34,6 @@ namespace Obfuz.Emit
private readonly IRandom _random;
private readonly IEncryptor _encryptor;
class RvaField
{
public FieldDef holderDataField;
@ -76,6 +76,11 @@ namespace Obfuz.Emit
_encryptor = encryptor;
}
public override void Init(ModuleDef mod)
{
}
private (FieldDef, FieldDef) CreateDataHolderRvaField(TypeDef dataHolderType)
{
if (_rvaTypeDef == null)
@ -230,10 +235,7 @@ namespace Obfuz.Emit
cctorMethod.Body = body;
var ins = body.Instructions;
IMethod initializeArrayMethod = mod.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new[] { typeof(Array), typeof(RuntimeFieldHandle) }));
IMethod decryptArrayMethod = mod.Import(typeof(EncryptionService).GetMethod("DecryptBlock", new[] { typeof(byte[]), typeof(long), typeof(int) }));
Assert.IsNotNull(initializeArrayMethod);
DefaultModuleMetadataImporter importer = MetadataImporter.Instance.GetDefaultModuleMetadataImporter(mod);
foreach (var field in _rvaFields)
{
// ldc
@ -248,12 +250,12 @@ namespace Obfuz.Emit
ins.Add(Instruction.Create(OpCodes.Dup));
ins.Add(Instruction.Create(OpCodes.Stsfld, field.runtimeValueField));
ins.Add(Instruction.Create(OpCodes.Ldtoken, field.holderDataField));
ins.Add(Instruction.Create(OpCodes.Call, initializeArrayMethod));
ins.Add(Instruction.Create(OpCodes.Call, importer.InitializedArrayMethod));
// EncryptionService.DecryptBlock(array, field.encryptionOps, field.salt);
ins.Add(Instruction.Create(OpCodes.Ldc_I8, field.encryptionOps));
ins.Add(Instruction.Create(OpCodes.Ldc_I4, field.salt));
ins.Add(Instruction.Create(OpCodes.Call, decryptArrayMethod));
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptBlock));
}
ins.Add(Instruction.Create(OpCodes.Ret));
@ -286,7 +288,6 @@ namespace Obfuz.Emit
private readonly IRandom _random;
private readonly IEncryptor _encryptor;
private readonly Dictionary<ModuleDef, ModuleRvaDataAllocator> _modules = new Dictionary<ModuleDef, ModuleRvaDataAllocator>();
public RvaDataAllocator(IRandom random, IEncryptor encryptor)
{
@ -296,12 +297,7 @@ namespace Obfuz.Emit
private ModuleRvaDataAllocator GetModuleRvaDataAllocator(ModuleDef mod)
{
if (!_modules.TryGetValue(mod, out var allocator))
{
allocator = new ModuleRvaDataAllocator(mod, _random, _encryptor);
_modules.Add(mod, allocator);
}
return allocator;
return EmitManager.Ins.GetEmitManager<ModuleRvaDataAllocator>(mod, mod => new ModuleRvaDataAllocator(mod, _random, _encryptor));
}
public RvaData Allocate(ModuleDef mod, int value)
@ -336,7 +332,7 @@ namespace Obfuz.Emit
public void Done()
{
foreach (var allocator in _modules.Values)
foreach (var allocator in EmitManager.Ins.GetEmitManagers<ModuleRvaDataAllocator>())
{
allocator.Done();
}

View File

@ -9,12 +9,18 @@ using System.Threading.Tasks;
using MethodImplAttributes = dnlib.DotNet.MethodImplAttributes;
using TypeAttributes = dnlib.DotNet.TypeAttributes;
namespace Obfuz.Emit
namespace Obfuz.ObfusPasses.CallObfus
{
public struct ProxyCallMethodData
{
public MethodDef proxyMethod;
public int secret;
public readonly MethodDef proxyMethod;
public readonly int secret;
public ProxyCallMethodData(MethodDef proxyMethod, int secret)
{
this.proxyMethod = proxyMethod;
this.secret = secret;
}
}
class ModuleDynamicProxyMethodAllocator
@ -161,7 +167,7 @@ namespace Obfuz.Emit
methodDispatcher.methods.Add(new CallInfo { method = method, callVir = callVir});
_methodProxys.Add(key, proxyInfo);
}
return new ProxyCallMethodData { proxyMethod = proxyInfo.proxyMethod, secret = proxyInfo.secret };
return new ProxyCallMethodData(proxyInfo.proxyMethod, proxyInfo.secret);
}
public void Done()

View File

@ -1,6 +1,7 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using Obfuz.Encryption;
using Obfuz.Utils;
using System;
using System.Collections.Generic;

View File

@ -38,6 +38,7 @@ namespace Obfuz
_obfuscatedAssemblyOutputDir = obfuscatedAssemblyOutputDir;
MetadataImporter.Reset();
EmitManager.Reset();
_assemblyCache = new AssemblyCache(new PathAssemblyResolver(assemblySearchDirs.ToArray()));
foreach (var pass in obfuscationPasses)
{

View File

@ -10,14 +10,14 @@ namespace Obfuz
{
private static readonly IEncryptor _encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D });
public static void EncryptBlock(byte[] data, int salt)
public static void EncryptBlock(byte[] data, long ops, int salt)
{
_encryptor.EncryptBlock(data, salt);
_encryptor.EncryptBlock(data, ops, salt);
}
public static void DecryptBlock(byte[] data, int salt)
public static void DecryptBlock(byte[] data, long ops, int salt)
{
_encryptor.DecryptBlock(data, salt);
_encryptor.DecryptBlock(data, ops, salt);
}
}
}