|
using HarmonyLib;
|
|
using IPA.Logging;
|
|
using MonoMod.RuntimeDetour;
|
|
using System;
|
|
using System.Reflection;
|
|
|
|
namespace IPA.Loader
|
|
{
|
|
internal static class HarmonyProtectorProxy
|
|
{
|
|
public static void ProtectNull() => HarmonyProtector.Protect();
|
|
}
|
|
|
|
internal static class HarmonyProtector
|
|
{
|
|
public static void Protect()
|
|
{
|
|
var guid = Guid.NewGuid().ToString("N");
|
|
var id = guid.Remove(new Random().Next(7, guid.Length - 1));
|
|
var harmony = new Harmony(id);
|
|
|
|
var unpatchByTypeOrId = AccessTools.Method(typeof(PatchProcessor), nameof(PatchProcessor.Unpatch), new[] { typeof(HarmonyPatchType), typeof(string) });
|
|
var unpatchMethod = AccessTools.Method(typeof(PatchProcessor), nameof(PatchProcessor.Unpatch), new[] { typeof(MethodInfo) });
|
|
var processPatchJob = AccessTools.Method(typeof(PatchClassProcessor), "ProcessPatchJob");
|
|
var patch = AccessTools.Method(typeof(PatchProcessor), nameof(PatchProcessor.Patch));
|
|
|
|
var unpatchPrefix = AccessTools.Method(typeof(HarmonyProtector), nameof(PatchProcessor_Unpatch_Prefix));
|
|
var processPatchJobPrefix = AccessTools.Method(typeof(HarmonyProtector), nameof(PatchClassProcessor_ProcessPatchJob_Prefix));
|
|
var patchPrefix = AccessTools.Method(typeof(HarmonyProtector), nameof(PatchProcessor_Patch_Prefix));
|
|
|
|
harmony.Patch(unpatchByTypeOrId, new HarmonyMethod(unpatchPrefix));
|
|
harmony.Patch(unpatchMethod, new HarmonyMethod(unpatchPrefix));
|
|
harmony.Patch(processPatchJob, new HarmonyMethod(processPatchJobPrefix));
|
|
harmony.Patch(patch, new HarmonyMethod(patchPrefix));
|
|
}
|
|
|
|
private static bool ShouldBlockExecution(MethodBase methodBase)
|
|
{
|
|
var getIdentifiable = AccessTools.Method(typeof(DetourHelper), nameof(DetourHelper.GetIdentifiable)).GetIdentifiable();
|
|
var getValue = AccessTools.Method(typeof(FieldInfo), nameof(FieldInfo.GetValue)).GetIdentifiable();
|
|
var declaringTypeGetter = AccessTools.PropertyGetter(typeof(MemberInfo), nameof(MemberInfo.DeclaringType)).GetIdentifiable();
|
|
var methodBaseEquals = AccessTools.Method(typeof(MethodBase), nameof(MethodBase.Equals)).GetIdentifiable();
|
|
var assemblyEquals = AccessTools.Method(typeof(Assembly), nameof(Assembly.Equals)).GetIdentifiable();
|
|
var assemblyGetter = AccessTools.PropertyGetter(typeof(Type), nameof(Type.Assembly)).GetIdentifiable();
|
|
var getExecutingAssembly = AccessTools.Method(typeof(Assembly), nameof(Assembly.GetExecutingAssembly)).GetIdentifiable();
|
|
var method = methodBase.GetIdentifiable();
|
|
var assembly = method.DeclaringType!.Assembly;
|
|
return method.Equals(getIdentifiable) ||
|
|
method.Equals(getValue) ||
|
|
method.Equals(declaringTypeGetter) ||
|
|
method.Equals(methodBaseEquals) ||
|
|
method.Equals(assemblyEquals) ||
|
|
method.Equals(assemblyGetter) ||
|
|
method.Equals(getExecutingAssembly) ||
|
|
assembly.Equals(Assembly.GetExecutingAssembly()) ||
|
|
assembly.Equals(typeof(Harmony).Assembly);
|
|
}
|
|
|
|
private static bool PatchProcessor_Patch_Prefix(MethodBase ___original, ref MethodInfo __result)
|
|
{
|
|
if (ShouldBlockExecution(___original))
|
|
{
|
|
__result = ___original as MethodInfo;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool PatchClassProcessor_ProcessPatchJob_Prefix(object job)
|
|
{
|
|
var original = AccessTools.Field(job.GetType(), "original");
|
|
var methodBase = (MethodBase)original!.GetValue(job);
|
|
return !ShouldBlockExecution(methodBase);
|
|
}
|
|
|
|
private static bool PatchProcessor_Unpatch_Prefix(MethodBase ___original) => !ShouldBlockExecution(___original);
|
|
}
|
|
}
|