mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
First resource manager hooks
This commit is contained in:
parent
ac838687f8
commit
5c7c6fc7d6
5 changed files with 256 additions and 1 deletions
|
|
@ -22,7 +22,20 @@ namespace Dalamud.Injector {
|
|||
int pid = int.Parse(args[0]);
|
||||
|
||||
Process process = null;
|
||||
process = pid == -1 ? Process.GetProcessesByName("ffxiv_dx11")[0] : Process.GetProcessById(pid);
|
||||
|
||||
switch (pid) {
|
||||
case -1:
|
||||
process = Process.GetProcessesByName("ffxiv_dx11")[0];
|
||||
break;
|
||||
case -2:
|
||||
process = Process.Start(
|
||||
"C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\ffxiv_dx11.exe",
|
||||
"DEV.TestSID=5fa077c389a61c4a45ea35153162753d7cdb34268cc38c9e206859a7 DEV.UseSqPack=1 DEV.DataPathType=1 DEV.LobbyHost01=127.0.0.1 DEV.LobbyPort01=54994 DEV.LobbyHost02=127.0.0.1 DEV.LobbyPort02=54994 DEV.LobbyHost03=127.0.0.1 DEV.LobbyPort03=54994 DEV.LobbyHost04=127.0.0.1 DEV.LobbyPort04=54994 DEV.LobbyHost05=127.0.0.1 DEV.LobbyPort05=54994 DEV.LobbyHost06=127.0.0.1 DEV.LobbyPort06=54994 DEV.LobbyHost07=127.0.0.1 DEV.LobbyPort07=54994 DEV.LobbyHost08=127.0.0.1 DEV.LobbyPort08=54994 SYS.Region=0 language=1 version=1.0.0.0 DEV.MaxEntitledExpansionID=2 DEV.GMServerHost=127.0.0.1 DEV.GameQuitMessageBox=0");
|
||||
break;
|
||||
default:
|
||||
process = Process.GetProcessById(pid);
|
||||
break;
|
||||
}
|
||||
|
||||
var startInfo = JsonConvert.DeserializeObject<DalamudStartInfo>(Encoding.UTF8.GetString(Convert.FromBase64String(args[1])));
|
||||
startInfo.WorkingDirectory = Directory.GetCurrentDirectory();
|
||||
|
|
|
|||
|
|
@ -37,7 +37,11 @@ namespace Dalamud {
|
|||
|
||||
public readonly ClientState ClientState;
|
||||
|
||||
public readonly DalamudStartInfo StartInfo;
|
||||
|
||||
public Dalamud(DalamudStartInfo info) {
|
||||
this.StartInfo = info;
|
||||
|
||||
this.baseDirectory = info.WorkingDirectory;
|
||||
|
||||
this.unloadSignal = new ManualResetEvent(false);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Dalamud.Game.Internal.Libc;
|
|||
using Dalamud.Game.Internal.Network;
|
||||
using Dalamud.Hooking;
|
||||
using Serilog;
|
||||
using Dalamud.Game.Internal.File;
|
||||
|
||||
namespace Dalamud.Game.Internal {
|
||||
public sealed class Framework : IDisposable {
|
||||
|
|
@ -29,6 +30,8 @@ namespace Dalamud.Game.Internal {
|
|||
public GameGui Gui { get; private set; }
|
||||
|
||||
public GameNetwork Network { get; private set; }
|
||||
|
||||
public ResourceManager Resource { get; private set; }
|
||||
|
||||
public LibcFunction Libc { get; private set; }
|
||||
|
||||
|
|
@ -52,6 +55,8 @@ namespace Dalamud.Game.Internal {
|
|||
Gui = new GameGui(Address.GuiManager, scanner, dalamud);
|
||||
|
||||
Network = new GameNetwork(dalamud, scanner);
|
||||
|
||||
Resource = new ResourceManager(dalamud, scanner);
|
||||
}
|
||||
|
||||
private void HookVTable() {
|
||||
|
|
@ -70,6 +75,7 @@ namespace Dalamud.Game.Internal {
|
|||
public void Enable() {
|
||||
Gui.Enable();
|
||||
Network.Enable();
|
||||
//Resource.Enable();
|
||||
|
||||
this.updateHook.Enable();
|
||||
}
|
||||
|
|
@ -77,6 +83,7 @@ namespace Dalamud.Game.Internal {
|
|||
public void Dispose() {
|
||||
Gui.Dispose();
|
||||
Network.Dispose();
|
||||
//Resource.Dispose();
|
||||
|
||||
this.updateHook.Dispose();
|
||||
}
|
||||
|
|
|
|||
211
Dalamud/Game/Internal/Resource/ResourceManager.cs
Normal file
211
Dalamud/Game/Internal/Resource/ResourceManager.cs
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.Internal.Libc;
|
||||
using Dalamud.Hooking;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Internal.File
|
||||
{
|
||||
public class ResourceManager {
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate IntPtr GetResourceAsyncDelegate(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, byte a7);
|
||||
private readonly Hook<GetResourceAsyncDelegate> getResourceAsyncHook;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate IntPtr GetResourceSyncDelegate(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6);
|
||||
private readonly Hook<GetResourceSyncDelegate> getResourceSyncHook;
|
||||
|
||||
private ResourceManagerAddressResolver Address { get; }
|
||||
private readonly Dalamud dalamud;
|
||||
|
||||
class ResourceHandleHookInfo {
|
||||
public string Path { get; set; }
|
||||
public Stream DetourFile { get; set; }
|
||||
}
|
||||
|
||||
private Dictionary<IntPtr, ResourceHandleHookInfo> resourceHookMap = new Dictionary<IntPtr, ResourceHandleHookInfo>();
|
||||
|
||||
public ResourceManager(Dalamud dalamud, SigScanner scanner) {
|
||||
this.dalamud = dalamud;
|
||||
Address = new ResourceManagerAddressResolver();
|
||||
Address.Setup(scanner);
|
||||
|
||||
Log.Verbose("===== R E S O U R C E M A N A G E R =====");
|
||||
Log.Verbose("GetResourceAsync address {GetResourceAsync}", Address.GetResourceAsync);
|
||||
Log.Verbose("GetResourceSync address {GetResourceSync}", Address.GetResourceSync);
|
||||
|
||||
this.getResourceAsyncHook =
|
||||
new Hook<GetResourceAsyncDelegate>(Address.GetResourceAsync,
|
||||
new GetResourceAsyncDelegate(GetResourceAsyncDetour),
|
||||
this);
|
||||
|
||||
this.getResourceSyncHook =
|
||||
new Hook<GetResourceSyncDelegate>(Address.GetResourceSync,
|
||||
new GetResourceSyncDelegate(GetResourceSyncDetour),
|
||||
this);
|
||||
|
||||
}
|
||||
|
||||
public void Enable() {
|
||||
this.getResourceAsyncHook.Enable();
|
||||
this.getResourceSyncHook.Enable();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.getResourceAsyncHook.Dispose();
|
||||
this.getResourceSyncHook.Dispose();
|
||||
}
|
||||
|
||||
private IntPtr GetResourceAsyncDetour(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, byte a7) {
|
||||
|
||||
try {
|
||||
var path = Marshal.PtrToStringAnsi(a5);
|
||||
|
||||
var resourceHandle = this.getResourceAsyncHook.Original(manager, a2, a3, a4, IntPtr.Zero, a6, a7);
|
||||
//var resourceHandle = IntPtr.Zero;
|
||||
|
||||
Log.Verbose("GetResourceAsync CALL - this:{0} a2:{1} a3:{2} a4:{3} a5:{4} a6:{5} a7:{6} => RET:{7}", manager, a2, a3, a4, a5, a6, a7, resourceHandle);
|
||||
|
||||
Log.Verbose($"->{path}");
|
||||
|
||||
HandleGetResourceHookAcquire(resourceHandle, path);
|
||||
|
||||
return resourceHandle;
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex, "Exception on ReadResourceAsync hook.");
|
||||
|
||||
return this.getResourceAsyncHook.Original(manager, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
}
|
||||
|
||||
private void DumpMem(IntPtr address, int len = 512) {
|
||||
if (address == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
var data = new byte[len];
|
||||
Marshal.Copy(address, data, 0, len);
|
||||
|
||||
Log.Verbose($"MEMDMP at {address.ToInt64():X} for {len:X}\n{ByteArrayToHex(data)}");
|
||||
}
|
||||
|
||||
private IntPtr GetResourceSyncDetour(IntPtr manager, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6) {
|
||||
|
||||
try {
|
||||
var resourceHandle = this.getResourceSyncHook.Original(manager, a2, a3, a4, a5, a6);
|
||||
|
||||
Log.Verbose("GetResourceSync CALL - this:{0} a2:{1} a3:{2} a4:{3} a5:{4} a6:{5} => RET:{6}", manager, a2, a3, a4, a5, a6, resourceHandle);
|
||||
|
||||
var path = Marshal.PtrToStringAnsi(a5);
|
||||
|
||||
Log.Verbose($"->{path}");
|
||||
|
||||
HandleGetResourceHookAcquire(resourceHandle, path);
|
||||
|
||||
return resourceHandle;
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex, "Exception on ReadResourceSync hook.");
|
||||
|
||||
return this.getResourceSyncHook.Original(manager, a2, a3, a4, a5, a6);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleGetResourceHookAcquire(IntPtr handlePtr, string path) {
|
||||
if (FilePathHasInvalidChars(path))
|
||||
return;
|
||||
|
||||
if (this.resourceHookMap.ContainsKey(handlePtr)) {
|
||||
Log.Verbose($"-> Handle {handlePtr.ToInt64():X}({path}) was cached!");
|
||||
return;
|
||||
}
|
||||
|
||||
var hookInfo = new ResourceHandleHookInfo {
|
||||
Path = path
|
||||
};
|
||||
|
||||
var hookPath = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "ResourceHook", path);
|
||||
|
||||
if (System.IO.File.Exists(hookPath)) {
|
||||
hookInfo.DetourFile = new FileStream(hookPath, FileMode.Open);
|
||||
Log.Verbose("-> Added resource hook detour at {0}", hookPath);
|
||||
}
|
||||
|
||||
this.resourceHookMap.Add(handlePtr, hookInfo);
|
||||
}
|
||||
|
||||
public static bool FilePathHasInvalidChars(string path)
|
||||
{
|
||||
|
||||
return (!string.IsNullOrEmpty(path) && path.IndexOfAny(System.IO.Path.GetInvalidPathChars()) >= 0);
|
||||
}
|
||||
|
||||
public static string ByteArrayToHex(byte[] bytes, int offset = 0, int bytesPerLine = 16)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var hexChars = "0123456789ABCDEF".ToCharArray();
|
||||
|
||||
var offsetBlock = 8 + 3;
|
||||
var byteBlock = offsetBlock + bytesPerLine * 3 + (bytesPerLine - 1) / 8 + 2;
|
||||
var lineLength = byteBlock + bytesPerLine + Environment.NewLine.Length;
|
||||
|
||||
var line = (new string(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray();
|
||||
var numLines = (bytes.Length + bytesPerLine - 1) / bytesPerLine;
|
||||
|
||||
var sb = new StringBuilder(numLines * lineLength);
|
||||
|
||||
for (var i = 0; i < bytes.Length; i += bytesPerLine)
|
||||
{
|
||||
var h = i + offset;
|
||||
|
||||
line[0] = hexChars[(h >> 28) & 0xF];
|
||||
line[1] = hexChars[(h >> 24) & 0xF];
|
||||
line[2] = hexChars[(h >> 20) & 0xF];
|
||||
line[3] = hexChars[(h >> 16) & 0xF];
|
||||
line[4] = hexChars[(h >> 12) & 0xF];
|
||||
line[5] = hexChars[(h >> 8) & 0xF];
|
||||
line[6] = hexChars[(h >> 4) & 0xF];
|
||||
line[7] = hexChars[(h >> 0) & 0xF];
|
||||
|
||||
var hexColumn = offsetBlock;
|
||||
var charColumn = byteBlock;
|
||||
|
||||
for (var j = 0; j < bytesPerLine; j++)
|
||||
{
|
||||
if (j > 0 && (j & 7) == 0)
|
||||
{
|
||||
hexColumn++;
|
||||
}
|
||||
|
||||
if (i + j >= bytes.Length)
|
||||
{
|
||||
line[hexColumn] = ' ';
|
||||
line[hexColumn + 1] = ' ';
|
||||
line[charColumn] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
var by = bytes[i + j];
|
||||
line[hexColumn] = hexChars[(by >> 4) & 0xF];
|
||||
line[hexColumn + 1] = hexChars[by & 0xF];
|
||||
line[charColumn] = by < 32 ? '.' : (char)by;
|
||||
}
|
||||
|
||||
hexColumn += 3;
|
||||
charColumn++;
|
||||
}
|
||||
|
||||
sb.Append(line);
|
||||
}
|
||||
|
||||
return sb.ToString().TrimEnd(Environment.NewLine.ToCharArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dalamud.Game.Internal.File
|
||||
{
|
||||
class ResourceManagerAddressResolver : BaseAddressResolver
|
||||
{
|
||||
public IntPtr GetResourceAsync { get; private set; }
|
||||
public IntPtr GetResourceSync { get; private set; }
|
||||
|
||||
protected override void Setup64Bit(SigScanner sig) {
|
||||
GetResourceAsync = sig.ScanText("48 89 5C 24 08 48 89 54 24 10 57 48 83 EC 20 B8 03 00 00 00 48 8B F9 86 82 A1 00 00 00 48 8B 5C 24 38 B8 01 00 00 00 87 83 90 00 00 00 85 C0 74");
|
||||
GetResourceSync = sig.ScanText("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 54 41 55 41 56 41 57 48 83 EC 30 48 8B F9 49 8B E9 48 83 C1 30 4D 8B F0 4C 8B EA FF 15 CE F6");
|
||||
//ReadResourceSync = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue