Merge pull request #646 from goatcorp/corehook

This commit is contained in:
goaaats 2021-10-21 01:47:32 +02:00 committed by GitHub
commit a7ac7b48cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 141 additions and 21 deletions

View file

@ -0,0 +1,33 @@
using System;
namespace Dalamud.Configuration.Internal
{
/// <summary>
/// Environmental configuration settings.
/// </summary>
internal class EnvironmentConfiguration
{
/// <summary>
/// Gets a value indicating whether the DALAMUD_NOT_HAVE_INTERFACE setting has been enabled.
/// </summary>
public static bool DalamudNoInterface { get; } = GetEnvironmentVariable("DALAMUD_NOT_HAVE_INTERFACE");
/// <summary>
/// Gets a value indicating whether the XL_WINEONLINUX setting has been enabled.
/// </summary>
public static bool XlWineOnLinux { get; } = GetEnvironmentVariable("XL_WINEONLINUX");
/// <summary>
/// Gets a value indicating whether the DALAMUD_NOT_HAVE_PLUGINS setting has been enabled.
/// </summary>
public static bool DalamudNoPlugins { get; } = GetEnvironmentVariable("DALAMUD_NOT_HAVE_PLUGINS");
/// <summary>
/// Gets a value indicating whether the DalamudForceCoreHook setting has been enabled.
/// </summary>
public static bool DalamudForceCoreHook { get; } = GetEnvironmentVariable("DALAMUD_FORCE_COREHOOK");
private static bool GetEnvironmentVariable(string name)
=> bool.Parse(Environment.GetEnvironmentVariable(name) ?? "false");
}
}

View file

