Improvements (#903)

This commit is contained in:
kizer 2022-06-29 18:51:40 +09:00 committed by GitHub
parent e9cd7e0273
commit 716736f022
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 1809 additions and 872 deletions

View file

@ -88,6 +88,22 @@ namespace Dalamud.Hooking
/// <exception cref="ObjectDisposedException">Hook is already disposed.</exception>
public virtual T Original => this.compatHookImpl != null ? this.compatHookImpl!.Original : throw new NotImplementedException();
/// <summary>
/// Gets a delegate function that can be used to call the actual function as if function is not hooked yet.
/// This can be called even after Dispose.
/// </summary>
public T OriginalDisposeSafe
{
get
{
if (this.compatHookImpl != null)
return this.compatHookImpl!.OriginalDisposeSafe;
if (this.IsDisposed)
return Marshal.GetDelegateForFunctionPointer<T>(this.address);
return this.Original;
}
}
/// <summary>
/// Gets a value indicating whether or not the hook is enabled.
/// </summary>
@ -115,14 +131,17 @@ namespace Dalamud.Hooking
/// <summary>
/// Creates a hook by rewriting import table address.
/// </summary>
/// <param name="module">Module to check for.</param>
/// <param name="module">Module to check for. Current process' main module if null.</param>
/// <param name="moduleName">Name of the DLL, including the extension.</param>
/// <param name="functionName">Decorated name of the function.</param>
/// <param name="hintOrOrdinal">Hint or ordinal. 0 to unspecify.</param>
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
/// <returns>The hook with the supplied parameters.</returns>
public static unsafe Hook<T> FromImport(ProcessModule module, string moduleName, string functionName, uint hintOrOrdinal, T detour)
public static unsafe Hook<T> FromImport(ProcessModule? module, string moduleName, string functionName, uint hintOrOrdinal, T detour)
{
module ??= Process.GetCurrentProcess().MainModule;
if (module == null)
throw new InvalidOperationException("Current module is null?");
var pDos = (PeHeader.IMAGE_DOS_HEADER*)module.BaseAddress;
var pNt = (PeHeader.IMAGE_FILE_HEADER*)(module.BaseAddress + (int)pDos->e_lfanew + 4);
var isPe64 = pNt->SizeOfOptionalHeader == Marshal.SizeOf<PeHeader.IMAGE_OPTIONAL_HEADER64>();

View file

@ -27,24 +27,27 @@ namespace Dalamud.Hooking.Internal
internal FunctionPointerVariableHook(IntPtr address, T detour, Assembly callingAssembly)
: base(address)
{
var hasOtherHooks = HookManager.Originals.ContainsKey(this.Address);
if (!hasOtherHooks)
lock (HookManager.HookEnableSyncRoot)
{
MemoryHelper.ReadRaw(this.Address, 0x32, out var original);
HookManager.Originals[this.Address] = original;
var hasOtherHooks = HookManager.Originals.ContainsKey(this.Address);
if (!hasOtherHooks)
{
MemoryHelper.ReadRaw(this.Address, 0x32, out var original);
HookManager.Originals[this.Address] = original;
}
if (!HookManager.MultiHookTracker.TryGetValue(this.Address, out var indexList))
indexList = HookManager.MultiHookTracker[this.Address] = new();
this.pfnOriginal = Marshal.ReadIntPtr(this.Address);
this.originalDelegate = Marshal.GetDelegateForFunctionPointer<T>(this.pfnOriginal);
this.detourDelegate = detour;
// Add afterwards, so the hookIdent starts at 0.
indexList.Add(this);
HookManager.TrackedHooks.TryAdd(Guid.NewGuid(), new HookInfo(this, detour, callingAssembly));
}
if (!HookManager.MultiHookTracker.TryGetValue(this.Address, out var indexList))
indexList = HookManager.MultiHookTracker[this.Address] = new();
this.pfnOriginal = Marshal.ReadIntPtr(this.Address);
this.originalDelegate = Marshal.GetDelegateForFunctionPointer<T>(this.pfnOriginal);
this.detourDelegate = detour;
// Add afterwards, so the hookIdent starts at 0.
indexList.Add(this);
HookManager.TrackedHooks.TryAdd(Guid.NewGuid(), new HookInfo(this, detour, callingAssembly));
}
/// <inheritdoc/>
@ -91,11 +94,15 @@ namespace Dalamud.Hooking.Internal
if (!this.enabled)
{
if (!NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(), MemoryProtection.ExecuteReadWrite, out var oldProtect))
throw new Win32Exception(Marshal.GetLastWin32Error());
lock (HookManager.HookEnableSyncRoot)
{
if (!NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(),
MemoryProtection.ExecuteReadWrite, out var oldProtect))
throw new Win32Exception(Marshal.GetLastWin32Error());
Marshal.WriteIntPtr(this.Address, Marshal.GetFunctionPointerForDelegate(this.detourDelegate));
NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(), oldProtect, out _);
Marshal.WriteIntPtr(this.Address, Marshal.GetFunctionPointerForDelegate(this.detourDelegate));
NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(), oldProtect, out _);
}
}
}
@ -106,11 +113,15 @@ namespace Dalamud.Hooking.Internal
if (this.enabled)
{
if (!NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(), MemoryProtection.ExecuteReadWrite, out var oldProtect))
throw new Win32Exception(Marshal.GetLastWin32Error());
lock (HookManager.HookEnableSyncRoot)
{
if (!NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(),
MemoryProtection.ExecuteReadWrite, out var oldProtect))
throw new Win32Exception(Marshal.GetLastWin32Error());
Marshal.WriteIntPtr(this.Address, this.pfnOriginal);
NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(), oldProtect, out _);
Marshal.WriteIntPtr(this.Address, this.pfnOriginal);
NativeFunctions.VirtualProtect(this.Address, (UIntPtr)Marshal.SizeOf<IntPtr>(), oldProtect, out _);
}
}
}
}

