diff --git a/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs b/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs new file mode 100644 index 000000000..b271ee4a4 --- /dev/null +++ b/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs @@ -0,0 +1,33 @@ +using System; + +namespace Dalamud.Configuration.Internal +{ + /// + /// Environmental configuration settings. + /// + internal class EnvironmentConfiguration + { + /// + /// Gets a value indicating whether the DALAMUD_NOT_HAVE_INTERFACE setting has been enabled. + /// + public static bool DalamudNoInterface { get; } = GetEnvironmentVariable("DALAMUD_NOT_HAVE_INTERFACE"); + + /// + /// Gets a value indicating whether the XL_WINEONLINUX setting has been enabled. + /// + public static bool XlWineOnLinux { get; } = GetEnvironmentVariable("XL_WINEONLINUX"); + + /// + /// Gets a value indicating whether the DALAMUD_NOT_HAVE_PLUGINS setting has been enabled. + /// + public static bool DalamudNoPlugins { get; } = GetEnvironmentVariable("DALAMUD_NOT_HAVE_PLUGINS"); + + /// + /// Gets a value indicating whether the DalamudForceCoreHook setting has been enabled. + /// + public static bool DalamudForceCoreHook { get; } = GetEnvironmentVariable("DALAMUD_FORCE_COREHOOK"); + + private static bool GetEnvironmentVariable(string name) + => bool.Parse(Environment.GetEnvironmentVariable(name) ?? "false"); + } +} diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 803fd346b..beacf3a6b 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -186,7 +186,7 @@ namespace Dalamud Log.Information("[T2] LOC OK!"); - if (!bool.Parse(Environment.GetEnvironmentVariable("DALAMUD_NOT_HAVE_INTERFACE") ?? "false")) + if (!EnvironmentConfiguration.DalamudNoInterface) { try { diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 9415888d8..774f7aa25 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -64,6 +64,7 @@ + @@ -93,6 +94,12 @@ + + + PreserveNewest + + + diff --git a/Dalamud/Game/Network/Internal/WinSockHandlers.cs b/Dalamud/Game/Network/Internal/WinSockHandlers.cs index 68be91fb1..281291210 100644 --- a/Dalamud/Game/Network/Internal/WinSockHandlers.cs +++ b/Dalamud/Game/Network/Internal/WinSockHandlers.cs @@ -20,7 +20,7 @@ namespace Dalamud.Game.Network.Internal public WinSockHandlers() { this.ws2SocketHook = HookManager.DirtyLinuxUser ? null - : Hook.FromSymbol("ws2_32.dll", "socket", this.OnSocket); + : Hook.FromSymbol("ws2_32.dll", "socket", this.OnSocket, true); this.ws2SocketHook?.Enable(); } diff --git a/Dalamud/Hooking/Hook.cs b/Dalamud/Hooking/Hook.cs index feea082d7..25471a23f 100644 --- a/Dalamud/Hooking/Hook.cs +++ b/Dalamud/Hooking/Hook.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; +using Dalamud.Configuration.Internal; using Dalamud.Hooking.Internal; using Dalamud.Memory; using Reloaded.Hooks; @@ -16,6 +17,8 @@ namespace Dalamud.Hooking { private readonly IntPtr address; private readonly Reloaded.Hooks.Definitions.IHook hookImpl; + private readonly CoreHook.IHook coreHookImpl; + private readonly bool isCoreHook; /// /// Initializes a new instance of the class. @@ -24,8 +27,22 @@ namespace Dalamud.Hooking /// A memory address to install a hook. /// Callback function. Delegate must have a same original function prototype. public Hook(IntPtr address, T detour) + : this(address, detour, false) + { + } + + /// + /// Initializes a new instance of the class. + /// Hook is not activated until Enable() method is called. + /// Please do not use CoreHook unless you have thoroughly troubleshot why Reloaded does not work. + /// + /// A memory address to install a hook. + /// Callback function. Delegate must have a same original function prototype. + /// Use the corehook hooking library instead of Reloaded. + public Hook(IntPtr address, T detour, bool useCoreHook) { address = HookManager.FollowJmp(address); + this.isCoreHook = useCoreHook || EnvironmentConfiguration.DalamudForceCoreHook; var hasOtherHooks = HookManager.Originals.ContainsKey(address); if (!hasOtherHooks) @@ -35,7 +52,14 @@ namespace Dalamud.Hooking } this.address = address; - this.hookImpl = ReloadedHooks.Instance.CreateHook(detour, address.ToInt64()); + if (this.isCoreHook) + { + this.coreHookImpl = CoreHook.HookFactory.CreateHook(address, detour); + } + else + { + this.hookImpl = ReloadedHooks.Instance.CreateHook(detour, address.ToInt64()); + } HookManager.TrackedHooks.Add(new HookInfo(this, detour, Assembly.GetCallingAssembly())); } @@ -62,7 +86,14 @@ namespace Dalamud.Hooking get { this.CheckDisposed(); - return this.hookImpl.OriginalFunction; + if (this.isCoreHook) + { + return this.coreHookImpl.Original; + } + else + { + return this.hookImpl.OriginalFunction; + } } } @@ -74,7 +105,14 @@ namespace Dalamud.Hooking get { this.CheckDisposed(); - return this.hookImpl.IsHookEnabled; + if (this.isCoreHook) + { + return this.coreHookImpl.Enabled; + } + else + { + return this.hookImpl.IsHookEnabled; + } } } @@ -92,6 +130,19 @@ namespace Dalamud.Hooking /// Callback function. Delegate must have a same original function prototype. /// The hook with the supplied parameters. public static Hook FromSymbol(string moduleName, string exportName, T detour) + => FromSymbol(moduleName, exportName, detour, false); + + /// + /// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function. + /// The hook is not activated until Enable() method is called. + /// Please do not use CoreHook unless you have thoroughly troubleshot why Reloaded does not work. + /// + /// A name of the module currently loaded in the memory. (e.g. ws2_32.dll). + /// A name of the exported function name (e.g. send). + /// Callback function. Delegate must have a same original function prototype. + /// Use the corehook hooking library instead of Reloaded. + /// The hook with the supplied parameters. + public static Hook FromSymbol(string moduleName, string exportName, T detour, bool useCoreHook) { var moduleHandle = NativeFunctions.GetModuleHandleW(moduleName); if (moduleHandle == IntPtr.Zero) @@ -101,7 +152,7 @@ namespace Dalamud.Hooking if (procAddress == IntPtr.Zero) throw new Exception($"Could not get the address of {moduleName}::{exportName}"); - return new Hook(procAddress, detour); + return new Hook(procAddress, detour, useCoreHook); } /// @@ -112,10 +163,19 @@ namespace Dalamud.Hooking if (this.IsDisposed) return; - this.IsDisposed = true; + if (this.isCoreHook) + { + this.Disable(); + // Disposing CoreHook causes an APPCRASH on game exit. + // We already overwrite the original hook code, so there shouldn't be any real risk with not disposing here. + // this.coreHookImpl.Dispose(); + } + else + { + this.Disable(); + } - if (this.hookImpl.IsHookEnabled) - this.hookImpl.Disable(); + this.IsDisposed = true; } /// @@ -125,11 +185,19 @@ namespace Dalamud.Hooking { this.CheckDisposed(); - if (!this.hookImpl.IsHookActivated) - this.hookImpl.Activate(); + if (this.isCoreHook) + { + if (!this.coreHookImpl.Enabled) + this.coreHookImpl.Enabled = true; + } + else + { + if (!this.hookImpl.IsHookActivated) + this.hookImpl.Activate(); - if (!this.hookImpl.IsHookEnabled) - this.hookImpl.Enable(); + if (!this.hookImpl.IsHookEnabled) + this.hookImpl.Enable(); + } } /// @@ -139,11 +207,19 @@ namespace Dalamud.Hooking { this.CheckDisposed(); - if (!this.hookImpl.IsHookActivated) - return; + if (this.isCoreHook) + { + if (this.coreHookImpl.Enabled) + this.coreHookImpl.Enabled = false; + } + else + { + if (!this.hookImpl.IsHookActivated) + return; - if (this.hookImpl.IsHookEnabled) - this.hookImpl.Disable(); + if (this.hookImpl.IsHookEnabled) + this.hookImpl.Disable(); + } } /// diff --git a/Dalamud/Hooking/Internal/HookManager.cs b/Dalamud/Hooking/Internal/HookManager.cs index 483a0e4af..1f67ee1e8 100644 --- a/Dalamud/Hooking/Internal/HookManager.cs +++ b/Dalamud/Hooking/Internal/HookManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using Dalamud.Configuration.Internal; using Dalamud.Logging.Internal; using Dalamud.Memory; using Iced.Intel; @@ -40,7 +41,7 @@ namespace Dalamud.Hooking.Internal bool Check1() { - return Environment.GetEnvironmentVariable("XL_WINEONLINUX") != null; + return EnvironmentConfiguration.XlWineOnLinux; } bool Check2() diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index de477ae0d..150c050e7 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -95,7 +95,7 @@ namespace Dalamud.Interface.Internal } this.setCursorHook = HookManager.DirtyLinuxUser ? null - : Hook.FromSymbol("user32.dll", "SetCursor", this.SetCursorDetour); + : Hook.FromSymbol("user32.dll", "SetCursor", this.SetCursorDetour, true); this.presentHook = new Hook(this.address.Present, this.PresentDetour); this.resizeBuffersHook = new Hook(this.address.ResizeBuffers, this.ResizeBuffersDetour); diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index e1d3e0171..536f9e48e 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -56,8 +56,8 @@ namespace Dalamud.Plugin.Internal if (!this.devPluginDirectory.Exists) this.devPluginDirectory.Create(); - var noPlugins = bool.Parse(Environment.GetEnvironmentVariable("DALAMUD_NOT_HAVE_PLUGINS") ?? "false"); - if (this.SafeMode = noPlugins || configuration.PluginSafeMode) + this.SafeMode = EnvironmentConfiguration.DalamudNoPlugins || configuration.PluginSafeMode; + if (this.SafeMode) { configuration.PluginSafeMode = false; configuration.Save(); diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs index 14440e48b..e2e892b77 100644 --- a/Dalamud/Support/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -74,6 +74,7 @@ namespace Dalamud.Support DoPluginTest = configuration.DoPluginTest, InterfaceLoaded = interfaceManager?.IsReady ?? false, ThirdRepo = configuration.ThirdRepoList, + ForcedCoreHook = EnvironmentConfiguration.DalamudForceCoreHook, }; var encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload))); @@ -112,6 +113,8 @@ namespace Dalamud.Support public bool InterfaceLoaded { get; set; } + public bool ForcedCoreHook { get; set; } + public List ThirdRepo { get; set; } } } diff --git a/Dalamud/corehook64.dll b/Dalamud/corehook64.dll new file mode 100644 index 000000000..9b21a40d1 Binary files /dev/null and b/Dalamud/corehook64.dll differ