揭秘Windows程序启动的神秘之旅

📅 2026/8/3 3:00:48
揭秘Windows程序启动的神秘之旅
程序的真正入口winmain或者main不是真正的入口只是语法规定的入口。通常通过mainCRTStartup、wimmainCRTStartup、WinMainCRTStartup或者wWinMainCRTStartup。启动函数默认的#includeiostreamintmain() {std::cout Hello, World! std::endl;return0;}直接使用msvc我是用的tools可能不一样自己的为准。挂断点看堆栈我们的调用流我反着写main()àinvoke_main()à__scrt_common_main_seh()à__scrt_common_main()àmainCRTStartup()àkernel32.dllàntdl\windows内核再次我会在后续补充完整流程这个不太支持windows的编译工具。调用的函数invoke_main__scrt_common_main_seh()__scrt_common_main()mainCRTStartup()kernel32.dllàBaseThreadInitThunk12()ntdll.dllà__RtlUserThreadStart()__RtlUserThreadStart8()详细流程内核调度(ntdll.dll) __RtlUserThreadStart8()和__RtlUserThreadStart()àstdcall 调用约定初始化teb(Thread Environment Block)设置seh(结构化异常处理) 链初始化浮点/向量寄存器状态调用线程入口函数 (BaseThreadInitThunk)à kernel32.dll BaseThreadInitThunk12()发送 DLL_THREAD_ATTACH 通知给所有已加载的 DLL初始化线程本地存储Thread Local Storage捕获未处理的异常并上报入口函数返回后调用 ExitThread 清理stdcall由被调用者清理栈调用mainCRTStartup()à进入exe mainCRTStartup()进程专用入口点连接器是*.exe入口控制台使用gui使用winmaincrtstartupà__scrt_common_main()你的可执行文件静态链接到 CRT 库核心主逻辑负责运行时库所有的初始化和清理à__scrt_common_main_seh()(she异常保护壳)用—try/--except包裹主流程兜底捕获未处理的系统异常à invoke_main调用main的封装统一处理参数最终进入用户代码àmain()详细说明__RtlUserThreadStart()// 原型简化void RtlUserThreadStart(PVOID StartAddress, // 线程要执行的函数地址通常是 BaseThreadInitThunkPVOID Parameter // 传递给线程函数的参数);① 初始化 TEB (Thread Environment Block)② 设置 SEH (结构化异常处理) 链③ 初始化浮点/向量寄存器状态④ 调用线程入口函数 (BaseThreadInitThunk)起始返回后调用__RtlExitUserThread终止线程BaseThreadInitThunk参考ReactOSVOID NTAPI BaseThreadInitThunk(BOOL InitialThread,PVOID StartAddress,PVOID Parameter){// 1. 通知 DLL 新线程创建LdrInitializeThunk(InitialThread, NULL, NULL);// 2. 调用实际的线程入口__try {((VOID (WINAPI *)(PVOID))StartAddress)(Parameter);}__except(UnhandledExceptionFilter(GetExceptionInformation())) {// 3. 异常处理ExitProcess(GetExceptionCode());}// 4. 线程退出ExitThread(STATUS_SUCCESS);}用户线程最初始入口设置初始环境结构化寻常帧调用win32线程mainCRTStartup// 实际 CRT 启动代码简化呈现void mainCRTStartup(){// ① 初始化 CRT 的全局状态_set_app_type(_crt_console_app);// ② 设置浮点环境_fpreset();// ③ 调用主初始化含异常保护__scrt_common_main_seh();// ④ 正常情况下不会执行到这里}具体分析就好这里主要功能就是控制台程序的连接器入口点操作系统加载exe不直接调用main会调用本函数。作为薄壳交给__scrt_common_main处理所有初始化。如果是gui程序就调用winmainCRTStartup但是再底层同样会触发执行__scrt_common_main。__scrt_common_main通用crt堆、环境变量、安全、cookie、浮点单元调用__scrt_common_main_seh去执行受保护的程序的后续流程cookie是栈保护就是canary__scrt_common_main_sehshe结构化异常保护边界结构__try{//调用全局/静态对象的构造函数调用invoke_main正常退出exit(result)}__except{//异常终止显示错误的对话框、生成转储等内部操作}调用invoke_main异常处理的最后的防线invoke_main给main的参数envpagrcagrv传参调用main封装