mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-13 12:14:16 +01:00
fix: vtable is a fallback now
This commit is contained in:
parent
fa541ab05b
commit
a8714df33b
5 changed files with 141 additions and 105 deletions
|
|
@ -1,89 +0,0 @@
|
||||||
using SharpDX.Direct3D;
|
|
||||||
using SharpDX.Direct3D11;
|
|
||||||
using SharpDX.DXGI;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Dalamud.Game.Internal.DXGI
|
|
||||||
{
|
|
||||||
public class DXHookD3D11
|
|
||||||
{
|
|
||||||
const int DXGI_SWAPCHAIN_METHOD_COUNT = 18;
|
|
||||||
const int D3D11_DEVICE_METHOD_COUNT = 43;
|
|
||||||
|
|
||||||
public static SharpDX.DXGI.SwapChainDescription CreateSwapChainDescription(IntPtr renderForm)
|
|
||||||
{
|
|
||||||
return new SharpDX.DXGI.SwapChainDescription
|
|
||||||
{
|
|
||||||
BufferCount = 1,
|
|
||||||
Flags = SharpDX.DXGI.SwapChainFlags.None,
|
|
||||||
IsWindowed = true,
|
|
||||||
ModeDescription = new SharpDX.DXGI.ModeDescription(100, 100, new Rational(60, 1), SharpDX.DXGI.Format.R8G8B8A8_UNorm),
|
|
||||||
OutputHandle = renderForm,
|
|
||||||
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
|
|
||||||
SwapEffect = SharpDX.DXGI.SwapEffect.Discard,
|
|
||||||
Usage = SharpDX.DXGI.Usage.RenderTargetOutput
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IntPtr[] GetVTblAddresses(IntPtr pointer, int numberOfMethods)
|
|
||||||
{
|
|
||||||
return GetVTblAddresses(pointer, 0, numberOfMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IntPtr[] GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
|
|
||||||
{
|
|
||||||
List<IntPtr> vtblAddresses = new List<IntPtr>();
|
|
||||||
IntPtr vTable = Marshal.ReadIntPtr(pointer);
|
|
||||||
for (int i = startIndex; i < startIndex + numberOfMethods; i++)
|
|
||||||
vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes
|
|
||||||
|
|
||||||
return vtblAddresses.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IntPtr> _d3d11VTblAddresses = null;
|
|
||||||
List<IntPtr> _dxgiSwapChainVTblAddresses = null;
|
|
||||||
|
|
||||||
#region Internal device resources
|
|
||||||
SharpDX.Direct3D11.Device _device;
|
|
||||||
SharpDX.DXGI.SwapChain _swapChain;
|
|
||||||
SharpDX.Windows.RenderForm _renderForm;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Main device resources
|
|
||||||
public SharpDX.Windows.RenderForm RenderForm { get => _renderForm; set => _renderForm = value; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public IntPtr Hook()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (_d3d11VTblAddresses == null)
|
|
||||||
{
|
|
||||||
_d3d11VTblAddresses = new List<IntPtr>();
|
|
||||||
_dxgiSwapChainVTblAddresses = new List<IntPtr>();
|
|
||||||
|
|
||||||
#region Get Device and SwapChain method addresses
|
|
||||||
// Create temporary device + swapchain and determine method addresses
|
|
||||||
RenderForm = new SharpDX.Windows.RenderForm();
|
|
||||||
SharpDX.Direct3D11.Device.CreateWithSwapChain(
|
|
||||||
DriverType.Hardware,
|
|
||||||
DeviceCreationFlags.BgraSupport,
|
|
||||||
CreateSwapChainDescription(RenderForm.Handle),
|
|
||||||
out _device,
|
|
||||||
out _swapChain
|
|
||||||
);
|
|
||||||
if (_device != null && _swapChain != null)
|
|
||||||
{
|
|
||||||
_d3d11VTblAddresses.AddRange(GetVTblAddresses(_device.NativePointer, D3D11_DEVICE_METHOD_COUNT));
|
|
||||||
_dxgiSwapChainVTblAddresses.AddRange(GetVTblAddresses(_swapChain.NativePointer, DXGI_SWAPCHAIN_METHOD_COUNT));
|
|
||||||
}
|
|
||||||
_device.Dispose();
|
|
||||||
_swapChain.Dispose();
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
return _dxgiSwapChainVTblAddresses[8];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
Dalamud/Game/Internal/DXGI/ISwapChainAddressResolver.cs
Normal file
7
Dalamud/Game/Internal/DXGI/ISwapChainAddressResolver.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Internal.DXGI {
|
||||||
|
public interface ISwapChainAddressResolver {
|
||||||
|
IntPtr Present { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Dalamud.Game.Internal.DXGI
|
namespace Dalamud.Game.Internal.DXGI
|
||||||
{
|
{
|
||||||
public sealed class SwapChainAddressResolver : BaseAddressResolver
|
public sealed class SwapChainSigResolver : BaseAddressResolver, ISwapChainAddressResolver
|
||||||
{
|
{
|
||||||
public IntPtr Present { get; private set; }
|
public IntPtr Present { get; set; }
|
||||||
//public IntPtr ResizeBuffers { get; private set; }
|
//public IntPtr ResizeBuffers { get; private set; }
|
||||||
|
|
||||||
protected override void Setup64Bit(SigScanner sig)
|
protected override void Setup64Bit(SigScanner sig)
|
||||||
|
|
@ -17,7 +20,11 @@ namespace Dalamud.Game.Internal.DXGI
|
||||||
Log.Debug($"Found DXGI: {module.BaseAddress.ToInt64():X}");
|
Log.Debug($"Found DXGI: {module.BaseAddress.ToInt64():X}");
|
||||||
|
|
||||||
var scanner = new SigScanner(module);
|
var scanner = new SigScanner(module);
|
||||||
Present = scanner.ScanModule("48 89 5C 24 ?? 48 89 74 24 ?? 55 57 41 56 48 8D 6C 24 ??");
|
|
||||||
|
// This(code after the function head - offset of it) was picked to avoid running into issues with other hooks being installed into this function.
|
||||||
|
Present = scanner.ScanModule("41 8B F0 8B FA 89 54 24 ?? 48 8B D9 48 89 4D ?? C6 44 24 ?? 00") - 0x37;
|
||||||
|
|
||||||
|
|
||||||
// seems unnecessary for now, but we may need to handle it
|
// seems unnecessary for now, but we may need to handle it
|
||||||
//ResizeBuffers = scanner.ScanModule("48 8B C4 55 41 54 41 55 41 56 41 57 48 8D 68 ?? 48 81 EC C0 00 00 00");
|
//ResizeBuffers = scanner.ScanModule("48 8B C4 55 41 54 41 55 41 56 41 57 48 8D 68 ?? 48 81 EC C0 00 00 00");
|
||||||
}
|
}
|
||||||
98
Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs
Normal file
98
Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
using SharpDX.Direct3D;
|
||||||
|
using SharpDX.Direct3D11;
|
||||||
|
using SharpDX.DXGI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using SharpDX.Windows;
|
||||||
|
using Device = SharpDX.Direct3D11.Device;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Internal.DXGI
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This method of getting the SwapChain Addresses is currently not used.
|
||||||
|
* If the normal AddressResolver(SigScanner) fails, we should use it as a fallback.(Linux?)
|
||||||
|
*/
|
||||||
|
public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressResolver
|
||||||
|
{
|
||||||
|
private const int DxgiSwapchainMethodCount = 18;
|
||||||
|
private const int D3D11DeviceMethodCount = 43;
|
||||||
|
|
||||||
|
private static SwapChainDescription CreateSwapChainDescription(IntPtr renderForm) {
|
||||||
|
return new SwapChainDescription {
|
||||||
|
BufferCount = 1,
|
||||||
|
Flags = SwapChainFlags.None,
|
||||||
|
IsWindowed = true,
|
||||||
|
ModeDescription = new ModeDescription(100, 100, new Rational(60, 1), Format.R8G8B8A8_UNorm),
|
||||||
|
OutputHandle = renderForm,
|
||||||
|
SampleDescription = new SampleDescription(1, 0),
|
||||||
|
SwapEffect = SwapEffect.Discard,
|
||||||
|
Usage = Usage.RenderTargetOutput
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr[] GetVTblAddresses(IntPtr pointer, int numberOfMethods)
|
||||||
|
{
|
||||||
|
return GetVTblAddresses(pointer, 0, numberOfMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr[] GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
|
||||||
|
{
|
||||||
|
List<IntPtr> vtblAddresses = new List<IntPtr>();
|
||||||
|
IntPtr vTable = Marshal.ReadIntPtr(pointer);
|
||||||
|
for (int i = startIndex; i < startIndex + numberOfMethods; i++)
|
||||||
|
vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes
|
||||||
|
|
||||||
|
return vtblAddresses.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IntPtr> d3d11VTblAddresses = null;
|
||||||
|
private List<IntPtr> dxgiSwapChainVTblAddresses = null;
|
||||||
|
|
||||||
|
#region Internal device resources
|
||||||
|
|
||||||
|
private Device device;
|
||||||
|
private SwapChain swapChain;
|
||||||
|
private RenderForm renderForm;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Addresses
|
||||||
|
|
||||||
|
public IntPtr Present { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected override void Setup64Bit(SigScanner sig) {
|
||||||
|
if (this.d3d11VTblAddresses == null) {
|
||||||
|
this.d3d11VTblAddresses = new List<IntPtr>();
|
||||||
|
this.dxgiSwapChainVTblAddresses = new List<IntPtr>();
|
||||||
|
|
||||||
|
#region Get Device and SwapChain method addresses
|
||||||
|
|
||||||
|
// Create temporary device + swapchain and determine method addresses
|
||||||
|
this.renderForm = new RenderForm();
|
||||||
|
Device.CreateWithSwapChain(
|
||||||
|
DriverType.Hardware,
|
||||||
|
DeviceCreationFlags.BgraSupport,
|
||||||
|
CreateSwapChainDescription(this.renderForm.Handle),
|
||||||
|
out this.device,
|
||||||
|
out this.swapChain
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.device != null && this.swapChain != null) {
|
||||||
|
this.d3d11VTblAddresses.AddRange(
|
||||||
|
GetVTblAddresses(this.device.NativePointer, D3D11DeviceMethodCount));
|
||||||
|
this.dxgiSwapChainVTblAddresses.AddRange(
|
||||||
|
GetVTblAddresses(this.swapChain.NativePointer, DxgiSwapchainMethodCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.device?.Dispose();
|
||||||
|
this.swapChain?.Dispose();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
Present = this.dxgiSwapChainVTblAddresses[8];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Game.Internal;
|
||||||
using Dalamud.Game.Internal.DXGI;
|
using Dalamud.Game.Internal.DXGI;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
@ -27,7 +29,7 @@ namespace Dalamud.Interface
|
||||||
|
|
||||||
private readonly Hook<PresentDelegate> presentHook;
|
private readonly Hook<PresentDelegate> presentHook;
|
||||||
|
|
||||||
private DXHookD3D11 dXHookD3D11 = new DXHookD3D11();
|
private ISwapChainAddressResolver Address { get; }
|
||||||
|
|
||||||
private RawDX11Scene scene;
|
private RawDX11Scene scene;
|
||||||
|
|
||||||
|
|
@ -38,13 +40,30 @@ namespace Dalamud.Interface
|
||||||
|
|
||||||
public InterfaceManager(SigScanner scanner)
|
public InterfaceManager(SigScanner scanner)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
var sigResolver = new SwapChainSigResolver();
|
||||||
|
sigResolver.Setup(scanner);
|
||||||
|
|
||||||
|
Log.Verbose("Found SwapChain via signatures.");
|
||||||
|
|
||||||
|
Address = sigResolver;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// The SigScanner method fails on wine/proton since DXGI is not a real DLL. We fall back to vtable to detect our Present function address.
|
||||||
|
Log.Error(ex, "Could not get SwapChain address via sig method, falling back to vtable...");
|
||||||
|
|
||||||
|
var vtableResolver = new SwapChainVtableResolver();
|
||||||
|
vtableResolver.Setup(scanner);
|
||||||
|
|
||||||
|
Log.Verbose("Found SwapChain via vtable.");
|
||||||
|
|
||||||
|
Address = vtableResolver;
|
||||||
|
}
|
||||||
|
|
||||||
IntPtr addr = dXHookD3D11.Hook();
|
|
||||||
Log.Verbose("===== S W A P C H A I N =====");
|
Log.Verbose("===== S W A P C H A I N =====");
|
||||||
Log.Verbose("Present address {Present}", addr);
|
Log.Verbose("Present address {Present}", Address.Present);
|
||||||
|
|
||||||
this.presentHook =
|
this.presentHook =
|
||||||
new Hook<PresentDelegate>(addr,
|
new Hook<PresentDelegate>(Address.Present,
|
||||||
new PresentDelegate(PresentDetour),
|
new PresentDelegate(PresentDetour),
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
@ -53,20 +72,14 @@ namespace Dalamud.Interface
|
||||||
{
|
{
|
||||||
this.presentHook.Enable();
|
this.presentHook.Enable();
|
||||||
|
|
||||||
if (this.scene != null)
|
this.scene?.Enable();
|
||||||
{
|
|
||||||
this.scene.Enable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disable()
|
private void Disable()
|
||||||
{
|
{
|
||||||
this.presentHook.Disable();
|
this.presentHook.Disable();
|
||||||
|
|
||||||
if (this.scene != null)
|
this.scene?.Disable();
|
||||||
{
|
|
||||||
this.scene.Disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue