不幸的是,MSDN 和 Windows API 文档在这里真的很稀缺,除了 MSDN 中的最小描述之外,我很难找到任何其他内容。
事实证明,向量继续处理程序维护在一个链表中,与用于向量异常处理程序的列表非常相似。它们非常相似,以至于函数的原型实际上是相同的。
看一眼:
PVOID WINAPI AddVectoredExceptionHandler(
_In_ ULONG FirstHandler,
_In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
相比:
PVOID WINAPI AddVectoredContinueHandler(
_In_ ULONG FirstHandler,
_In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
幸运的是,向量异常处理程序更常用并有记录。例如,MSDN 有一个关于 VEH的页面,包含以下段落:
向量异常处理程序是结构化异常处理的扩展。应用程序可以注册一个函数来监视或处理应用程序的所有异常。向量处理程序不是基于帧的,因此,您可以添加一个处理程序,无论您在调用帧中的哪个位置,该处理程序都会被调用。在调试器获得第一次机会通知之后,但在系统开始展开堆栈之前,向量处理程序按照它们的添加顺序被调用。
同一页面只有对添加和删除 VCH API 的简洁引用。
经过对 ntdll 的一些研究和逆向工程,我意识到 VCH 和 VEH 在实现上非常相似。例如,查看AddVectoredExceptionHandler
和AddVectoredContinueHandler
是如何相同的,除了VectoredListIndex
,指定VectorHandlerList
在 VCH 的情况下它们应该添加到第二个:

类似地,除了向量处理程序列表索引外,RemoveVectoredExceptionHandler
和RemoveVectoredContinueHandler
是相同的。
在 内部RtlpAddVectoredHandler
,VectoredListIndex
用作 中的索引 _LdrpVectorHandlerList
,这是一个链表结构的大小为 2 的数组。
在下图中我们可以看到如何VectoredListIndex
乘以列表锚点对象的大小,然后添加到_LdrpVectorHandlerList
,即数组的基偏移量。

现在我们进入了有趣的部分——VEH 和 VCH 有什么不同?
如果我们走上对 的交叉引用_LdrpVectorHandlerList
,我们会注意到导致添加/删除功能的两个流程实际上是相同的。除了这四个 API 之外,我们只剩下一个RtlpCallVectoredHandlers
未记录的函数。
从名字RtlpCallVectoredHandlers
上看就很明显了,但是遍历向量(根据索引选择向量)并按顺序调用所有处理程序。一旦 Vectored Handler 返回EXCEPTION_CONTINUE_EXECUTION
,迭代就会因提前返回RtlpCallVectoredHandlers
而中断并恢复执行。
唯一的函数调用RtlpCallVectoredHandlers
是RtlDispatchException
,它是调度异常处理程序的主要函数。
首先,它执行所有异常处理程序,从第一个向量异常处理程序开始到最后一个,然后通过所有结构化异常处理程序将它们通过堆栈展开。要返回的第一个异常处理程序EXCEPTION_CONTINUE_EXECUTION
(无论是 VEH 还是 SEH 类型)将停止整个异常处理程序的执行过程。
与 VEH 一样,当 VCH 被调用时,它们会被一一调用,直到其中一个返回EXCEPTION_CONTINUE_EXECUTION
(就像调用 VEH 时一样),这会RtlpCallVectoredHandlers
向Vectored break
Handlers 调用循环发出信号。这很有趣,因为这意味着首先安装 Vectored Continue Handler 可以让您隐藏后续 VCH 的异常。
向量继续处理程序在以下情况下被调用:
- 如果异常处理程序(VEH 或 SEH)被调用并返回
EXCEPTION_CONTINUE_EXECUTION
- 如果由于某种原因 SEH 验证失败(参见 SafeSEH 和相关机制),也会调用 VCH,但之后不会继续执行。这可以在导致第二次
RtlpCallVectoredHandlers
调用的许多流中看到,在将其移动到并返回之前,没有设置bl
to1
并将其保持为零。调用函数,然后将调用,如果返回值的是。
al
false
KiUserExceptionDispatcher
ZwRaiseException
KiUserExceptionDispatcher
false