@ -186,7 +186,7 @@ namespace Dalamud
Log.Information("[T2] LOC OK!"); Log.Information("[T2] LOC OK!");
if (!bool.Parse(Environment.GetEnvironmentVariable("DALAMUD_NOT_HAVE_INTERFACE") ?? "false")) if (!EnvironmentConfiguration.DalamudNoInterface)
{ {
try try
{ {

View file

@ -64,6 +64,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CheapLoc" Version="1.1.6" /> <PackageReference Include="CheapLoc" Version="1.1.6" />
<PackageReference Include="CoreHook" Version="1.0.4" />
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" /> <PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
<PackageReference Include="Lumina" Version="3.3.0" /> <PackageReference Include="Lumina" Version="3.3.0" />
<PackageReference Include="Lumina.Excel" Version="5.50.0" /> <PackageReference Include="Lumina.Excel" Version="5.50.0" />
@ -93,6 +94,12 @@
<AdditionalFiles Include="..\stylecop.json" /> <AdditionalFiles Include="..\stylecop.json" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="corehook64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<Target Name="AddRuntimeDependenciesToContent" BeforeTargets="GetCopyToOutputDirectoryItems" DependsOnTargets="GenerateBuildDependencyFile;GenerateBuildRuntimeConfigurationFiles"> <Target Name="AddRuntimeDependenciesToContent" BeforeTargets="GetCopyToOutputDirectoryItems" DependsOnTargets="GenerateBuildDependencyFile;GenerateBuildRuntimeConfigurationFiles">
<ItemGroup> <ItemGroup>
<ContentWithTargetPath Include="$(ProjectDepsFilePath)" CopyToOutputDirectory="PreserveNewest" TargetPath="$(ProjectDepsFileName)" /> <ContentWithTargetPath Include="$(ProjectDepsFilePath)" CopyToOutputDirectory="PreserveNewest" TargetPath="$(ProjectDepsFileName)" />

View file

@ -20,7 +20,7 @@ namespace Dalamud.Game.Network.Internal
public WinSockHandlers() public WinSockHandlers()
{ {
this.ws2SocketHook = HookManager.DirtyLinuxUser ? null this.ws2SocketHook = HookManager.DirtyLinuxUser ? null
: Hook<SocketDelegate>.FromSymbol("ws2_32.dll", "socket", this.OnSocket); : Hook<SocketDelegate>.FromSymbol("ws2_32.dll", "socket", this.OnSocket, true);
this.ws2SocketHook?.Enable(); this.ws2SocketHook?.Enable();
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Reflection; using System.Reflection;
using Dalamud.Configuration.Internal;
using Dalamud.Hooking.Internal; using Dalamud.Hooking.Internal;
using Dalamud.Memory; using Dalamud.Memory;
using Reloaded.Hooks; using Reloaded.Hooks;
@ -16,6 +17,8 @@ namespace Dalamud.Hooking
{ {
private readonly IntPtr address; private readonly IntPtr address;
private readonly Reloaded.Hooks.Definitions.IHook<T> hookImpl; private readonly Reloaded.Hooks.Definitions.IHook<T> hookImpl;
private readonly CoreHook.IHook<T> coreHookImpl;
private readonly bool isCoreHook;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Hook{T}"/> class. /// Initializes a new instance of the <see cref="Hook{T}"/> class.
@ -24,8 +27,22 @@ namespace Dalamud.Hooking
/// <param name="address">A memory address to install a hook.</param> /// <param name="address">A memory address to install a hook.</param>
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param> /// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
public Hook(IntPtr address, T detour) public Hook(IntPtr address, T detour)
: this(address, detour, false)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hook{T}"/> 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.
/// </summary>
/// <param name="address">A memory address to install a hook.</param>
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
/// <param name="useCoreHook">Use the corehook hooking library instead of Reloaded.</param>
public Hook(IntPtr address, T detour, bool useCoreHook)
{ {
address = HookManager.FollowJmp(address); address = HookManager.FollowJmp(address);
this.isCoreHook = useCoreHook || EnvironmentConfiguration.DalamudForceCoreHook;
var hasOtherHooks = HookManager.Originals.ContainsKey(address); var hasOtherHooks = HookManager.Originals.ContainsKey(address);
if (!hasOtherHooks) if (!hasOtherHooks)
@ -35,7 +52,14 @@ namespace Dalamud.Hooking
} }
this.address = address; this.address = address;
this.hookImpl = ReloadedHooks.Instance.CreateHook<T>(detour, address.ToInt64()); if (this.isCoreHook)
{
this.coreHookImpl = CoreHook.HookFactory.CreateHook<T>(address, detour);
}
else
{
this.hookImpl = ReloadedHooks.Instance.CreateHook<T>(detour, address.ToInt64());
}
HookManager.TrackedHooks.Add(new HookInfo(this, detour, Assembly.GetCallingAssembly())); HookManager.TrackedHooks.Add(new HookInfo(this, detour, Assembly.GetCallingAssembly()));
} }
@ -62,7 +86,14 @@ namespace Dalamud.Hooking
get get
{ {
this.CheckDisposed(); 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 get
{ {
this.CheckDisposed(); 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
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param> /// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
/// <returns>The hook with the supplied parameters.</returns> /// <returns>The hook with the supplied parameters.</returns>
public static Hook<T> FromSymbol(string moduleName, string exportName, T detour) public static Hook<T> FromSymbol(string moduleName, string exportName, T detour)
=> FromSymbol(moduleName, exportName, detour, false);
/// <summary>
/// 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.
/// </summary>
/// <param name="moduleName">A name of the module currently loaded in the memory. (e.g. ws2_32.dll).</param>
/// <param name="exportName">A name of the exported function name (e.g. send).</param>
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
/// <param name="useCoreHook">Use the corehook hooking library instead of Reloaded.</param>
/// <returns>The hook with the supplied parameters.</returns>
public static Hook<T> FromSymbol(string moduleName, string exportName, T detour, bool useCoreHook)
{ {
var moduleHandle = NativeFunctions.GetModuleHandleW(moduleName); var moduleHandle = NativeFunctions.GetModuleHandleW(moduleName);
if (moduleHandle == IntPtr.Zero) if (moduleHandle == IntPtr.Zero)
@ -101,7 +152,7 @@ namespace Dalamud.Hooking
if (procAddress == IntPtr.Zero) if (procAddress == IntPtr.Zero)
throw new Exception($"Could not get the address of {moduleName}::{exportName}"); throw new Exception($"Could not get the address of {moduleName}::{exportName}");
return new Hook<T>(procAddress, detour); return new Hook<T>(procAddress, detour, useCoreHook);
} }
/// <summary> /// <summary>
@ -112,10 +163,19 @@ namespace Dalamud.Hooking
if (this.IsDisposed) if (this.IsDisposed)
return; 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.IsDisposed = true;
this.hookImpl.Disable();
} }
/// <summary> /// <summary>
@ -125,11 +185,19 @@ namespace Dalamud.Hooking
{ {
this.CheckDisposed(); this.CheckDisposed();
if (!this.hookImpl.IsHookActivated) if (this.isCoreHook)
this.hookImpl.Activate(); {
if (!this.coreHookImpl.Enabled)
this.coreHookImpl.Enabled = true;
}
else
{
if (!this.hookImpl.IsHookActivated)
this.hookImpl.Activate();
if (!this.hookImpl.IsHookEnabled) if (!this.hookImpl.IsHookEnabled)
this.hookImpl.Enable(); this.hookImpl.Enable();
}
} }
/// <summary> /// <summary>
@ -139,11 +207,19 @@ namespace Dalamud.Hooking
{ {
this.CheckDisposed(); this.CheckDisposed();
if (!this.hookImpl.IsHookActivated) if (this.isCoreHook)
return; {
if (this.coreHookImpl.Enabled)
this.coreHookImpl.Enabled = false;
}
else
{
if (!this.hookImpl.IsHookActivated)
return;
if (this.hookImpl.IsHookEnabled) if (this.hookImpl.IsHookEnabled)
this.hookImpl.Disable(); this.hookImpl.Disable();
}
} }
/// <summary> /// <summary>

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Configuration.Internal;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
using Dalamud.Memory; using Dalamud.Memory;
using Iced.Intel; using Iced.Intel;
@ -40,7 +41,7 @@ namespace Dalamud.Hooking.Internal
bool Check1() bool Check1()
{ {
return Environment.GetEnvironmentVariable("XL_WINEONLINUX") != null; return EnvironmentConfiguration.XlWineOnLinux;
} }
bool Check2() bool Check2()

View file

@ -95,7 +95,7 @@ namespace Dalamud.Interface.Internal
} }
this.setCursorHook = HookManager.DirtyLinuxUser ? null this.setCursorHook = HookManager.DirtyLinuxUser ? null
: Hook<SetCursorDelegate>.FromSymbol("user32.dll", "SetCursor", this.SetCursorDetour); : Hook<SetCursorDelegate>.FromSymbol("user32.dll", "SetCursor", this.SetCursorDetour, true);
this.presentHook = new Hook<PresentDelegate>(this.address.Present, this.PresentDetour); this.presentHook = new Hook<PresentDelegate>(this.address.Present, this.PresentDetour);
this.resizeBuffersHook = new Hook<ResizeBuffersDelegate>(this.address.ResizeBuffers, this.ResizeBuffersDetour); this.resizeBuffersHook = new Hook<ResizeBuffersDelegate>(this.address.ResizeBuffers, this.ResizeBuffersDetour);

View file

@ -56,8 +56,8 @@ namespace Dalamud.Plugin.Internal
if (!this.devPluginDirectory.Exists) if (!this.devPluginDirectory.Exists)
this.devPluginDirectory.Create(); this.devPluginDirectory.Create();
var noPlugins = bool.Parse(Environment.GetEnvironmentVariable("DALAMUD_NOT_HAVE_PLUGINS") ?? "false"); this.SafeMode = EnvironmentConfiguration.DalamudNoPlugins || configuration.PluginSafeMode;
if (this.SafeMode = noPlugins || configuration.PluginSafeMode) if (this.SafeMode)
{ {
configuration.PluginSafeMode = false; configuration.PluginSafeMode = false;
configuration.Save(); configuration.Save();

View file

@ -74,6 +74,7 @@ namespace Dalamud.Support
DoPluginTest = configuration.DoPluginTest, DoPluginTest = configuration.DoPluginTest,
InterfaceLoaded = interfaceManager?.IsReady ?? false, InterfaceLoaded = interfaceManager?.IsReady ?? false,
ThirdRepo = configuration.ThirdRepoList, ThirdRepo = configuration.ThirdRepoList,
ForcedCoreHook = EnvironmentConfiguration.DalamudForceCoreHook,
}; };
var encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload))); var encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload)));
@ -112,6 +113,8 @@ namespace Dalamud.Support
public bool InterfaceLoaded { get; set; } public bool InterfaceLoaded { get; set; }
public bool ForcedCoreHook { get; set; }
public List<ThirdPartyRepoSettings> ThirdRepo { get; set; } public List<ThirdPartyRepoSettings> ThirdRepo { get; set; }
} }
} }

BIN
Dalamud/corehook64.dll Normal file

Binary file not shown.