导致 CreateRemoteThread 的奇怪调用堆栈

Weird callstack leading up to CreateRemoteThread

我很难理解下面的调用堆栈。

ntdll!NtCreateThreadEx+0xc
KERNELBASE!CreateRemoteThreadEx+0x1f0
kernel32!CreateThreadStub+0x27
MyModule!_beginthreadex+0x87

抱歉,由于专有问题,我无法透露更多内容,但我相信我们应该至少能够从中理解部分意义。那是我正在查看的故障转储中由第三方库生成的线程的状态。 (线程本身与我正在调查的问题无关。)

什么情况可能导致对 _beginthreadex 的调用在 CreateRemoteThread 中结束? API 的 MSDN 文档没有给我任何线索('remote' 这个词甚至没有出现在那个页面上。)

我有第三方库的符号,调用堆栈绝对合法。

更新:

有意思。如果我从 CreateThreadStub 应该 return 的位置向后反汇编,我看到以下说明:

call    dword ptr [MyModule!_imp__CreateThread (573701a0)]
cmp     eax,ebx

当我这样做时:

0:048> dds MyModule!_imp__CreateThread l1
573701a0  75b5cf30 kernel32!CreateThreadStub

当我反汇编 CreateThreadStub 时,我确实看到它调用 CreateRemoteThread。这一切都非常混乱!

您发布的堆栈是正常堆栈。编译以下 C++ 代码:

#include "stdafx.h"
#include <iostream>
#include <process.h>
#include <Windows.h>
using namespace std;

void test(void *param)
{
    Sleep(1000);
    _endthread();
}

int main()
{
    HANDLE hThread;
    hThread = (HANDLE)_beginthread(test, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);
    return 0;
}
  1. 启动 WinDbg
  2. 打开可执行文件
  3. 在初始断点处,设置断点

    0:000> bp KERNELBASE!CreateRemoteThreadEx
    0:000> bl
         0 e Disable Clear  7485b060     0001 (0001)  0:**** KERNELBASE!CreateRemoteThreadEx
    0:000> g
    
  4. 看到main()方法在命中_beginthread()方法时调用了CreateRemoteThreadEx()

    0:000> k
     # ChildEBP RetAddr  
    WARNING: Stack unwind information not available. Following frames may be wrong.
    00 00f7f714 0f7ba3cd KERNELBASE!CreateRemoteThreadEx
    01 00f7f758 000f255f ucrtbased!_beginthread+0xed [d:\rs1\minkernel\crts\ucrt\src\appcrt\startup\thread.cpp @ 174] 
    02 00f7f844 000f2cbe ThreadStartStack!main+0x2f [c:\users\t\documents\visual studio 2015\projects\threadstartstack\threadstartstack\threadstartstack.cpp @ 19] 
    03 00f7f858 000f2b20 ThreadStartStack!invoke_main+0x1e [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 64] 
    04 00f7f8b0 000f29bd ThreadStartStack!__scrt_common_main_seh+0x150 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 253] 
    05 00f7f8b8 000f2cd8 ThreadStartStack!__scrt_common_main+0xd [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 296] 
    06 00f7f8c0 752362c4 ThreadStartStack!mainCRTStartup+0x8 [f:\dd\vctools\crt\vcstartup\src\startup\exe_main.cpp @ 17] 
    07 00f7f8d4 77370fd9 KERNEL32!BaseThreadInitThunk+0x24
    08 00f7f91c 77370fa4 ntdll!__RtlUserThreadStart+0x2f
    09 00f7f92c 00000000 ntdll!_RtlUserThreadStart+0x1b
    

MSDN 上的功能描述有点误导:

Creates a thread that runs in the virtual address space of another process.

评论的第一行是CreateRemoteThread的更好的总结:

The CreateRemoteThread function causes a new thread of execution to begin in the address space of the specified process.

至少通过这个描述,很明显您可以使用 CreateRemoteThread 在本地进程中创建一个线程,只需指定当前进程即可。还要在 CreateRemoteThreadEx 备注中注意这一点:

The CreateRemoteThreadEx function causes a new thread of execution to begin in the address space of the specified process. The thread has access to all objects that the process opens. The lpAttribute parameter can be used to specify extended attributes such as processor group affinity for the new thread. If lpAttribute is NULL, the function's behavior is the same as CreateRemoteThread.

当您考虑到内核模式的转换时,事实上 CreateRemoteThreadEx 通过选择参数可以完成 CreateThreadCreateRemoteThread 可以做的所有事情,并且测试每个系统调用的正确性和安全性的维护成本,只提供一个具有所有功能超集的系统调用,并让所有这些功能都使用它是有意义的。