mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Add additional logging to injector
This commit is contained in:
parent
9ba3d85b03
commit
4ca4d778aa
5 changed files with 125 additions and 106 deletions
|
|
@ -51,7 +51,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Label="Warnings">
|
<PropertyGroup Label="Warnings">
|
||||||
<NoWarn>IDE1006;CS1591;CS1701;CS1702</NoWarn>
|
<NoWarn>IDE0003;IDE0044;IDE1006;CS1591;CS1701;CS1702</NoWarn>
|
||||||
|
<!-- IDE0003 - Name can be simplified -->
|
||||||
<!-- IDE1006 - Naming violation -->
|
<!-- IDE1006 - Naming violation -->
|
||||||
<!-- CS1591 - Missing XML comment for publicly visible type or member -->
|
<!-- CS1591 - Missing XML comment for publicly visible type or member -->
|
||||||
<!-- CS1701 - Runtime policy may be needed -->
|
<!-- CS1701 - Runtime policy may be needed -->
|
||||||
|
|
@ -84,6 +85,5 @@
|
||||||
<Compile Include="..\Dalamud\DalamudStartInfo.cs" />
|
<Compile Include="..\Dalamud\DalamudStartInfo.cs" />
|
||||||
<Compile Include="..\Dalamud\Game\GameVersion.cs" />
|
<Compile Include="..\Dalamud\Game\GameVersion.cs" />
|
||||||
<Compile Include="..\Dalamud\Game\GameVersionConverter.cs" />
|
<Compile Include="..\Dalamud\Game\GameVersionConverter.cs" />
|
||||||
<Compile Include="..\Dalamud\Interface\Internal\SerilogEventSink.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Interface.Internal;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Reloaded.Memory.Buffers;
|
using Reloaded.Memory.Buffers;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
@ -131,7 +130,6 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.WriteTo.Async(a => a.File(logPath))
|
.WriteTo.Async(a => a.File(logPath))
|
||||||
.WriteTo.Sink(SerilogEventSink.Instance)
|
|
||||||
.MinimumLevel.ControlledBy(levelSwitch)
|
.MinimumLevel.ControlledBy(levelSwitch)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using PeNet.Header.Pe;
|
||||||
using Reloaded.Memory.Buffers;
|
using Reloaded.Memory.Buffers;
|
||||||
using Reloaded.Memory.Sources;
|
using Reloaded.Memory.Sources;
|
||||||
using Reloaded.Memory.Utilities;
|
using Reloaded.Memory.Utilities;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
using static Dalamud.Injector.NativeFunctions;
|
using static Dalamud.Injector.NativeFunctions;
|
||||||
using static Iced.Intel.AssemblerRegisters;
|
using static Iced.Intel.AssemblerRegisters;
|
||||||
|
|
@ -27,7 +28,7 @@ namespace Dalamud.Injector
|
||||||
private readonly Process targetProcess;
|
private readonly Process targetProcess;
|
||||||
private readonly ExternalMemory extMemory;
|
private readonly ExternalMemory extMemory;
|
||||||
private readonly CircularBuffer circularBuffer;
|
private readonly CircularBuffer circularBuffer;
|
||||||
private readonly PrivateMemoryBuffer privateBuffer;
|
private readonly PrivateMemoryBuffer memoryBuffer;
|
||||||
|
|
||||||
private IntPtr loadLibraryShellPtr;
|
private IntPtr loadLibraryShellPtr;
|
||||||
private IntPtr loadLibraryRetPtr;
|
private IntPtr loadLibraryRetPtr;
|
||||||
|
|
@ -45,7 +46,7 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
this.extMemory = new ExternalMemory(targetProcess);
|
this.extMemory = new ExternalMemory(targetProcess);
|
||||||
this.circularBuffer = new CircularBuffer(4096, this.extMemory);
|
this.circularBuffer = new CircularBuffer(4096, this.extMemory);
|
||||||
this.privateBuffer = new MemoryBufferHelper(targetProcess).CreatePrivateMemoryBuffer(4096);
|
this.memoryBuffer = new MemoryBufferHelper(targetProcess).CreatePrivateMemoryBuffer(4096);
|
||||||
|
|
||||||
using var kernel32Module = this.GetProcessModule("KERNEL32.DLL");
|
using var kernel32Module = this.GetProcessModule("KERNEL32.DLL");
|
||||||
var kernel32PeFile = new PeFile(kernel32Module.FileName);
|
var kernel32PeFile = new PeFile(kernel32Module.FileName);
|
||||||
|
|
@ -67,7 +68,7 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
this.targetProcess?.Dispose();
|
this.targetProcess?.Dispose();
|
||||||
this.circularBuffer?.Dispose();
|
this.circularBuffer?.Dispose();
|
||||||
this.privateBuffer?.Dispose();
|
this.memoryBuffer?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -82,6 +83,8 @@ namespace Dalamud.Injector
|
||||||
if (lpParameter == IntPtr.Zero)
|
if (lpParameter == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate LoadLibraryW parameter");
|
throw new Exception("Unable to allocate LoadLibraryW parameter");
|
||||||
|
|
||||||
|
Log.Verbose($"CreateRemoteThread: call 0x{this.loadLibraryShellPtr.ToInt64():X} with 0x{lpParameter.ToInt64():X}");
|
||||||
|
|
||||||
var threadHandle = CreateRemoteThread(
|
var threadHandle = CreateRemoteThread(
|
||||||
this.targetProcess.Handle,
|
this.targetProcess.Handle,
|
||||||
IntPtr.Zero,
|
IntPtr.Zero,
|
||||||
|
|
@ -93,7 +96,7 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
||||||
|
|
||||||
this.extMemory.Read(this.loadLibraryRetPtr, out address);
|
address = this.extMemory.Read<IntPtr>(this.loadLibraryRetPtr);
|
||||||
|
|
||||||
if (address == IntPtr.Zero)
|
if (address == IntPtr.Zero)
|
||||||
throw new Exception($"Error calling LoadLibraryW with {modulePath}");
|
throw new Exception($"Error calling LoadLibraryW with {modulePath}");
|
||||||
|
|
@ -107,7 +110,8 @@ namespace Dalamud.Injector
|
||||||
/// <param name="address">Address to the function.</param>
|
/// <param name="address">Address to the function.</param>
|
||||||
public void GetFunctionAddress(IntPtr module, string functionName, out IntPtr address)
|
public void GetFunctionAddress(IntPtr module, string functionName, out IntPtr address)
|
||||||
{
|
{
|
||||||
var getProcAddressParams = new GetProcAddressParams(module, this.WriteNullTerminatedASCIIString(functionName));
|
var functionNamePtr = this.WriteNullTerminatedASCIIString(functionName);
|
||||||
|
var getProcAddressParams = new GetProcAddressParams(module, functionNamePtr);
|
||||||
var lpParameter = this.circularBuffer.Add(ref getProcAddressParams);
|
var lpParameter = this.circularBuffer.Add(ref getProcAddressParams);
|
||||||
|
|
||||||
if (lpParameter == IntPtr.Zero)
|
if (lpParameter == IntPtr.Zero)
|
||||||
|
|
@ -151,19 +155,25 @@ namespace Dalamud.Injector
|
||||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
||||||
|
|
||||||
GetExitCodeThread(threadHandle, out exitCode);
|
GetExitCodeThread(threadHandle, out exitCode);
|
||||||
|
|
||||||
|
CloseHandle(threadHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupLoadLibrary(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
private void SetupLoadLibrary(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
||||||
{
|
{
|
||||||
var offset = this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
|
var offset = this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
|
||||||
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
||||||
var functionPtr = this.privateBuffer.Add(ref functionAddr);
|
Log.Verbose($"LoadLibraryW: 0x{functionAddr.ToInt64():X}");
|
||||||
|
|
||||||
|
var functionPtr = this.memoryBuffer.Add(ref functionAddr);
|
||||||
|
Log.Verbose($"LoadLibraryPtr: 0x{functionPtr.ToInt64():X}");
|
||||||
|
|
||||||
if (functionPtr == IntPtr.Zero)
|
if (functionPtr == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate LoadLibraryW function ptr");
|
throw new Exception("Unable to allocate LoadLibraryW function ptr");
|
||||||
|
|
||||||
var dummy = 0L;
|
var dummy = IntPtr.Zero;
|
||||||
this.loadLibraryRetPtr = this.privateBuffer.Add(ref dummy);
|
this.loadLibraryRetPtr = this.memoryBuffer.Add(ref dummy);
|
||||||
|
Log.Verbose($"LoadLibraryRetPtr: 0x{this.loadLibraryRetPtr.ToInt64():X}");
|
||||||
|
|
||||||
if (this.loadLibraryRetPtr == IntPtr.Zero)
|
if (this.loadLibraryRetPtr == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate LoadLibraryW return value");
|
throw new Exception("Unable to allocate LoadLibraryW return value");
|
||||||
|
|
@ -180,23 +190,41 @@ namespace Dalamud.Injector
|
||||||
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
||||||
|
|
||||||
var bytes = this.Assemble(asm);
|
var bytes = this.Assemble(asm);
|
||||||
this.loadLibraryShellPtr = this.privateBuffer.Add(bytes);
|
this.loadLibraryShellPtr = this.memoryBuffer.Add(bytes);
|
||||||
|
Log.Verbose($"LoadLibraryShellPtr: 0x{this.loadLibraryShellPtr.ToInt64():X}");
|
||||||
|
|
||||||
if (this.loadLibraryShellPtr == IntPtr.Zero)
|
if (this.loadLibraryShellPtr == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate LoadLibraryW shellcode");
|
throw new Exception("Unable to allocate LoadLibraryW shellcode");
|
||||||
|
|
||||||
|
this.extMemory.ChangePermission(this.loadLibraryShellPtr, bytes.Length, Reloaded.Memory.Kernel32.Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
var outFunctionPtr = this.extMemory.Read<IntPtr>(functionPtr);
|
||||||
|
Log.Verbose($"LoadLibraryPtr: {this.GetResultMarker(outFunctionPtr == functionAddr)}");
|
||||||
|
|
||||||
|
var outRetPtr = this.extMemory.Read<IntPtr>(this.loadLibraryRetPtr);
|
||||||
|
Log.Verbose($"LoadLibraryRet: {this.GetResultMarker(dummy == outRetPtr)}");
|
||||||
|
|
||||||
|
this.extMemory.ReadRaw(this.loadLibraryShellPtr, out var outBytes, bytes.Length);
|
||||||
|
Log.Verbose($"LoadLibraryShellPtr: {this.GetResultMarker(Enumerable.SequenceEqual(bytes, outBytes))}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupGetProcAddress(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
private void SetupGetProcAddress(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
||||||
{
|
{
|
||||||
var offset = this.GetExportedFunctionOffset(kernel32Exports, "GetProcAddress");
|
var offset = this.GetExportedFunctionOffset(kernel32Exports, "GetProcAddress");
|
||||||
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
||||||
var functionPtr = this.privateBuffer.Add(ref functionAddr);
|
Log.Verbose($"GetProcAddress: 0x{functionAddr.ToInt64():X}");
|
||||||
|
|
||||||
|
var functionPtr = this.memoryBuffer.Add(ref functionAddr);
|
||||||
|
Log.Verbose($"GetProcAddressPtr: 0x{functionPtr.ToInt64():X}");
|
||||||
|
|
||||||
if (functionPtr == IntPtr.Zero)
|
if (functionPtr == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate GetProcAddress function ptr");
|
throw new Exception("Unable to allocate GetProcAddress function ptr");
|
||||||
|
|
||||||
var dummy = 0L;
|
var dummy = IntPtr.Zero;
|
||||||
this.getProcAddressRetPtr = this.privateBuffer.Add(ref dummy);
|
this.getProcAddressRetPtr = this.memoryBuffer.Add(ref dummy);
|
||||||
|
Log.Verbose($"GetProcAddressRetPtr: 0x{this.loadLibraryRetPtr.ToInt64():X}");
|
||||||
|
|
||||||
if (this.getProcAddressRetPtr == IntPtr.Zero)
|
if (this.getProcAddressRetPtr == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate GetProcAddress return value");
|
throw new Exception("Unable to allocate GetProcAddress return value");
|
||||||
|
|
@ -215,10 +243,24 @@ namespace Dalamud.Injector
|
||||||
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
||||||
|
|
||||||
var bytes = this.Assemble(asm);
|
var bytes = this.Assemble(asm);
|
||||||
this.getProcAddressShellPtr = this.privateBuffer.Add(bytes);
|
this.getProcAddressShellPtr = this.memoryBuffer.Add(bytes);
|
||||||
|
Log.Verbose($"GetProcAddressShellPtr: 0x{this.getProcAddressShellPtr.ToInt64():X}");
|
||||||
|
|
||||||
if (this.getProcAddressShellPtr == IntPtr.Zero)
|
if (this.getProcAddressShellPtr == IntPtr.Zero)
|
||||||
throw new Exception("Unable to allocate GetProcAddress shellcode");
|
throw new Exception("Unable to allocate GetProcAddress shellcode");
|
||||||
|
|
||||||
|
this.extMemory.ChangePermission(this.getProcAddressShellPtr, bytes.Length, Reloaded.Memory.Kernel32.Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
var outFunctionPtr = this.extMemory.Read<IntPtr>(functionPtr);
|
||||||
|
Log.Verbose($"GetProcAddressPtr: {this.GetResultMarker(outFunctionPtr == functionAddr)}");
|
||||||
|
|
||||||
|
var outRetPtr = this.extMemory.Read<IntPtr>(this.loadLibraryRetPtr);
|
||||||
|
Log.Verbose($"GetProcAddressRet: {this.GetResultMarker(dummy == outRetPtr)}");
|
||||||
|
|
||||||
|
this.extMemory.ReadRaw(this.getProcAddressShellPtr, out var outBytes, bytes.Length);
|
||||||
|
Log.Verbose($"GetProcAddressShellPtr: {this.GetResultMarker(Enumerable.SequenceEqual(bytes, outBytes))}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] Assemble(Assembler assembler)
|
private byte[] Assemble(Assembler assembler)
|
||||||
|
|
@ -264,28 +306,42 @@ namespace Dalamud.Injector
|
||||||
return exportFunction.Address;
|
return exportFunction.Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntPtr WriteNullTerminatedASCIIString(string libraryPath)
|
private IntPtr WriteNullTerminatedASCIIString(string value)
|
||||||
{
|
{
|
||||||
var libraryNameBytes = Encoding.ASCII.GetBytes(libraryPath + '\0');
|
var bytes = Encoding.ASCII.GetBytes(value + '\0');
|
||||||
var value = this.circularBuffer.Add(libraryNameBytes);
|
var address = this.circularBuffer.Add(bytes);
|
||||||
|
|
||||||
if (value == IntPtr.Zero)
|
if (address == IntPtr.Zero)
|
||||||
throw new Exception("Unable to write ASCII string to buffer");
|
throw new Exception("Unable to write ASCII string to buffer");
|
||||||
|
|
||||||
return value;
|
#if DEBUG
|
||||||
|
this.extMemory.ReadRaw(address, out var outBytes, bytes.Length);
|
||||||
|
Log.Verbose($"WriteASCII: {this.GetResultMarker(Enumerable.SequenceEqual(bytes, outBytes))} 0x{address.ToInt64():X} {value}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntPtr WriteNullTerminatedUnicodeString(string libraryPath)
|
private IntPtr WriteNullTerminatedUnicodeString(string value)
|
||||||
{
|
{
|
||||||
var libraryNameBytes = Encoding.Unicode.GetBytes(libraryPath + '\0');
|
var bytes = Encoding.Unicode.GetBytes(value + '\0');
|
||||||
var value = this.circularBuffer.Add(libraryNameBytes);
|
var address = this.circularBuffer.Add(bytes);
|
||||||
|
|
||||||
if (value == IntPtr.Zero)
|
if (address == IntPtr.Zero)
|
||||||
throw new Exception("Unable to write Unicode string to buffer");
|
throw new Exception("Unable to write Unicode string to buffer");
|
||||||
|
|
||||||
return value;
|
#if DEBUG
|
||||||
|
this.extMemory.ReadRaw(address, out var outBytes, bytes.Length);
|
||||||
|
Log.Verbose($"WriteUnicode: {this.GetResultMarker(Enumerable.SequenceEqual(bytes, outBytes))} 0x{address.ToInt64():X} {value}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private string GetResultMarker(bool result) => result ? "✅" : "❌";
|
||||||
|
#endif
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
private struct GetProcAddressParams
|
private struct GetProcAddressParams
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -582,6 +582,22 @@ namespace Dalamud.Injector
|
||||||
WAIT_FAILED = 0xFFFFFFF,
|
WAIT_FAILED = 0xFFFFFFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes an open object handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hObject">
|
||||||
|
/// A valid handle to an open object.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error
|
||||||
|
/// information, call GetLastError. If the application is running under a debugger, the function will throw an exception if it receives
|
||||||
|
/// either a handle value that is not valid or a pseudo-handle value. This can happen if you close a handle twice, or if you call
|
||||||
|
/// CloseHandle on a handle returned by the FindFirstFile function instead of calling the FindClose function.
|
||||||
|
/// </returns>
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool CloseHandle(IntPtr hObject);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a thread that runs in the virtual address space of another process. Use the CreateRemoteThreadEx function
|
/// Creates a thread that runs in the virtual address space of another process. Use the CreateRemoteThreadEx function
|
||||||
/// to create a thread that runs in the virtual address space of another process and optionally specify extended attributes.
|
/// to create a thread that runs in the virtual address space of another process and optionally specify extended attributes.
|
||||||
|
|
@ -651,6 +667,34 @@ namespace Dalamud.Injector
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
|
public static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens an existing local process object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dwDesiredAccess">
|
||||||
|
/// The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or
|
||||||
|
/// more of the process access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the
|
||||||
|
/// contents of the security descriptor.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="bInheritHandle">
|
||||||
|
/// If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="dwProcessId">
|
||||||
|
/// The identifier of the local process to be opened. If the specified process is the System Idle Process(0x00000000), the function fails and the
|
||||||
|
/// last error code is ERROR_INVALID_PARAMETER.If the specified process is the System process or one of the Client Server Run-Time Subsystem(CSRSS)
|
||||||
|
/// processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from
|
||||||
|
/// opening them. If you are using GetCurrentProcessId as an argument to this function, consider using GetCurrentProcess instead of OpenProcess, for
|
||||||
|
/// improved performance.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// If the function succeeds, the return value is an open handle to the specified process.
|
||||||
|
/// If the function fails, the return value is NULL.To get extended error information, call GetLastError.
|
||||||
|
/// </returns>
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
public static extern IntPtr OpenProcess(
|
||||||
|
ProcessAccessFlags dwDesiredAccess,
|
||||||
|
bool bInheritHandle,
|
||||||
|
int dwProcessId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex.
|
/// See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex.
|
||||||
/// Reserves, commits, or changes the state of a region of memory within the virtual address space of a specified process.
|
/// Reserves, commits, or changes the state of a region of memory within the virtual address space of a specified process.
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using static Dalamud.Injector.NativeFunctions;
|
|
||||||
|
|
||||||
namespace Dalamud.Injector
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Pin an arbitrary string to a remote process.
|
|
||||||
/// </summary>
|
|
||||||
internal class RemotePinnedData : IDisposable
|
|
||||||
{
|
|
||||||
private readonly Process process;
|
|
||||||
private readonly byte[] data;
|
|
||||||
private readonly IntPtr allocAddr;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="RemotePinnedData"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="process">Process to write in.</param>
|
|
||||||
/// <param name="data">Data to write.</param>
|
|
||||||
public unsafe RemotePinnedData(Process process, byte[] data)
|
|
||||||
{
|
|
||||||
this.process = process;
|
|
||||||
this.data = data;
|
|
||||||
|
|
||||||
this.allocAddr = VirtualAllocEx(
|
|
||||||
this.process.Handle,
|
|
||||||
IntPtr.Zero,
|
|
||||||
this.data.Length,
|
|
||||||
AllocationType.Commit,
|
|
||||||
MemoryProtection.ReadWrite);
|
|
||||||
|
|
||||||
if (this.allocAddr == IntPtr.Zero || Marshal.GetLastWin32Error() != 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Error allocating memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = WriteProcessMemory(
|
|
||||||
this.process.Handle,
|
|
||||||
this.allocAddr,
|
|
||||||
this.data,
|
|
||||||
this.data.Length,
|
|
||||||
out _);
|
|
||||||
|
|
||||||
if (!result || Marshal.GetLastWin32Error() != 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Error writing memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the pinned data.
|
|
||||||
/// </summary>
|
|
||||||
public IntPtr Address => this.allocAddr;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (this.allocAddr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = VirtualFreeEx(
|
|
||||||
this.process.Handle,
|
|
||||||
this.allocAddr,
|
|
||||||
0,
|
|
||||||
AllocationType.Release);
|
|
||||||
|
|
||||||
if (!result || Marshal.GetLastWin32Error() != 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Error freeing memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue