Merge remote-tracking branch 'refs/remotes/pmgr/master'

This commit is contained in:
Ottermandias 2024-07-22 20:43:58 +02:00
commit 528e3226b5
2 changed files with 33 additions and 11 deletions

View file

@ -3,6 +3,7 @@ using Dalamud.Hooking;
using Iced.Intel; using Iced.Intel;
using OtterGui; using OtterGui;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Swan;
namespace Penumbra.Interop.Hooks.ResourceLoading; namespace Penumbra.Interop.Hooks.ResourceLoading;
@ -10,9 +11,10 @@ public sealed class PapRewriter(PapRewriter.PapResourceHandlerPrototype papResou
{ {
public unsafe delegate int PapResourceHandlerPrototype(void* self, byte* path, int length); public unsafe delegate int PapResourceHandlerPrototype(void* self, byte* path, int length);
private readonly PeSigScanner _scanner = new(); private readonly PeSigScanner _scanner = new();
private readonly Dictionary<nint, AsmHook> _hooks = []; private readonly Dictionary<nint, AsmHook> _hooks = [];
private readonly List<nint> _nativeAllocList = []; private readonly Dictionary<(nint, Register, ulong), nint> _nativeAllocPaths = [];
private readonly List<nint> _nativeAllocCaves = [];
public void Rewrite(string sig, string name) public void Rewrite(string sig, string name)
{ {
@ -25,8 +27,12 @@ public sealed class PapRewriter(PapRewriter.PapResourceHandlerPrototype papResou
foreach (var hookPoint in hookPoints) foreach (var hookPoint in hookPoints)
{ {
var stackAccesses = ScanStackAccesses(funcInstructions, hookPoint).ToList(); var stackAccesses = ScanStackAccesses(funcInstructions, hookPoint).ToList();
var stringAllocation = NativeAlloc(Utf8GamePath.MaxGamePathLength); var stringAllocation = NativeAllocPath(
address, hookPoint.MemoryBase, hookPoint.MemoryDisplacement64,
Utf8GamePath.MaxGamePathLength
);
WriteToAlloc(stringAllocation, Utf8GamePath.MaxGamePathLength, name); WriteToAlloc(stringAllocation, Utf8GamePath.MaxGamePathLength, name);
// We'll need to grab our true hook point; the location where we can change the path at our leisure. // We'll need to grab our true hook point; the location where we can change the path at our leisure.
// This is going to be the first call instruction after our 'hookPoint', so, we'll find that. // This is going to be the first call instruction after our 'hookPoint', so, we'll find that.
// Pretty scuffed, this might need a refactoring at some point. // Pretty scuffed, this might need a refactoring at some point.
@ -44,7 +50,7 @@ public sealed class PapRewriter(PapRewriter.PapResourceHandlerPrototype papResou
var targetRegister = hookPoint.Op0Register.ToString().ToLower(); var targetRegister = hookPoint.Op0Register.ToString().ToLower();
var hookAddress = new IntPtr((long)detourPoint.IP); var hookAddress = new IntPtr((long)detourPoint.IP);
var caveAllocation = NativeAlloc(16); var caveAllocation = NativeAllocCave(16);
var hook = new AsmHook( var hook = new AsmHook(
hookAddress, hookAddress,
[ [
@ -137,13 +143,24 @@ public sealed class PapRewriter(PapRewriter.PapResourceHandlerPrototype papResou
} }
} }
private unsafe nint NativeAlloc(nuint size) private unsafe nint NativeAllocCave(nuint size)
{ {
var caveLoc = (nint)NativeMemory.Alloc(size); var caveLoc = (nint)NativeMemory.Alloc(size);
_nativeAllocList.Add(caveLoc); _nativeAllocCaves.Add(caveLoc);
return caveLoc; return caveLoc;
} }
// This is a bit conked but, if we identify a path by:
// 1) The function it belongs to (starting address, 'funcAddress')
// 2) The stack register (not strictly necessary - should always be rbp - but abundance of caution, so I don't hit myself in the future)
// 3) The displacement on the stack
// Then we ensure we have a unique identifier for the specific variable location of that specific function
// This is useful because sometimes the stack address is reused within the same function for different GetResourceAsync calls
private unsafe nint NativeAllocPath(nint funcAddress, Register stackRegister, ulong stackDisplacement, nuint size)
{
return _nativeAllocPaths.GetOrAdd((funcAddress, stackRegister, stackDisplacement), _ => (nint)NativeMemory.Alloc(size));
}
private static unsafe void NativeFree(nint mem) private static unsafe void NativeFree(nint mem)
=> NativeMemory.Free((void*)mem); => NativeMemory.Free((void*)mem);
@ -160,10 +177,15 @@ public sealed class PapRewriter(PapRewriter.PapResourceHandlerPrototype papResou
_hooks.Clear(); _hooks.Clear();
foreach (var mem in _nativeAllocList) foreach (var mem in _nativeAllocCaves)
NativeFree(mem); NativeFree(mem);
_nativeAllocList.Clear(); _nativeAllocCaves.Clear();
foreach (var mem in _nativeAllocPaths.Values)
NativeFree(mem);
_nativeAllocPaths.Clear();
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]

View file

@ -6,7 +6,7 @@
"Description": "Runtime mod loader and manager.", "Description": "Runtime mod loader and manager.",
"InternalName": "Penumbra", "InternalName": "Penumbra",
"AssemblyVersion": "1.1.1.2", "AssemblyVersion": "1.1.1.2",
"TestingAssemblyVersion": "1.2.0.12", "TestingAssemblyVersion": "1.2.0.13",
"RepoUrl": "https://github.com/xivdev/Penumbra", "RepoUrl": "https://github.com/xivdev/Penumbra",
"ApplicableVersion": "any", "ApplicableVersion": "any",
"DalamudApiLevel": 9, "DalamudApiLevel": 9,
@ -19,7 +19,7 @@
"LoadRequiredState": 2, "LoadRequiredState": 2,
"LoadSync": true, "LoadSync": true,
"DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.1.1.2/Penumbra.zip", "DownloadLinkInstall": "https://github.com/xivdev/Penumbra/releases/download/1.1.1.2/Penumbra.zip",
"DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.2.0.12/Penumbra.zip", "DownloadLinkTesting": "https://github.com/xivdev/Penumbra/releases/download/testing_1.2.0.13/Penumbra.zip",
"DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.1.1.2/Penumbra.zip", "DownloadLinkUpdate": "https://github.com/xivdev/Penumbra/releases/download/1.1.1.2/Penumbra.zip",
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png" "IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
} }