Created
January 7, 2017 15:57
-
-
Save andyleap/04e28138c1dbea032bd068e749e3b06e to your computer and use it in GitHub Desktop.
Attribute based detouring
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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