Skip to content

Instantly share code, notes, and snippets.

@andyleap
Created January 7, 2017 15:57
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save andyleap/04e28138c1dbea032bd068e749e3b06e to your computer and use it in GitHub Desktop.
Attribute based detouring
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using Verse;
namespace RimLib
{
public class DetourAttribute : Attribute
{
public Type detourType;
public string Method;
public bool Static { get; set; } = false;
public DetourAttribute(Type detourType, string Method)
{
this.detourType = detourType;
this.Method = Method;
}
}
public class DetourPrivateAttribute : Attribute
{
public string detourType;
public string Method;
public bool Static { get; set; } = false;
public DetourPrivateAttribute(string detourType, string Method)
{
this.detourType = detourType;
this.Method = Method;
}
}
public static class Detours
{
private static List<string> detoured = new List<string>();
private static List<string> destinations = new List<string>();
public unsafe static bool TryDetourFromTo(MethodInfo source, MethodInfo destination)
{
if (source == null)
{
Debug.LogError("Detours - Source MethodInfo is null");
return false;
}
if (destination == null)
{
Debug.LogError("Detours - Destination MethodInfo is null");
return false;
}
string item = string.Concat(new string[]
{
source.DeclaringType.FullName,
".",
source.Name,
" @ 0x",
source.MethodHandle.GetFunctionPointer().ToString("X" + (IntPtr.Size * 2).ToString())
});
string item2 = string.Concat(new string[]
{
destination.DeclaringType.FullName,
".",
destination.Name,
" @ 0x",
destination.MethodHandle.GetFunctionPointer().ToString("X" + (IntPtr.Size * 2).ToString())
});
Detours.detoured.Add(item);
Detours.destinations.Add(item2);
Debug.Log("Detoured " + item + " to " + item2);
if (IntPtr.Size == 8)
{
long num = destination.MethodHandle.GetFunctionPointer().ToInt64();
byte* ptr = (byte*)source.MethodHandle.GetFunctionPointer().ToInt64();
long* ptr2 = (long*)(ptr + 2);
*ptr = 72;
ptr[1] = 184;
*ptr2 = num;
ptr[10] = 255;
ptr[11] = 224;
}
else
{
int num2 = source.MethodHandle.GetFunctionPointer().ToInt32();
int arg_1A6_0 = destination.MethodHandle.GetFunctionPointer().ToInt32();
byte* ptr3 = (byte*)num2;
int* ptr4 = (int*)(ptr3 + 1);
int num3 = arg_1A6_0 - num2 - 5;
*ptr3 = 233;
*ptr4 = num3;
}
return true;
}
public static void DetourAll()
{
foreach (Type type in Assembly.GetCallingAssembly().GetTypes())
{
var methods = type.GetMethods();
foreach (var method in methods)
{
var da = method.GetCustomAttributes(typeof(DetourAttribute), false);
if (da.Length > 0)
{
var dtype = (da[0] as DetourAttribute).detourType;
var target = dtype.GetMethod((da[0] as DetourAttribute).Method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if (!Detours.TryDetourFromTo(target, method))
{
Log.Error("Detour for " + dtype.Name + "." + (da[0] as DetourAttribute).Method + " failed");
}
}
var dpa = method.GetCustomAttributes(typeof(DetourPrivateAttribute), false);
if (dpa.Length > 0)
{
var dtype = dpa[0] as DetourPrivateAttribute;
Type find = null;
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
//var types = a.GetTypes();
find = a.GetType(dtype.detourType);
if (find != null)
{
break;
}
}
if (find == null)
{
Log.Error("Cannot find type " + dtype.detourType + " to detour");
}
else
{
var target = find.GetMethod(dtype.Method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if (!Detours.TryDetourFromTo(target, method))
{
Log.Error("Detour for " + dtype.detourType + "." + dtype.Method + " failed");
}
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment