使用 Get- 和 SetThreadContext 的组合更改线程的起始地址?

逆向工程 部件 线 地址
2021-06-11 19:56:14

我有以下装配线:

 PUSH 0
 PUSH 4                                   ; CreationFlags = CREATE_SUSPENDED
 PUSH 0
 PUSH program.0040163B                    ; start address of thread 
 PUSH 0
 PUSH 0
 CALL DWORD PTR DS:[402428]               ; kernel32.CreateThread 
 MOV DWORD PTR DS:[4023F8], EAX           ; store handle to created thread to [4023F8]
 ....
 ....
 LEA ESI, DWORD PTR DS:[402000]
 PUSH ESI                                 ; [402000] will be the location where we store the context of the thread
 PUSH DWORD PTR DS:[4023F8]               ; handle to created thread
 CALL DWORD PTR DS:[402424]               ; kernel32.GetThreadContext
 MOV [ESI+B0], program.004010E9           ; [ESI+B0] = [4020B0] = 0040163B (starting address of the created thread will be replaced by 004010E9, I guess)
 PUSH ESI                                 ; ESI points to 402000 where the thread context is stored, but now with a modified starting address of the thread
 PUSH DWORD PTR DS:[4023F8]               ; handle to thread
 CALL DWORD PTR DS:[402418]               ; kernel32.SetThreadContext
 PUSH DWORD PTR DS:[4023F8]
 CALL DWORD PTR DS:[402410]               ; kernel32.ResumeThread
 ....
 ....
 RETN

所以,总结一下:我们创建了一个处于挂起状态的线程。它的起始地址是 0040163B。然后我们得到线程上下文,存入402000,通过将B0的偏移量加上402000,就到了上下文结构体中存放线程起始地址的地方。我们将其更改为 004010E9 并使用 SetThreadContext 设置修改后的上下文。

所以,我的问题是:当我到达/调用 ResumeThread() 时,线程的起始地址将是 0040163B 还是 004010E9 ?因为Get-和SetThreadContext的结合,所以我的线程的起始地址必须是004010E9是有道理的,但我想确定一下。

编辑:

总之我的问题是
(1) 如果我创建一个挂起的线程
(2) 通过 SetThreadContext 改变其入口点  
(3) 恢复挂起的线程

线程会在原始入口点CreateThread或新修改的入口点处开始执行吗?

1个回答

你的直觉是正确的。更改 Thread via 的起始地址SetThreadContext将更改入口点。这是一个 C++ 片段来验证我们的声明

#include <Windows.h>
#include <WinNT.h>

DWORD WINAPI orig_entry( LPVOID param)
{
    MessageBoxA(0, "Original Thread Entrypoint called", "", MB_OK);
    return 0;   
}

DWORD WINAPI new_entry(LPVOID param)
{
    MessageBoxA(0, "Modified Thread Entrypoint called", "", MB_OK);
    return 0;   
}

int main()
{
    HANDLE tHand;
    CONTEXT ctx;

    //Thread created with orig_entry as starting address
    tHand = CreateThread(NULL, 0, orig_entry, NULL, CREATE_SUSPENDED, NULL);

    ctx.ContextFlags = CONTEXT_INTEGER; //We only want to get/set register eax
    GetThreadContext(tHand, &ctx);

    //Entry point is stored in register eax (ctx + 0xB0)
    ctx.Eax = (DWORD) new_entry;    
    ctx.ContextFlags = CONTEXT_INTEGER;

    //Comment the line below to see the difference
    SetThreadContext(tHand, &ctx);

    ResumeThread(tHand);    
    Sleep(-1);  //Pause main thread permanently
    return 0;
}

运行代码,你会注意到函数new_entry被调用,这证明入口点被改变了SetThreadContext