由于未知原因,SetThreadContext在x64进程中无法正常工作。我打算在挂起的线程上使用它来修改指令指针并使线程执行一些shellcode。不幸的是,SetThreadContext似乎只修改了x64指令RIP的最后32位。
为了隔离问题,我制作了以下小程序,提示用户输入一个线程ID,如果它成功连接到线程,用户可以输入一个地址来手动修改指令指针。
#include <Windows.h>
#include <iostream>
using namespace std;
int main() {
DWORD tid = 0;
cout << "Thread ID: ";
cin >> dec >> tid;
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid);
if (hThread == NULL) {
cout << "Failed." << endl;
system("pause");
return EXIT_FAILURE;
}
DWORD64 newRip = 0;
cout << "New RIP: 0x";
cin >> hex >> newRip;
CONTEXT tcNew;
SecureZeroMemory(&tcNew, sizeof(tcNew));
tcNew.ContextFlags = CONTEXT_FULL;
tcNew.Rip = newRip;
SuspendThread(hThread);
SetThreadContext(hThread, &tcNew);
ResumeThread(hThread);
cout << "Done." << endl;
system("pause");
return EXIT_SUCCESS;
}
现在,如果我启动另一个x64进程,我附加到调试器并使用Process Hacker或Sysinternals的Process Explorer等工具来获取此进程的运行线程ID,我可以简单地将此程序附加到我想要修改的线程中输入我希望它执行的地址。
我用几个程序进行了测试(一些用我的Visual Studio和我的Windows中的一些x64进程编译,如记事本或mspaint),如果我将新RIP设置为0x1234567890ABCDEF,那么我得到一个Access违规执行位置0x0000000090ABCDEF
现在这很有意思,似乎RIP地址中最重要的32位在这个过程中由于某种原因而丢失,我无法解释。我想到了我的Visual Studio项目配置中的一些问题,所以我再次从头开始,但同样的事情。我还尝试安装另一个IDE和编译器(Code :: Blocks和MinGW64)但由于某种原因问题仍然存在。更有趣的是,GetThreadContext运行良好,我成功获得了RIP处于挂起线程中的64位地址。只有SetThreadContext似乎是问题所在。
如果你知道为什么会发生这种情况,或者有任何实验建议,我可以试着让我对如何解决这个问题有新的想法,请毫不犹豫地分享。
非常感谢你。
谢谢@RbMm在CONTEXT上调用GetThreadContext然后用来编辑RIP解决了这个问题。我将详细了解此SegCs的作用,以更详细地了解此问题的原因。