如果编辑线程的指令指针,如何跳回到(旧的)指令指针?

问题描述 投票:2回答:1

我正在尝试编辑线程的指令指针,以使其在跳回旧的指令指针并按常规继续之前,先调用某些已组装的x64程序集。在继续执行假定的线程后,我正在执行此操作的程序崩溃,它表明它没有跳回到旧的指令指针。

当前,我正在尝试以下方法

获取线程的句柄

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenThread(ThreadPrivileges dwDesiredAccess, bool bInheritHandle, IntPtr dwThreadId);

public enum ThreadPrivileges
{
    SuspendResume = 0x02,
    GetContext = 0x08,
    SetContext = 0x010,
    AllAccess = SuspendResume | GetContext | SetContext
}

var threadId = Process.GetProcessesByName(processName)[0].Threads[0].Id;

var threadHandle = OpenThread(ThreadPrivileges.AllAccess, false, (IntPtr)threadId);

暂停线程

[DllImport("kernel32.dll", SetLastError = true)]
public static extern void SuspendThread(IntPtr hThread);

SuspendThread(threadHandle); 

获取线程的上下文

[Context64和ContextFlags的结构可以在此link中找到

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetThreadContext(IntPtr hThread, ref Context64 lpContext);

var context = new Context64() { ContextFlags = ContextFlags.ContextFull };
GetThreadContext(threadHandle, ref context);

试图将旧的指令指针写入堆栈

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, int lpNumberOfBytesWritten);

context.Rsp -= sizeof(ulong); // Allocate 8 bytes on the stack

WriteProcessMemory(processHandle, (IntPtr)context.Rsp, BitConverter.GetBytes(context.Rip), sizeof(ulong), 0);

覆盖指令指针

context.Rip = (ulong)myAssemblyPointer;

将线程上下文设置为已编辑的上下文

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetThreadContext(IntPtr hThread, ref Context64 lpContext);

SetThreadContext(threadHandle, ref context);

最后恢复线程

[DllImport("kernel32.dll", SetLastError = true)]
public static extern void ResumeThread(IntPtr hThread);

ResumeThread(threadHandle);

我不确定这是否有任何相关性,但是我正在使用的程序集如下

PUSHFQ
PUSH rax
PUSH rbx
PUSH rcx
PUSH rdx
PUSH r8
PUSH r9
PUSH r10
PUSH r11

sub RSP, 0x28
movabs RCX, 0x0000000000000000  ; Pointer 1
movabs RAX, 0x0000000000000000  ; Pointer 2
call RAX
add RSP, 0x28

POP r11
POP r10
POP r9
POP r8
POP rdx
POP rcx
POP rbx
POP rax
POPFQ

ret

我已尽我所能排除尽可能多的代码(错误检查和清除),以使这篇文章简短,但是我所有的错误检查似乎都表明pinvoke方法正在按预期工作。我主要担心的是当我尝试将旧的指令指针写入堆栈时。虽然WriteProcessMemory没有失败,但是我有一种错误的感觉。如果有人可以向我解释我是否正确地将旧的指令指针正确地写入了堆栈,如果不能,我将如何实现它,我将不胜感激。

[如果您想让我提供其他信息,例如processHandlemyAssemblyPointer变量,请告诉我。

c# assembly 64-bit pinvoke x86-64
1个回答
0
投票

根据评论:

您仅读取4个字节,您需要读取8个字节,因为它是x64进程,并且这是内存地址指针所需的大小。 long只有4个字节,您需要使用long long。

© www.soinside.com 2019 - 2024. All rights reserved.