Fix 32-bit host context APIs and ExternalReader bitness detection
- Add GetThreadContext/SetThreadContext overloads accepting Context32 so a 32-bit process on a native 32-bit OS can capture x86 thread context. - DllInjector.InjectWithThreadHijack now selects the context API based on both process bitness and OS bitness: * 64-bit process -> native 64-bit context * 32-bit process on 64-bit OS -> WOW64 context * 32-bit process on 32-bit OS -> native x86 context - ExternalReader now validates that the caller supplied ProcessAccess.QueryInformation, and surfaces any IsWow64Process failure instead of silently falling back to host bitness. Tests: 207 passing, 4 skipped.
This commit is contained in:
@@ -215,7 +215,7 @@ public sealed class DllInjector
|
||||
{
|
||||
IntPtr result;
|
||||
|
||||
if (_currentIs64Bit)
|
||||
if (Environment.Is64BitProcess)
|
||||
{
|
||||
var originalContext = new Context64 { ContextFlags = ContextFlags.Amd64Full };
|
||||
if (!NativeMethods.GetThreadContext(thread, ref originalContext))
|
||||
@@ -264,21 +264,32 @@ public sealed class DllInjector
|
||||
}
|
||||
else
|
||||
{
|
||||
// 32-bit process on either a 32-bit or 64-bit (WOW64) host.
|
||||
bool useWow64 = Environment.Is64BitOperatingSystem;
|
||||
|
||||
var originalContext = new Context32 { ContextFlags = ContextFlags.X86Full };
|
||||
if (!NativeMethods.Wow64GetThreadContext(thread, ref originalContext))
|
||||
bool gotContext = useWow64
|
||||
? NativeMethods.Wow64GetThreadContext(thread, ref originalContext)
|
||||
: NativeMethods.GetThreadContext(thread, ref originalContext);
|
||||
if (!gotContext)
|
||||
{
|
||||
int error = Marshal.GetLastPInvokeError();
|
||||
throw new InvalidOperationException($"Wow64GetThreadContext failed (error {error}).");
|
||||
string api = useWow64 ? "Wow64GetThreadContext" : "GetThreadContext";
|
||||
throw new InvalidOperationException($"{api} failed (error {error}).");
|
||||
}
|
||||
|
||||
var redirectContext = originalContext;
|
||||
redirectContext.Eip = (uint)(nint)remoteBase;
|
||||
redirectContext.Esp = (uint)(nint)stackTop;
|
||||
|
||||
if (!NativeMethods.Wow64SetThreadContext(thread, ref redirectContext))
|
||||
bool setContext = useWow64
|
||||
? NativeMethods.Wow64SetThreadContext(thread, ref redirectContext)
|
||||
: NativeMethods.SetThreadContext(thread, ref redirectContext);
|
||||
if (!setContext)
|
||||
{
|
||||
int error = Marshal.GetLastPInvokeError();
|
||||
throw new InvalidOperationException($"Wow64SetThreadContext failed (error {error}).");
|
||||
string api = useWow64 ? "Wow64SetThreadContext" : "SetThreadContext";
|
||||
throw new InvalidOperationException($"{api} failed (error {error}).");
|
||||
}
|
||||
|
||||
if (NativeMethods.ResumeThread(thread) == 0xFFFFFFFF)
|
||||
@@ -295,10 +306,14 @@ public sealed class DllInjector
|
||||
throw new InvalidOperationException($"SuspendThread failed while capturing result (error {error}).");
|
||||
}
|
||||
|
||||
if (!NativeMethods.Wow64SetThreadContext(thread, ref originalContext))
|
||||
bool restoredContext = useWow64
|
||||
? NativeMethods.Wow64SetThreadContext(thread, ref originalContext)
|
||||
: NativeMethods.SetThreadContext(thread, ref originalContext);
|
||||
if (!restoredContext)
|
||||
{
|
||||
int error = Marshal.GetLastPInvokeError();
|
||||
throw new InvalidOperationException($"Wow64SetThreadContext restore failed (error {error}).");
|
||||
string api = useWow64 ? "Wow64SetThreadContext" : "SetThreadContext";
|
||||
throw new InvalidOperationException($"{api} restore failed (error {error}).");
|
||||
}
|
||||
|
||||
if (NativeMethods.ResumeThread(thread) == 0xFFFFFFFF)
|
||||
|
||||
Reference in New Issue
Block a user