mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-13 12:14:16 +01:00
Fetch win32 error codes on remote LoadLibrary/GetProcAddress calls (#816)
* Fetch win32 error codes on remote LoadLibrary/GetProcAddress calls * Fix out of index exc
This commit is contained in:
parent
4d7b3bca9c
commit
eb2197132e
2 changed files with 26 additions and 30 deletions
|
|
@ -48,7 +48,7 @@ namespace Dalamud.Injector
|
||||||
args.Add(Marshal.PtrToStringUni(argv[i]));
|
args.Add(Marshal.PtrToStringUni(argv[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[1].ToLowerInvariant() == "launch-test")
|
if (args.Count >= 2 && args[1].ToLowerInvariant() == "launch-test")
|
||||||
{
|
{
|
||||||
Environment.Exit(ProcessLaunchTestCommand(args));
|
Environment.Exit(ProcessLaunchTestCommand(args));
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -83,23 +84,15 @@ 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}");
|
this.CallRemoteFunction(this.loadLibraryShellPtr, lpParameter, out var err);
|
||||||
|
|
||||||
var threadHandle = CreateRemoteThread(
|
if (err != 0)
|
||||||
this.targetProcess.Handle,
|
throw new Exception($"LoadLibraryW(\"{modulePath}\") failure: {new Win32Exception((int)err).Message} ({err})");
|
||||||
IntPtr.Zero,
|
|
||||||
UIntPtr.Zero,
|
|
||||||
this.loadLibraryShellPtr,
|
|
||||||
lpParameter,
|
|
||||||
CreateThreadFlags.RunImmediately,
|
|
||||||
out _);
|
|
||||||
|
|
||||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
|
||||||
|
|
||||||
address = this.extMemory.Read<IntPtr>(this.loadLibraryRetPtr);
|
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($"LoadLibraryW(\"{modulePath}\") failure: Error code unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -113,25 +106,16 @@ namespace Dalamud.Injector
|
||||||
var functionNamePtr = this.WriteNullTerminatedASCIIString(functionName);
|
var functionNamePtr = this.WriteNullTerminatedASCIIString(functionName);
|
||||||
var getProcAddressParams = new GetProcAddressParams(module, functionNamePtr);
|
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)
|
||||||
throw new Exception("Unable to allocate GetProcAddress parameter ptr");
|
throw new Exception("Unable to allocate GetProcAddress parameter ptr");
|
||||||
|
|
||||||
var threadHandle = CreateRemoteThread(
|
this.CallRemoteFunction(this.getProcAddressShellPtr, lpParameter, out var err);
|
||||||
this.targetProcess.Handle,
|
if (err != 0)
|
||||||
IntPtr.Zero,
|
throw new Exception($"GetProcAddress(0x{module:X}, \"{functionName}\") failure: {new Win32Exception((int)err).Message} ({err})");
|
||||||
UIntPtr.Zero,
|
|
||||||
this.getProcAddressShellPtr,
|
|
||||||
lpParameter,
|
|
||||||
CreateThreadFlags.RunImmediately,
|
|
||||||
out _);
|
|
||||||
|
|
||||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
|
||||||
|
|
||||||
this.extMemory.Read(this.getProcAddressRetPtr, out address);
|
this.extMemory.Read(this.getProcAddressRetPtr, out address);
|
||||||
|
|
||||||
if (address == IntPtr.Zero)
|
if (address == IntPtr.Zero)
|
||||||
throw new Exception($"Error calling GetProcAddress with {functionName}");
|
throw new Exception($"GetProcAddress(0x{module:X}, \"{functionName}\") failure: Error code unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -152,6 +136,9 @@ namespace Dalamud.Injector
|
||||||
CreateThreadFlags.RunImmediately,
|
CreateThreadFlags.RunImmediately,
|
||||||
out _);
|
out _);
|
||||||
|
|
||||||
|
if (threadHandle == IntPtr.Zero)
|
||||||
|
throw new Exception($"CreateRemoteThread failure: {Marshal.GetLastWin32Error()}");
|
||||||
|
|
||||||
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
|
||||||
|
|
||||||
GetExitCodeThread(threadHandle, out exitCode);
|
GetExitCodeThread(threadHandle, out exitCode);
|
||||||
|
|
@ -161,8 +148,10 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
private void SetupLoadLibrary(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
private void SetupLoadLibrary(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
||||||
{
|
{
|
||||||
var offset = this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
|
var getLastErrorAddr = kernel32Module.BaseAddress + (int)this.GetExportedFunctionOffset(kernel32Exports, "GetLastError");
|
||||||
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
Log.Verbose($"GetLastError: 0x{getLastErrorAddr.ToInt64():X}");
|
||||||
|
|
||||||
|
var functionAddr = kernel32Module.BaseAddress + (int)this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
|
||||||
Log.Verbose($"LoadLibraryW: 0x{functionAddr.ToInt64():X}");
|
Log.Verbose($"LoadLibraryW: 0x{functionAddr.ToInt64():X}");
|
||||||
|
|
||||||
var functionPtr = this.memoryBuffer.Add(ref functionAddr);
|
var functionPtr = this.memoryBuffer.Add(ref functionAddr);
|
||||||
|
|
@ -187,7 +176,9 @@ namespace Dalamud.Injector
|
||||||
asm.call(__qword_ptr[__qword_ptr[func]]); // call qword [qword func] // CreateRemoteThread lpParameter with string already in ECX.
|
asm.call(__qword_ptr[__qword_ptr[func]]); // call qword [qword func] // CreateRemoteThread lpParameter with string already in ECX.
|
||||||
asm.mov(__qword_ptr[__qword_ptr[retVal]], rax); // mov qword [qword retVal], rax //
|
asm.mov(__qword_ptr[__qword_ptr[retVal]], rax); // mov qword [qword retVal], rax //
|
||||||
asm.add(rsp, 40); // add rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
asm.add(rsp, 40); // add rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
||||||
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
asm.mov(rax, (ulong)getLastErrorAddr); // mov rax, pfnGetLastError // Change return address to GetLastError.
|
||||||
|
asm.push(rax); // push rax //
|
||||||
|
asm.ret(); // ret // Jump to GetLastError.
|
||||||
|
|
||||||
var bytes = this.Assemble(asm);
|
var bytes = this.Assemble(asm);
|
||||||
this.loadLibraryShellPtr = this.memoryBuffer.Add(bytes);
|
this.loadLibraryShellPtr = this.memoryBuffer.Add(bytes);
|
||||||
|
|
@ -212,6 +203,9 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
private void SetupGetProcAddress(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
private void SetupGetProcAddress(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
|
||||||
{
|
{
|
||||||
|
var getLastErrorAddr = kernel32Module.BaseAddress + (int)this.GetExportedFunctionOffset(kernel32Exports, "GetLastError");
|
||||||
|
Log.Verbose($"GetLastError: 0x{getLastErrorAddr.ToInt64():X}");
|
||||||
|
|
||||||
var offset = this.GetExportedFunctionOffset(kernel32Exports, "GetProcAddress");
|
var offset = this.GetExportedFunctionOffset(kernel32Exports, "GetProcAddress");
|
||||||
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
var functionAddr = kernel32Module.BaseAddress + (int)offset;
|
||||||
Log.Verbose($"GetProcAddress: 0x{functionAddr.ToInt64():X}");
|
Log.Verbose($"GetProcAddress: 0x{functionAddr.ToInt64():X}");
|
||||||
|
|
@ -240,7 +234,9 @@ namespace Dalamud.Injector
|
||||||
asm.call(__qword_ptr[__qword_ptr[func]]); // call qword [qword func] //
|
asm.call(__qword_ptr[__qword_ptr[func]]); // call qword [qword func] //
|
||||||
asm.mov(__qword_ptr[__qword_ptr[retVal]], rax); // mov qword [qword retVal] //
|
asm.mov(__qword_ptr[__qword_ptr[retVal]], rax); // mov qword [qword retVal] //
|
||||||
asm.add(rsp, 40); // add rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
asm.add(rsp, 40); // add rsp, 40 // Re-align stack to 16 byte boundary + shadow space.
|
||||||
asm.ret(); // ret // Restore stack ptr. (Callee cleanup)
|
asm.mov(rax, (ulong)getLastErrorAddr); // mov rax, pfnGetLastError // Change return address to GetLastError.
|
||||||
|
asm.push(rax); // push rax //
|
||||||
|
asm.ret(); // ret // Jump to GetLastError.
|
||||||
|
|
||||||
var bytes = this.Assemble(asm);
|
var bytes = this.Assemble(asm);
|
||||||
this.getProcAddressShellPtr = this.memoryBuffer.Add(bytes);
|
this.getProcAddressShellPtr = this.memoryBuffer.Add(bytes);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue