diff --git a/MelonLoader.Bootstrap/Logging/ConsoleHandler.cs b/MelonLoader.Bootstrap/Logging/ConsoleHandler.cs index 50e9dc31..9863c128 100644 --- a/MelonLoader.Bootstrap/Logging/ConsoleHandler.cs +++ b/MelonLoader.Bootstrap/Logging/ConsoleHandler.cs @@ -51,19 +51,7 @@ internal static class ConsoleHandler if (!string.IsNullOrEmpty(title)) Console.Title = title; -#if LINUX - PltHook.InstallHooks( - [ - ("fclose", Marshal.GetFunctionPointerForDelegate(HookFCloseDelegate)) - ]); -#endif - #if WINDOWS - PltHook.InstallHooks( - [ - ("CloseHandle", Marshal.GetFunctionPointerForDelegate(HookCloseHandleDelegate)), - ]); - Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true }); Console.SetError(new StreamWriter(Console.OpenStandardError()) { AutoFlush = true }); Console.SetIn(new StreamReader(Console.OpenStandardInput())); @@ -77,6 +65,21 @@ internal static class ConsoleHandler IsOpen = true; } + public static void InstallHooks() + { +#if LINUX + PltHook.InstallHooks( + [ + ("fclose", Marshal.GetFunctionPointerForDelegate(HookFCloseDelegate)) + ]); +#elif WINDOWS + PltHook.InstallHooks( + [ + ("CloseHandle", Marshal.GetFunctionPointerForDelegate(HookCloseHandleDelegate)), + ]); +#endif + } + public static void NullHandles() { #if WINDOWS diff --git a/MelonLoader.Bootstrap/Logging/MelonLogger.cs b/MelonLoader.Bootstrap/Logging/MelonLogger.cs index 7c35d8be..293396f0 100644 --- a/MelonLoader.Bootstrap/Logging/MelonLogger.cs +++ b/MelonLoader.Bootstrap/Logging/MelonLogger.cs @@ -105,6 +105,8 @@ internal static class MelonLogger { Core.Logger.Error("Failed to create any log files. Logging to console only"); } + + ConsoleHandler.InstallHooks(); if (LoaderConfig.Current.Loader.CapturePlayerLogs) { @@ -131,7 +133,7 @@ internal static class MelonLogger file.WriteLine(log); } } - + public static void Log(ColorARGB msgColor, ReadOnlySpan msg, ReadOnlySpan strippedMessage) { var time = DateTime.Now.ToString(timeFormat); diff --git a/MelonLoader.Bootstrap/RuntimeHandlers/Dotnet/DotnetHandler.cs b/MelonLoader.Bootstrap/RuntimeHandlers/Dotnet/DotnetHandler.cs index e7cb023c..0e59601b 100644 --- a/MelonLoader.Bootstrap/RuntimeHandlers/Dotnet/DotnetHandler.cs +++ b/MelonLoader.Bootstrap/RuntimeHandlers/Dotnet/DotnetHandler.cs @@ -159,7 +159,7 @@ internal static class DotnetHandler catch (Exception ex) { if (LoaderConfig.Current.Loader.DebugMode) - MelonLogger.LogError(ex.ToString()); + Core.Logger.Error(ex.ToString()); return false; } @@ -174,7 +174,7 @@ internal static class DotnetHandler catch (Exception ex) { if (LoaderConfig.Current.Loader.DebugMode) - MelonLogger.LogError(ex.ToString()); + Core.Logger.Error(ex.ToString()); return false; } @@ -199,7 +199,7 @@ internal static class DotnetHandler catch (Exception ex) { if (LoaderConfig.Current.Loader.DebugMode) - MelonLogger.LogError(ex.ToString()); + Core.Logger.Error(ex.ToString()); } // Restore Original Root and Path @@ -211,7 +211,7 @@ internal static class DotnetHandler catch (Exception ex) { if (LoaderConfig.Current.Loader.DebugMode) - MelonLogger.LogError(ex.ToString()); + Core.Logger.Error(ex.ToString()); } return false; diff --git a/MelonLoader.Bootstrap/Utils/PltHook.cs b/MelonLoader.Bootstrap/Utils/PltHook.cs index 6db26663..0dec6261 100644 --- a/MelonLoader.Bootstrap/Utils/PltHook.cs +++ b/MelonLoader.Bootstrap/Utils/PltHook.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using MelonLoader.Bootstrap.Logging; namespace MelonLoader.Bootstrap; @@ -36,19 +35,21 @@ internal static partial class PltHook private static partial nint PlthookError(); private static bool WasError; - private static string? PlayerFileName; + private static string? PlayerFilePath; + private static nint PlayerModuleHandle; private const string UnityPlayerLibName = "UnityPlayer"; internal static void InstallHooks(List<(string functionName, nint hookFunctionPtr)> hooks) { - if (!EnsureUnityPlayerLibrary()) + if (!FindUnityPlayerLibrary() + || !LoadUnityPlayerLibrary()) return; nint pltHook = IntPtr.Zero; - if (PlthookOpen(ref pltHook, PlayerFileName) != 0) + if (PlthookOpenByHandle(ref pltHook, PlayerModuleHandle) != 0) { - MelonLogger.LogError($"plthook_open error: {Marshal.PtrToStringAuto(PlthookError())}"); - PlayerFileName = null; + Core.Logger.Error($"plthook_open error: {Marshal.PtrToStringAuto(PlthookError())}"); + PlayerFilePath = null; WasError = true; return; } @@ -68,21 +69,45 @@ internal static partial class PltHook PlthookClose(pltHook); } - private static bool EnsureUnityPlayerLibrary() + private static bool LoadUnityPlayerLibrary() + { + if (WasError) + return false; + if (PlayerModuleHandle != IntPtr.Zero) + return true; + + MelonDebug.Log($"Attempting to use UnityPlayer: '{PlayerFilePath}'"); + +#if WINDOWS + PlayerModuleHandle = WindowsNative.LoadLibrary(PlayerFilePath!); +#else + PlayerModuleHandle = LibcNative.Dlopen(PlayerFilePath!, LibcNative.RtldLazy | LibcNative.RtldNoLoad); +#endif + if (PlayerModuleHandle == IntPtr.Zero) + { + Core.Logger.Error($"Failed to load {PlayerFilePath}, cannot apply plt hooks"); + PlayerModuleHandle = IntPtr.Zero; + PlayerFilePath = null; + WasError = true; + return false; + } + + Core.Logger.Msg($"Using UnityPlayer: '{PlayerFilePath}'"); + return true; + } + + private static bool FindUnityPlayerLibrary() { if (WasError) return false; - if (!string.IsNullOrEmpty(PlayerFileName)) + if (!string.IsNullOrEmpty(PlayerFilePath)) return true; - PlayerFileName = Process.GetCurrentProcess().Modules.OfType() + PlayerFilePath = Process.GetCurrentProcess().Modules.OfType() .FirstOrDefault(x => x.FileName.Contains(UnityPlayerLibName))?.FileName; - if (!string.IsNullOrEmpty(PlayerFileName)) - { - MelonDebug.Log($"Attempting to use UnityPlayer: '{PlayerFileName}'"); + if (!string.IsNullOrEmpty(PlayerFilePath)) return true; - } string processModulePath = Process.GetCurrentProcess().MainModule!.FileName; string parentPlayerPath = Path.GetDirectoryName(processModulePath)!; @@ -90,37 +115,36 @@ internal static partial class PltHook #if OSX string libName = $"{UnityPlayerLibName}.dylib"; parentPlayerPath = Path.Combine(Path.GetDirectoryName(parentPlayerPath)!, "Frameworks"); - PlayerFileName = Path.Combine(parentPlayerPath, libName); + PlayerFilePath = Path.Combine(parentPlayerPath, libName); #elif LINUX string libName = $"{UnityPlayerLibName}.so"; - PlayerFileName = Path.Combine(parentPlayerPath, libName); + PlayerFilePath = Path.Combine(parentPlayerPath, libName); #elif WINDOWS string libName = $"{UnityPlayerLibName}.dll"; - PlayerFileName = Path.Combine(parentPlayerPath, libName); + PlayerFilePath = Path.Combine(parentPlayerPath, libName); #endif #if !WINDOWS - if (!File.Exists(PlayerFileName)) + if (!File.Exists(PlayerFilePath)) { libName = $"lib{UnityPlayerLibName}.so"; - PlayerFileName = Path.Combine(parentPlayerPath, libName); + PlayerFilePath = Path.Combine(parentPlayerPath, libName); } - if (!File.Exists(PlayerFileName)) + if (!File.Exists(PlayerFilePath)) { libName = $"Lib{UnityPlayerLibName}.so"; - PlayerFileName = Path.Combine(parentPlayerPath, libName); + PlayerFilePath = Path.Combine(parentPlayerPath, libName); } #endif - if (!File.Exists(PlayerFileName)) + if (!File.Exists(PlayerFilePath)) { - MelonLogger.LogError($"Unable to find {UnityPlayerLibName} library to apply plthook"); - PlayerFileName = null; + Core.Logger.Error($"Unable to find {UnityPlayerLibName} library to apply plthook"); + PlayerFilePath = null; WasError = true; return false; } - MelonDebug.Log($"Attempting to use UnityPlayer: '{PlayerFileName}'"); return true; } } \ No newline at end of file diff --git a/MelonLoader.Bootstrap/WindowsNative.cs b/MelonLoader.Bootstrap/WindowsNative.cs index f4470187..4fd9de18 100644 --- a/MelonLoader.Bootstrap/WindowsNative.cs +++ b/MelonLoader.Bootstrap/WindowsNative.cs @@ -13,6 +13,10 @@ internal static partial class WindowsNative [LibraryImport("kernel32.dll", EntryPoint = "GetProcAddress", StringMarshalling = StringMarshalling.Utf8)] [UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])] internal static partial nint GetProcAddress(nint hModule, string lpProcName); + + [LibraryImport("kernel32.dll", EntryPoint = "LoadLibraryA", StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])] + internal static partial nint LoadLibrary(string lpLibFileName); [LibraryImport("kernel32.dll")] [UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]