0x00
对windows比较熟悉的同学应该都知道SEH这个概念,我们可以通过SEH来来捕获异常,之后决定怎么处理。
具体的内容可以查看:https://bbs.pediy.com/thread-173853.htm
在上面的文章中,少讲了VCH。
我们根据异常的分发流程,在没有挂上调试器的情况下,异常会先被路由到veh,之后进入seh。那么就存在一个很严重的问题,seh是针对特定线程的特定函数的异常处理块。他会有很多特异性的处理操作;而veh是针对进程全局的异常处理块。如果先进入veh再进入seh就会无法针对特定代码的特定处理。
而且veh还会捕获OutputDebugString产生的异常,导致OutputDebugString无法输出打印信息。
所以在实际工作中,veh的使用并不多。一般都是通过 seh和TopLevelEH来处理异常。
但是在某些情况下(下面会说到),SEH和TopLevelEH都无法捕获到异常,只能通过VEH来捕获,而我们又不想在大部分情况下的SEH失效。这种情况我们需要使用到VCH。
VCH的注册于VEH类似,调用AddVectoredContinueHandler即可。它也是向量化异常处理的一部分,只是他在SEH之后调用。它可以完美解决VEH存在的问题。
0x01
现在我们说说SEH和TopLevelEH无法捕获异常的情况。
最近同事在测试64位程序时,发现某些异常无法捕获。我定位了下,发现只有处于手写的汇编代码中才有这样的问题。经过试验,增加vch后能正常捕获到异常。
众所周知,windows上32位程序的栈回溯依靠ebp及pdb文件。当调用链不存在FPO时,通过ebp即可以遍历所有的堆栈,否则需要依靠pdb中存储的FPO信息来完成完整的堆栈回溯。
而x64环境中,rbp作为普通的非易失寄存器,已经不具备栈帧寄存器的作用,那么64位的堆栈回溯如何实现呢?
其实我们思考一下就能知道,只能通过rsp来回溯整个堆栈。一个典型的函数调用堆栈的数据分布(从高到底)为:调用参数,返回地址,局部变量地址。如果我们能知道局部变