View file

@ -23,6 +23,11 @@ namespace Dalamud.Hooking.Internal
{
}
/// <summary>
/// Gets sync root object for hook enabling/disabling.
/// </summary>
internal static object HookEnableSyncRoot { get; } = new();
/// <summary>
/// Gets a static list of tracked and registered hooks.
/// </summary>

View file

@ -22,24 +22,27 @@ namespace Dalamud.Hooking.Internal
internal MinHookHook(IntPtr address, T detour, Assembly callingAssembly)
: base(address)
{
var hasOtherHooks = HookManager.Originals.ContainsKey(this.Address);
if (!hasOtherHooks)
lock (HookManager.HookEnableSyncRoot)
{
MemoryHelper.ReadRaw(this.Address, 0x32, out var original);
HookManager.Originals[this.Address] = original;
var hasOtherHooks = HookManager.Originals.ContainsKey(this.Address);
if (!hasOtherHooks)
{
MemoryHelper.ReadRaw(this.Address, 0x32, out var original);
HookManager.Originals[this.Address] = original;
}
if (!HookManager.MultiHookTracker.TryGetValue(this.Address, out var indexList))
indexList = HookManager.MultiHookTracker[this.Address] = new();
var index = (ulong)indexList.Count;
this.minHookImpl = new MinSharp.Hook<T>(this.Address, detour, index);
// Add afterwards, so the hookIdent starts at 0.
indexList.Add(this);
HookManager.TrackedHooks.TryAdd(Guid.NewGuid(), new HookInfo(this, detour, callingAssembly));
}
if (!HookManager.MultiHookTracker.TryGetValue(this.Address, out var indexList))
indexList = HookManager.MultiHookTracker[this.Address] = new();
var index = (ulong)indexList.Count;
this.minHookImpl = new MinSharp.Hook<T>(this.Address, detour, index);
// Add afterwards, so the hookIdent starts at 0.
indexList.Add(this);
HookManager.TrackedHooks.TryAdd(Guid.NewGuid(), new HookInfo(this, detour, callingAssembly));
}
/// <inheritdoc/>
@ -71,10 +74,13 @@ namespace Dalamud.Hooking.Internal
if (this.IsDisposed)
return;
this.minHookImpl.Dispose();
lock (HookManager.HookEnableSyncRoot)
{
this.minHookImpl.Dispose();
var index = HookManager.MultiHookTracker[this.Address].IndexOf(this);
HookManager.MultiHookTracker[this.Address][index] = null;
var index = HookManager.MultiHookTracker[this.Address].IndexOf(this);
HookManager.MultiHookTracker[this.Address][index] = null;
}
base.Dispose();
}
@ -86,7 +92,10 @@ namespace Dalamud.Hooking.Internal
if (!this.minHookImpl.Enabled)
{
this.minHookImpl.Enable();
lock (HookManager.HookEnableSyncRoot)
{
this.minHookImpl.Enable();
}
}
}
@ -97,7 +106,10 @@ namespace Dalamud.Hooking.Internal
if (this.minHookImpl.Enabled)
{
this.minHookImpl.Disable();
lock (HookManager.HookEnableSyncRoot)
{
this.minHookImpl.Disable();
}
}
}
}

View file

@ -19,16 +19,19 @@ namespace Dalamud.Hooking.Internal
internal ReloadedHook(IntPtr address, T detour, Assembly callingAssembly)
: base(address)
{
var hasOtherHooks = HookManager.Originals.ContainsKey(this.Address);
if (!hasOtherHooks)
lock (HookManager.HookEnableSyncRoot)
{
MemoryHelper.ReadRaw(this.Address, 0x32, out var original);
HookManager.Originals[this.Address] = original;
var hasOtherHooks = HookManager.Originals.ContainsKey(this.Address);
if (!hasOtherHooks)
{
MemoryHelper.ReadRaw(this.Address, 0x32, out var original);
HookManager.Originals[this.Address] = original;
}
this.hookImpl = ReloadedHooks.Instance.CreateHook<T>(detour, address.ToInt64());
HookManager.TrackedHooks.TryAdd(Guid.NewGuid(), new HookInfo(this, detour, callingAssembly));
}
this.hookImpl = ReloadedHooks.Instance.CreateHook<T>(detour, address.ToInt64());
HookManager.TrackedHooks.TryAdd(Guid.NewGuid(), new HookInfo(this, detour, callingAssembly));
}
/// <inheritdoc/>
@ -70,11 +73,14 @@ namespace Dalamud.Hooking.Internal
{
this.CheckDisposed();
if (!this.hookImpl.IsHookActivated)
this.hookImpl.Activate();
lock (HookManager.HookEnableSyncRoot)
{
if (!this.hookImpl.IsHookActivated)
this.hookImpl.Activate();
if (!this.hookImpl.IsHookEnabled)
this.hookImpl.Enable();
if (!this.hookImpl.IsHookEnabled)
this.hookImpl.Enable();
}
}
/// <inheritdoc/>
@ -82,11 +88,14 @@ namespace Dalamud.Hooking.Internal
{
this.CheckDisposed();
if (!this.hookImpl.IsHookActivated)
return;
lock (HookManager.HookEnableSyncRoot)
{
if (!this.hookImpl.IsHookActivated)
return;
if (this.hookImpl.IsHookEnabled)
this.hookImpl.Disable();
if (this.hookImpl.IsHookEnabled)
this.hookImpl.Disable();
}
}
}
}