Переглянути джерело

Improve trampoline logging and debugging

Bepis 4 роки тому
батько
коміт
2c2b44588e

+ 17 - 1
BepInEx.IL2CPP/Hook/FastNativeDetour.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Reflection;
 using System.Runtime.InteropServices;
+using BepInEx.Logging;
 using MonoMod.RuntimeDetour;
 using MonoMod.Utils;
 
@@ -37,7 +38,22 @@ namespace BepInEx.IL2CPP.Hook
 
 		public void Apply()
 		{
-			TrampolinePtr = TrampolineGenerator.Generate(OriginalFuncPtr, DetourFuncPtr, out int trampolineLength);
+			Apply(null);
+		}
+
+
+		public void Apply(ManualLogSource debuggerLogSource)
+		{
+			if (IsApplied)
+				return;
+
+			int trampolineLength;
+
+			if (debuggerLogSource == null)
+				TrampolinePtr = TrampolineGenerator.Generate(OriginalFuncPtr, DetourFuncPtr, out trampolineLength);
+			else
+				TrampolinePtr = TrampolineGenerator.Generate(debuggerLogSource, OriginalFuncPtr, DetourFuncPtr, out trampolineLength);
+
 			TrampolineSize = trampolineLength;
 
 			IsApplied = true;

+ 31 - 10
BepInEx.IL2CPP/Hook/TrampolineGenerator.cs

@@ -12,11 +12,14 @@ namespace BepInEx.IL2CPP
 		public static IntPtr Generate(IntPtr originalFunctionPtr, IntPtr patchedFunctionPtr, out int trampolineLength)
 		{
 			var trampolineAlloc = DetourHelper.Native.MemAlloc(80);
-			DetourHelper.Native.MakeExecutable(trampolineAlloc, 80);
-			DetourHelper.Native.MakeWritable(originalFunctionPtr, 24);
+			DetourHelper.Native.MakeWritable(originalFunctionPtr, 32);
+			DetourHelper.Native.MakeWritable(trampolineAlloc, 80);
 
 			trampolineLength = Generate(originalFunctionPtr, patchedFunctionPtr, trampolineAlloc, IntPtr.Size == 8 ? 64 : 32);
 
+			DetourHelper.Native.MakeExecutable(trampolineAlloc, (uint)trampolineLength);
+			DetourHelper.Native.MakeExecutable(originalFunctionPtr, 32);
+
 			return trampolineAlloc;
 		}
 
@@ -35,37 +38,51 @@ namespace BepInEx.IL2CPP
 				decoder.Decode(out var instr);
 				formatter.Format(instr, output);
 				logSource.LogDebug($"{instr.IP:X16} {output.ToStringAndReset()}");
+
+				if (instr.Code == Code.Jmp_rm64 && instr.Immediate32 == 0) // && instr.IsIPRelativeMemoryOperand && instr.IPRelativeMemoryAddress = 6
+				{
+					byte[] address = new byte[8];
+
+					for (int i = 0; i < 8; i++)
+						address[i] = (byte)codeReader.ReadByte();
+
+					logSource.LogDebug($"{(instr.IP + (ulong)instr.Length):X16} db 0x{BitConverter.ToUInt64(address, 0):X16}");
+					decoder.IP += 8;
+				}
 			}
 		}
 
-		public static IntPtr Generate(ManualLogSource logSource, IntPtr originalFunctionPtr, IntPtr patchedFunctionPtr)
+		public static IntPtr Generate(ManualLogSource logSource, IntPtr originalFunctionPtr, IntPtr patchedFunctionPtr, out int trampolineLength)
 		{
 			logSource.LogDebug($"DoHook 0x{originalFunctionPtr.ToString("X")} -> 0x{patchedFunctionPtr.ToString("X")}");
 
 			var trampolineAlloc = DetourHelper.Native.MemAlloc(80);
-			DetourHelper.Native.MakeExecutable(trampolineAlloc, 80);
-			DetourHelper.Native.MakeWritable(originalFunctionPtr, 24);
+			DetourHelper.Native.MakeWritable(originalFunctionPtr, 32);
+			DetourHelper.Native.MakeWritable(trampolineAlloc, 80);
 
 			logSource.LogDebug($"Trampoline allocation: 0x{trampolineAlloc.ToString("X")}");
 
 
-			logSource.LogDebug("Original (24) asm");
+			logSource.LogDebug("Original (32) asm");
 
 
-			Disassemble(logSource, originalFunctionPtr, 24);
+			Disassemble(logSource, originalFunctionPtr, 32);
 
 
-			var trampolineLength = Generate(originalFunctionPtr, patchedFunctionPtr, trampolineAlloc, IntPtr.Size == 8 ? 64 : 32);
+			trampolineLength = Generate(originalFunctionPtr, patchedFunctionPtr, trampolineAlloc, IntPtr.Size == 8 ? 64 : 32);
 
 
-			logSource.LogDebug("Modified (24) asm");
+			logSource.LogDebug("Modified (32) asm");
 
-			Disassemble(logSource, originalFunctionPtr, 24);
+			Disassemble(logSource, originalFunctionPtr, 32);
 
 			logSource.LogDebug($"Trampoline ({trampolineLength}) asm");
 
 			Disassemble(logSource, trampolineAlloc, trampolineLength);
 
+			DetourHelper.Native.MakeExecutable(trampolineAlloc, 80);
+			DetourHelper.Native.MakeExecutable(originalFunctionPtr, 32);
+
 			return trampolineAlloc;
 		}
 
