在Windows上的SEH,调用堆栈回溯消失了

我正在阅读这篇关于Windows上的SEH的文章 。 这里是myseh.cpp的源代码

debugging了myseh.cpp。 我在printf("Hello from an exception handler\n");处设置了2个断点printf("Hello from an exception handler\n"); 在行:24和DWORD handler = (DWORD)_except_handler; 在线:36分别。

然后,我跑了,它在线:36。 我看到堆栈跟踪如下。

在这里输入图像说明 随着去,由于mov [eax], 1发生了AccessViolationException mov [eax], 1然后它在线:24打破。 我看到堆栈跟踪如下。 在这里输入图像说明

同样的线程,但main框架已经消失了! 而不是_except_handle 。 ESP从0018f6c8跳到0018f6c8 ,经过Exception处理, 0018f6c80018ef34之间差距很大。

我知道_except_handle必须在用户模式而不是内核模式下运行。 在返回_except_handle之后,线程转到ring0,然后windows内核修改CONTEXT EAX&scratch &然后返回到ring3。 因此,线程不断运行。

我很好奇窗口处理exception的机制:为什么调用main不见了?

为什么ESP从0018f6c8跳到0018ef34 ?(我的意思是一个很大的音高),那些ESP地址属于同一个线程的堆栈? 内核在ring3上玩ESP的一些技巧? 如果是这样,为什么select0018ef34的地址作为处理程序callback的框架? 非常感谢!

您正在使用默认的调试器设置,不足以查看所有细节。 他们被选中来帮助您专注于您自己的代码,并尽快启动调试会话。

[External Code]块会告诉你堆栈框架的某些部分不属于你写的代码。 他们不,他们属于操作系统。 使用工具>选项>调试>常规,并取消“启用只是我的代码”选项。

[下面的框架可能不正确…]警告告诉您,调试器没有准确的PDB来正确地走栈。 使用工具>选项>调试>符号,然后勾选“Microsoft Symbol servers”选项并选择一个缓存位置。 调试器现在将通过操作系统DLL下载您需要调试的PDB。 可能需要一段时间,它只做一次。

你可以推断出大的ESP变化,CONTEXT结构相当大,占用堆栈空间。

这些变化之后,你现在应该看到类似的东西:

 ConsoleApplication1942.exe!_except_handler(_EXCEPTION_RECORD * ExceptionRecord, void * EstablisherFrame, _CONTEXT * ContextRecord, void * DispatcherContext) Line 22 C++ ntdll.dll!ExecuteHandler2@20() Unknown ntdll.dll!ExecuteHandler@20() Unknown ntdll.dll!_KiUserExceptionDispatcher@8() Unknown ConsoleApplication1942.exe!main() Line 46 C++ ConsoleApplication1942.exe!invoke_main() Line 64 C++ ConsoleApplication1942.exe!__scrt_common_main_seh() Line 255 C++ ConsoleApplication1942.exe!__scrt_common_main() Line 300 C++ ConsoleApplication1942.exe!mainCRTStartup() Line 17 C++ kernel32.dll!@BaseThreadInitThunk@12() Unknown ntdll.dll!__RtlUserThreadStart() Unknown ntdll.dll!__RtlUserThreadStart@8() Unknown 

记录在Win10版本1607和VS2015更新2.这不是正确的方式来编写SEH处理程序,在这篇文章中找到一个更好的例子。