C 如何在64位进程(Windows)上正确保存和恢复线程上下文?

C 如何在64位进程(Windows)上正确保存和恢复线程上下文?,c,assembly,64-bit,code-injection,threadcontext,C,Assembly,64 Bit,Code Injection,Threadcontext,下面是从64位进程中释放库的代码。它完成了它的工作,但问题是在恢复保存的上下文后,目标进程就崩溃了。不知道这里有什么问题。它应该设置所有寄存器和标志,它们以前是什么,对吗?。我做错了什么 #ifdef _WIN64 const static unsigned char FreeLibrary_InjectionCodeRAW_x64[] = { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //mov rax,

下面是从64位进程中释放库的代码。它完成了它的工作,但问题是在恢复保存的上下文后,目标进程就崩溃了。不知道这里有什么问题。它应该设置所有寄存器和标志,它们以前是什么,对吗?。我做错了什么

#ifdef _WIN64

const static unsigned char FreeLibrary_InjectionCodeRAW_x64[] =
{
    0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //mov rax, value
    0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //mov rcx, value
    0xFF, 0xD0, //call rax (FreeLibrary)
    0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //mov rax, value
    0xC7, 0x00, 0x01, 0x00, 0x00, 0x00, //mov [rax],1
    0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //mov rax, value
    0xB9, 0x64, 0x00, 0x00, 0x00, //mov ecx, 0x64
    0xFF, 0xD0, //call Sleep 
    0xEB, 0xED, //jmp
    0x00, 0x00, 0x00, 0x00 //status
};

#pragma pack(push, 1)
struct FreeLibrary_InjectionCode_x64
{
    FreeLibrary_InjectionCode_x64()
    {
        memcpy(this, FreeLibrary_InjectionCodeRAW_x64, sizeof(FreeLibrary_InjectionCodeRAW_x64));
    }

    char code_1[2];
    FARPROC lpFreeLibrary;
    char code_2[2];
    HMODULE hLib;
    char code_3[4];
    LPVOID lpStatusAddress;
    char code_4[8];
    FARPROC lpSleep;
    char code_5[9];
    int status;
};
#pragma pack(pop)

#endif

void FreeLib(const char what[], const char where[])
{
    HANDLE hToken;
    OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
    SetPrivilege(hToken, SE_DEBUG_NAME, TRUE);
    CloseHandle(hToken);
    OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken);
    SetPrivilege(hToken, SE_DEBUG_NAME, TRUE);
    CloseHandle(hToken);

    HMODULE hMod;
    DWORD dwProcessId = GetProcessIdByName(where);
    if ((hMod = GetModuleHandleInProcess(what, dwProcessId)) != NULL)
    {
        HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, FALSE, dwProcessId);
        if (hProcess != NULL)
        {
            HMODULE hKernel = LoadLibrary("kernel32.dll");
            FARPROC FLaddr = GetProcAddress(hKernel, "FreeLibrary");
            FARPROC Saddr = GetProcAddress(hKernel, "Sleep");

            HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION | THREAD_SUSPEND_RESUME,
                FALSE, GetValidThreadIdInProcess(dwProcessId));

            if (hThread != NULL && FLaddr != NULL && Saddr != NULL)
            {
                LPVOID addr = VirtualAllocEx(hProcess, NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                LPVOID lpStatusAddress = (PUCHAR)addr + (sizeof(FreeLibrary_InjectionCode_x64)-sizeof(int));
                FreeLibrary_InjectionCode_x64 code = FreeLibrary_InjectionCode_x64();
                code.hLib = hMod;
                code.lpFreeLibrary = FLaddr;
                code.lpSleep = Saddr;
                code.lpStatusAddress = lpStatusAddress;
                WriteProcessMemory(hProcess, addr, &code, sizeof(FreeLibrary_InjectionCode_x64), NULL);

                CONTEXT ctx, oldCtx;
                ctx.ContextFlags = CONTEXT_ALL;

                SuspendThread(hThread);
                GetThreadContext(hThread, &ctx);

                memcpy(&oldCtx, &ctx, sizeof(CONTEXT));
                ctx.Rip = (DWORD64)addr; 

                SetThreadContext(hThread, &ctx);
                ResumeThread(hThread);

                while (!code.status)
                {
                    Sleep(15);
                    ReadProcessMemory(hProcess, addr, &code, sizeof(FreeLibrary_InjectionCode_x64), NULL);
                }

                SuspendThread(hThread);
                SetThreadContext(hThread, &oldCtx);
                ResumeThread(hThread);

                VirtualFreeEx(hProcess, addr, 4096, MEM_DECOMMIT);

                CloseHandle(hThread);
            }

            CloseHandle(hProcess);
        }
    }
}

您没有执行任何错误处理,以确保在执行另一个进程之前已实际分配内存并将其写入另一个进程,或者确保
ReadProcessMemory()
成功,或者确保线程挂起/恢复和上下文交换成功

很有可能,远程线程在注入器有机会在原始上下文信息中调回之前,已经运行了注入的代码,并尝试运行其原始代码(甚至是在内存中分配的块之后的随机代码)。这可能是撞车的原因


<> P>不要在另一个进程中劫持一个现有线程,并将其上下文隐藏在其背后,您可能需要考虑使用<代码> CurraseMeTeTeRead()/代码>,而不是在自己的专用线程中运行注入的代码。不需要上下文交换。

Windows 64位使用fastcall调用约定。在此约定中,函数调用方负责在堆栈上为被调用函数保留4*64位(32字节)以保存寄存器。 这意味着您的呼叫应如下所示:

sub rsp, 32
call rax
add rsp, 32

在代码中,对FreeLibrary或Sleep的调用会覆盖不属于其堆栈框架的堆栈,导致稍后崩溃。

正如我所说的-注入代码很好-它可以工作。查看
freebrary\u InjectionCode\u x64
构造函数,它用
freebrary\u InjectionCode\u x64
填充内存。4096对于代码和
int status
来说已经足够了。关于阅读整个
FreeLibrary\u InjectionCode\u x64
,它只是更方便(对我来说)。如果仔细查看asm代码,远程线程实际上正在循环中等待恢复到其原始状态。毫无疑问,如果我想使用
CreateRemoteThread()
方法注入代码。需要说明的是,除了恢复线程上下文(此处崩溃)之外,一切正常(内存已分配,
ReadProcessMemory()
不会失败,远程线程更改
int状态
,并等待beign切换回其原始状态)。不过,为什么不使用
CreateRemoteThread()
?这样会更安全,也更容易管理。没有要写入的程序集代码(
freebrary()
可以是执行的线程进程,其输入参数为
hMod
)。无需上下文交换,无需远程睡眠,无需循环。不再需要状态变量,如果需要,可以通过
GetExitCodeThread()
检索
FreeLibrary()
的结果。调用线程可以使用
WaitForSingleObject()
等待远程线程终止。我就是不能使用
CreateRemoteThread()
。我需要静默代码执行,因为大多数防病毒程序会将我的应用程序检测为威胁。另一个原因是
CreateRemoteThread()
方法在windows 8中的某些进程上不起作用。