@@ -166,6 +183,10 @@ namespace BepInEx.IL2CPP
 
 			Marshal.Copy(generatedJmp, 0, originalFunctionPtr, (int)requiredBytes);
 
+			// Fill overwritten instructions with NOP
+			for (int i = (int)requiredBytes; i < totalBytes; i++)
+				Marshal.WriteByte(originalFunctionPtr + i, 0x90);
+
 			return newCode.Length;
 		}
 

+ 22 - 4
BepInEx.IL2CPP/IL2CPPChainloader.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
 using System.Reflection;
@@ -71,7 +72,7 @@ namespace BepInEx.IL2CPP
 			{
 				IntPtr originalFunc = new IntPtr(*(void**)ptr);
 
-				var trampolinePtr = TrampolineGenerator.Generate(unhollowerLogSource, originalFunc, patchedFunctionPtr);
+				var trampolinePtr = TrampolineGenerator.Generate(unhollowerLogSource, originalFunc, patchedFunctionPtr, out _);
 
 				*(void**)ptr = (void*)trampolinePtr;
 			};
@@ -83,18 +84,25 @@ namespace BepInEx.IL2CPP
 
 			PreloaderLogger.Log.LogDebug($"Runtime invoke pointer: 0x{functionPtr.ToInt64():X}");
 
-			var invokeDetour = new NativeDetour(functionPtr, Marshal.GetFunctionPointerForDelegate(new RuntimeInvokeDetour(OnInvokeMethod)), new NativeDetourConfig { ManualApply = true });
+			var invokeDetour = new NativeDetour(functionPtr, Marshal.GetFunctionPointerForDelegate(new RuntimeInvokeDetour(OnInvokeMethod)));
 
 			originalInvoke = invokeDetour.GenerateTrampoline<RuntimeInvokeDetour>();
 
+			//invokeDetour.Apply(unhollowerLogSource);
 			invokeDetour.Apply();
 		}
 
 		private static bool HasSet = false;
 
+		private static HashSet<string> recordedNames = new HashSet<string>();
 		private static IntPtr OnInvokeMethod(IntPtr method, IntPtr obj, IntPtr parameters, IntPtr exc)
 		{
 			string methodName = Marshal.PtrToStringAnsi(UnhollowerBaseLib.IL2CPP.il2cpp_method_get_name(method));
+			IntPtr methodClass = UnhollowerBaseLib.IL2CPP.il2cpp_method_get_class(method);
+			string methodClassName = Marshal.PtrToStringAnsi(UnhollowerBaseLib.IL2CPP.il2cpp_class_get_name(methodClass));
+			string methodClassNamespace = Marshal.PtrToStringAnsi(UnhollowerBaseLib.IL2CPP.il2cpp_class_get_namespace(methodClass));
+
+			string methodFullName = $"{methodClassNamespace}.{methodClassName}::{methodName}";
 
 			if (!HasSet && methodName == "Internal_ActiveSceneChanged")
 			{
@@ -114,9 +122,19 @@ namespace BepInEx.IL2CPP
 				HasSet = true;
 			}
 
-			//UnityLogSource.LogDebug(methodName);
+			var result = originalInvoke(method, obj, parameters, exc);
+
+			//UnityLogSource.LogDebug(methodName + " => " + result.ToString("X"));
+
+			if (!recordedNames.Contains(methodFullName))
+			{
+				UnityLogSource.LogDebug(methodFullName + " => " + result.ToString("X"));
+
+				lock (recordedNames)
+					recordedNames.Add(methodFullName);
+			}
 
-			return originalInvoke(method, obj, parameters, exc);
+			return result;
 		}
 
 		protected override void InitializeLoggers()