Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion Il2CppInterop.HarmonySupport/Il2CppDetourMethodPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,22 @@ private static readonly MethodInfo ReportExceptionMethodInfo

private static readonly List<object> DelegateCache = new();
private static readonly List<object> DetourCache = new();
private readonly Dictionary<IntPtr, INativeMethodInfoStruct> modifiedNativeMethodInfoCache = new(); // key: income method info ptr
private static Dictionary<IntPtr, Il2CppDetourMethodPatcher> activePatchers = new();

private INativeMethodInfoStruct modifiedNativeMethodInfo;

private IDetour nativeDetour;

private INativeMethodInfoStruct originalNativeMethodInfo;

public static ThreadLocal<IntPtr> currentMethodInfoPointer = new();
private static readonly FieldInfo currentMethodInfoPointerFieldInfo =
typeof(Il2CppDetourMethodPatcher).GetField(nameof(currentMethodInfoPointer),
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
private static readonly MethodInfo currentMethodInfoPointerSetMethodInfo =
typeof(ThreadLocal<IntPtr>).GetProperty("Value")!.GetSetMethod();

/// <summary>
/// Constructs a new instance of <see cref="MonoMod.RuntimeDetour.NativeDetour" /> method patcher.
/// </summary>
Expand Down Expand Up @@ -105,6 +114,7 @@ private void Init()
Buffer.MemoryCopy(originalNativeMethodInfo.Pointer.ToPointer(),
modifiedNativeMethodInfo.Pointer.ToPointer(), UnityVersionHandler.MethodSize(),
UnityVersionHandler.MethodSize());
activePatchers[modifiedNativeMethodInfo.Pointer] = this;
IsValid = true;
}
catch (Exception e)
Expand All @@ -126,7 +136,9 @@ public override MethodBase DetourTo(MethodBase replacement)
{
// Point back to the original method before we unpatch
modifiedNativeMethodInfo.MethodPointer = originalNativeMethodInfo.MethodPointer;
activePatchers.Remove(nativeDetour.OriginalTrampoline);
nativeDetour.Dispose();
modifiedNativeMethodInfoCache.Clear();
}

// Generate a new DMD of the modified unhollowed method, and apply harmony patches to it
Expand Down Expand Up @@ -188,11 +200,33 @@ public override DynamicMethodDefinition CopyOriginal()
// Replace original IL2CPPMethodInfo pointer with a modified one that points to the trampoline
cursor
.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I8, modifiedNativeMethodInfo.Pointer.ToInt64())
.Emit(Mono.Cecil.Cil.OpCodes.Conv_I);
.Emit(Mono.Cecil.Cil.OpCodes.Conv_I)
.Emit(Mono.Cecil.Cil.OpCodes.Call, typeof(Il2CppDetourMethodPatcher).GetMethod(nameof(GetModifiedMethodInfoPointerTyped), BindingFlags.Static | BindingFlags.NonPublic));

return dmd;
}

private static IntPtr GetModifiedMethodInfoPointerTyped(IntPtr ptr)
{
if (!activePatchers.TryGetValue(ptr, out var patcher))
return ptr;

var incomeMethodInfoPtr = currentMethodInfoPointer.Value;
if (incomeMethodInfoPtr == IntPtr.Zero)
return ptr;

ref var nativeModifiedMethod = ref CollectionsMarshal.GetValueRefOrAddDefault(patcher.modifiedNativeMethodInfoCache, incomeMethodInfoPtr, out var exists);
if (!exists)
{
nativeModifiedMethod = UnityVersionHandler.NewMethod();
Buffer.MemoryCopy((void*)incomeMethodInfoPtr, nativeModifiedMethod.Pointer.ToPointer(), UnityVersionHandler.MethodSize(), UnityVersionHandler.MethodSize());

nativeModifiedMethod.MethodPointer = patcher.nativeDetour.OriginalTrampoline;
}

return nativeModifiedMethod.Pointer;
}

// Tries to guess whether a function needs a return buffer for the return struct, in all cases except win64 it's undefined behaviour
private static bool IsReturnBufferNeeded(int size)
{
Expand Down Expand Up @@ -273,6 +307,10 @@ private DynamicMethodDefinition GenerateNativeToManagedTrampoline(MethodInfo tar
var il = dmd.GetILGenerator();
il.BeginExceptionBlock();

il.Emit(OpCodes.Ldsfld, currentMethodInfoPointerFieldInfo);
il.Emit(OpCodes.Ldarg, unmanagedParams.Length - 1);
il.Emit(OpCodes.Call, currentMethodInfoPointerSetMethodInfo);

// Declare a list of variables to dereference back to the original pointers.
// This is required due to the needed interop type conversions, so we can't directly pass some addresses as byref types
var indirectVariables = new LocalBuilder[managedParams.Length];
Expand Down
1 change: 1 addition & 0 deletions Il2CppInterop.Runtime/Il2CppClassPointerStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ static Il2CppClassPointerStore()
if (!targetType.IsEnum)
{
RuntimeHelpers.RunClassConstructor(targetType.TypeHandle);

}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,9 @@ private void Hook(IntPtr obj, IntPtr data)
{
new()
{
// Among Us - 2020.3.22 (x86)
pattern = "\x55\x8B\xEC\x51\x56\x8B\x75\x08\xC7\x45\x00\x00\x00\x00\x00",
mask = "xxxxxxxxxx?????",
xref = false
},
new()
{
// Summer Vacation! Scramble - 2021.3.33 (x64)
pattern = "\x48\x89\x5c\x24\x10\x48\x89\x74\x24\x18\x57\x48\x83\xec\x20\x48\x8b\x19\x33\xff\x48\x89\x7c\x24\x30\x48\x8b\xf1\xf6\x83\x32\x01\x00\x00\x02\x75\x08\x48\x8b\xcb\xe8",
mask = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
xref = false,
},
new()
{
// Test Game - 2021.3.22 (x64)
pattern = "\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\x48\xC7\x44\x24\x30\x00\x00\x00\x00\x48\x8B",
mask = "xxxxxxxxxxxxxxxxxxxx",
xref = false,
},
new()
{
// V Rising - 2022.3.23 (x64)
pattern = "\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x83\xEC\x20\x48\x8B\x19",
pattern = "H\u0089\\$\u0010H\u0089t$\u0018WH\u0083ì H\u008b\u0019",
mask = "xxxxxxxxxxxxxxxxxx",
xref = false,
xref = false
}
};

Expand Down
Loading