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:
kizer 2022-04-24 04:37:32 +09:00 committed by GitHub
parent 4d7b3bca9c
commit eb2197132e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 30 deletions

View file

@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -83,23 +84,15 @@ namespace Dalamud.Injector
if (lpParameter == IntPtr.Zero)
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(
this.targetProcess.Handle,
IntPtr.Zero,
UIntPtr.Zero,
this.loadLibraryShellPtr,
lpParameter,
CreateThreadFlags.RunImmediately,
out _);
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
if (err != 0)
throw new Exception($"LoadLibraryW(\"{modulePath}\") failure: {new Win32Exception((int)err).Message} ({err})");
address = this.extMemory.Read<IntPtr>(this.loadLibraryRetPtr);
if (address == IntPtr.Zero)
throw new Exception($"Error calling LoadLibraryW with {modulePath}");
throw new Exception($"LoadLibraryW(\"{modulePath}\") failure: Error code unavailable");
}
/// <summary>
@ -113,25 +106,16 @@ namespace Dalamud.Injector
var functionNamePtr = this.WriteNullTerminatedASCIIString(functionName);
var getProcAddressParams = new GetProcAddressParams(module, functionNamePtr);
var lpParameter = this.circularBuffer.Add(ref getProcAddressParams);
if (lpParameter == IntPtr.Zero)
throw new Exception("Unable to allocate GetProcAddress parameter ptr");
var threadHandle = CreateRemoteThread(
this.targetProcess.Handle,
IntPtr.Zero,
UIntPtr.Zero,
this.getProcAddressShellPtr,
lpParameter,
CreateThreadFlags.RunImmediately,
out _);
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
this.CallRemoteFunction(this.getProcAddressShellPtr, lpParameter, out var err);
if (err != 0)
throw new Exception($"GetProcAddress(0x{module:X}, \"{functionName}\") failure: {new Win32Exception((int)err).Message} ({err})");
this.extMemory.Read(this.getProcAddressRetPtr, out address);
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>
@ -152,6 +136,9 @@ namespace Dalamud.Injector
CreateThreadFlags.RunImmediately,
out _);
if (threadHandle == IntPtr.Zero)
throw new Exception($"CreateRemoteThread failure: {Marshal.GetLastWin32Error()}");
_ = WaitForSingleObject(threadHandle, uint.MaxValue);
GetExitCodeThread(threadHandle, out exitCode);
@ -161,8 +148,10 @@ namespace Dalamud.Injector
private void SetupLoadLibrary(ProcessModule kernel32Module, ExportFunction[] kernel32Exports)
{
var offset = this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
var functionAddr = kernel32Module.BaseAddress + (int)offset;
var getLastErrorAddr = kernel32Module.BaseAddress + (int)this.GetExportedFunctionOffset(kernel32Exports, "GetLastError");
Log.Verbose($"GetLastError: 0x{getLastErrorAddr.ToInt64():X}");
var functionAddr = kernel32Module.BaseAddress + (int)this.GetExportedFunctionOffset(kernel32Exports, "LoadLibraryW");
Log.Verbose($"LoadLibraryW: 0x{functionAddr.ToInt64():X}");
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.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.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);
this.loadLibraryShellPtr = this.memoryBuffer.Add(bytes);
@ -212,6 +203,9 @@ namespace Dalamud.Injector
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 functionAddr = kernel32Module.BaseAddress + (int)offset;
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.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.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);
this.getProcAddressShellPtr = this.memoryBuffer.Add(bytes);