如果你打电话CreateProcess https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx系统内部调用ZwCreateThread[Ex] http://processhacker.sourceforge.net/doc/ntzwapi_8h.html#a8d4778b0d54da088821971642873ef51创建进程中的第一个线程
当你创建线程时 - 你(如果你直接调用ZwCreateThread http://processhacker.sourceforge.net/doc/ntzwapi_8h.html#a8d4778b0d54da088821971642873ef51)或系统初始化CONTEXT https://msdn.microsoft.com/en-us/library/windows/desktop/ms679284(v=vs.85).aspx新线程记录 - 此处Eip(i386)
or Rip(amd64)
线程的入口点。如果您这样做 - 您可以指定任何地址。但当你打电话说Create[Remote]Thread[Ex] https://msdn.microsoft.com/en-us/library/windows/desktop/dd405484(v=vs.85).aspx- 我怎么说 - 系统填充CONTEXT https://msdn.microsoft.com/en-us/library/windows/desktop/ms679284(v=vs.85).aspx并将自身例程设置为线程入口点。您的原始入口点保存在Eax(i386)
or Rcx(amd64)
登记。
该例程的名称取决于 Windows 版本。
早些时候这是BaseThreadStartThunk
or BaseProcessStartThunk
(如果从CreateProcess
称为)来自kernel32.dll
.
但现在系统指定RtlUserThreadStart
from ntdll.dll
. the RtlUserThreadStart
通常打电话BaseThreadInitThunk
from kernel32.dll
(本机(启动执行)应用程序除外,例如smss.exe
and chkdsk.exe
其中没有kernel32.dll
完全在自地址空间中)。BaseThreadInitThunk
已经调用您的原始线程入口点,并且在(如果)它返回之后 -RtlExitUserThread https://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx called.
the main goal of this common thread startup wrapper - set the top level SEH https://msdn.microsoft.com/en-us/library/windows/desktop/ms679270(v=vs.85).aspx filter. only because this we can call SetUnhandledExceptionFilter https://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx function. if thread start direct from your entry point, without wrapper - the functional of Top level Exception Filter https://msdn.microsoft.com/en-us/library/windows/desktop/ms681401(v=vs.85).aspx become unavailable.
但无论线程入口点是什么——用户空间中的线程——NEVER从此时开始执行!
当用户模式线程开始执行时尽早 - 系统插入APC
与LdrInitializeThunk
作为 Apc 例程 - 这是通过复制(保存)线程完成的CONTEXT
到用户堆栈然后调用KiUserApcDispatcher
哪个电话LdrInitializeThunk
. when LdrInitializeThunk
完成 - 我们回到KiUserApcDispatcher
这叫NtContinue
与保存的线程CONTEXT
- 仅在该线程入口点开始执行之后。
但现在系统在这个过程中做了一些优化 - 它复制(保存)线程CONTEXT
到用户堆栈并直接调用LdrInitializeThunk
。在此函数的末尾NtContinue
被调用 - 和正在执行的线程入口点。
so EVERY线程从用户模式开始执行LdrInitializeThunk
. (这个函数的名称准确,在从 nt4 到 win10 的所有 Windows 版本中都存在并调用)
what is this function do ? for what is this ? you may be listen about DLL_THREAD_ATTACH https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx notification ? when new thread in process begin executed (with exception for special system worked threads, like LdrpWorkCallback
)- he walk by loaded DLL list, and call DLLs entry points with DLL_THREAD_ATTACH https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx notification (of course if DLL have entry point and DisableThreadLibraryCalls https://msdn.microsoft.com/en-us/library/windows/desktop/ms682579(v=vs.85).aspx not called for this DLL). but how this is implemented ? thanks to LdrInitializeThunk
which call LdrpInitialize
-> LdrpInitializeThread
-> LdrpCallInitRoutine
(for DLLs EP)
when the first thread in process start - this is special case. need do many extra jobs for process initialization. at this time only two modules loaded in process - EXE
and ntdll.dll
. LdrInitializeThunk
call LdrpInitializeProcess
for this job. if very briefly:
-
不同的进程结构被初始化
-
静态加载 EXE 的所有 DLL(及其依赖项)
链接 - 但不称它们为 EP!
-
called LdrpDoDebuggerBreak
- 这个函数看起来 - 是调试器
附加到流程,如果是 -int 3
称为 - 所以调试器
接收异常消息 -STATUS_BREAKPOINT
- 大多数调试器可以
UI 调试仅从此时开始。然而存在
调试器,它让调试过程从LdrInitializeThunk
-
我所有的屏幕截图都来自这种调试器
-
重要的一点 - 直到进程中只执行代码ntdll.dll
(并且可能来自kernel32.dll
) - 来自另一个的代码
DLL,任何尚未在进程中执行的第三方代码。
-
可选加载的 shim dll 来处理 - Shim 引擎已初始化。但
这是可选的
-
遍历加载的 DLL 列表并调用其 EPDLL_PROCESS_DETACH https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
-
TLS https://msdn.microsoft.com/en-us/library/windows/desktop/ms686749(v=vs.85).aspx调用初始化和 TLS 回调(如果存在)
-
ZwTestAlert
被调用 - 此调用检查线程中是否存在 APC
排队,并执行它。这一点在NT4到所有版本中都存在
win 10。例如,以挂起状态创建进程
然后插入 APC 调用(QueueUserAPC https://msdn.microsoft.com/en-us/library/windows/desktop/ms684954(v=vs.85).aspx)到它的线程
(PROCESS_INFORMATION.hThread
) - 结果这个调用将是
进程完全初始化后执行,所有DLL_PROCESS_DETACH
调用,但在 EXE 入口点之前。在上下文中
第一个进程线程。
-
最后调用 NtContinue - 此恢复保存的线程上下文
我们终于跳到线程 EP
read also Flow of CreateProcess https://web.archive.org/web/20151214014944/https://www.microsoft.com/mspress/books/sampchap/4354a.aspx