SEH分析笔记(X64篇
参考:
https://bbs.pediy.com/thread-142371.htm
SEH分析笔记(X64篇)
v1.0.0
boxcounter
历史:
v1.0.0, 2011-11-4:最初版本。
[不介意转载,但请注明出处 www.boxcounter.com
附件里有本文的原始稿,一样的内容,更好的高亮和排版。
本文的部分代码可能会因为论坛的自动换行变得很乱,需要的朋友手动复制到自己的代码编辑器就可以正常显示了]
在之前的《SEH分析笔记(X86篇)》中,我借助 wrk1.2 介绍了 x86 下 windows 系统内核中的 SEH 实现。这次我们来看看 x64 位 windows 系统内核中 SEH 的实现。
本文需要大家熟悉 x64 位系统的一些特性,比如调用约定、Prolog 和 Epilog。可以通过这几篇文章熟悉一下:
Overview of x64 Calling Conventions, MSDN
The history of calling conventions, part 5: amd64 , The Old New Thing
Everything You Need To Know To Start Programming 64-Bit Windows Systems, Matt Pietrek
首先回顾一下前一篇文章。
在 x86 windows 中,函数通过以下几个步骤来参与 SEH :
1. 在自身的栈空间中分配并初始化一个 EXCEPTION_REGISTRATION(_RECORD) 结构体。
2. 将该 EXCEPTION_REGISTRATION(_RECORD) 挂入当前线程的异常链表。
当某函数触发异常时,系统首先会通过调用 KiDispatchException 来给内核调试器一个机会,如果内核调试器没有处理该异常,则该机会被转给 RtlDispatchException,这个函数就开始分发该异常。分发过程为:
从当前线程的异常链表头开始遍历,对于每一个 SEH 注册信息(即 EXCEPTION_REGISTRATION(_RECORD)),调用其 Handler。根据 Handler 的返回值做相应的后续处理:
1. 返回 ExceptionContinueExecution,表示 Handler 已经修复了异常触发点,从异常触发点继续执行。
2. 返回 ExceptionContinueSearch,表示该 Handler 没有处理该异常,继续遍历异常链表。
3. Handler 没有修复异常触发点,但是却能处理该异常(某个 __except 过滤代码返回 EXCEPTION_EXECUTE_HANDLER)。这种情况下,处理完该异常后就从异常解决代码(__except 代码块)继续执行,Handler 不会返回。
以上是简略的 x86 SEH 流程,其中省略了很多细节,比如展开、错误处理、ExceptionNestedException 和 ExceptionCollidedUnwind 等等。
之所以在这里重温这个流程,是因为 x64 中 SEH 的流程总体思路也是如此,只是细节上做了一些修改。但这并不表示熟悉 x86 SEH 就能很轻松的掌握 x64 SEH。
本文分为四个部分:“异常注册”、“异常分发”、“展开、解决”和“ExceptionNestedException 和 ExceptionCollidedUnwind”。依然以 MSC 的增强版为分析对象。分析环境为:WDK 7600.16385.1,内置的 cl 的版本是15.00.30729.207,link 的版本是9.00.30729.207,测试虚拟机系统为 amd64 WinXP + wrk1.2。
在讲述之前,需要先定义几个名词,以简化后续的讲述。
RVA —— 熟悉 PE 格式的朋友都懂的,表示某个绝对地址相对于所在模块的基地址的偏移。
EXCEPT_POINT —— 异常触发点。
EXCEPT_FILTER —— __except 小括号内的异常过滤代码。
EXCEPT_HANDLER —— __except 大括号内的异常解决代码。
FINALLY_HANDLER —— __finally 大括号内的代码。
以下面的伪码为例,
EXCEPT_POINT 指的是行5中的代码。
EXCEPT_FILTER 指的是行7中的“(STATUS_INVALID_PARAMETER == GetExceptionCode()) ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER”。
EXCEPT_HANDLER 指的是行8到行10中所有的代码。
FINALLY_HANDLER 指的是行13到行15中所有的代码。
一、异常注册
在 x64 windows 中,异常注册信息发生了巨大的改变。x86 中异常注册信息是在函数执行过程中在栈中分配并初始化的。x64 中变成这样:
异常注册信息不再是动态创建,而是编译过程中生成,链接时写入 PE+ 头中的 ExceptionDirectory(参考 winnt.h 中 IMAGE_RUNTIME_FUNCTION_ENTRY 的定义)。ExceptionDirectory 里包含几乎所有函数的栈操作、异常处理等信息。
来看看新异常注册信息的数据结构:
x64 中,MSC 为几乎所有的函数都登记了完备的信息,用来在展开过程中完整的回滚函数所做的栈、寄存器操作。登记的信息包括:
函数是否使用了 SEH、
函数使用的是什么组合的 SEH(__try/__except?__try/__finally?)、
函数申请了多少栈空间、
函数保存了哪些寄存器、
函数是否建立了栈帧,
等等,
同时也记录了这些操作的顺序(以保证回滚的时候不会乱套)。
这些信息就存储在 UNWIND_INFO 之中。
UNWIND_INFO 相当于 x86 下的 EXCEPTION_REGISTRATION。它的成员分别是:
Version —— 结构体的版本。
Flags —— 标志位,可以有这么几种取值:
UNW_FLAG_NHANDLER (0x0): 表示既没有 EXCEPT_FILTER 也没有 EXCEPT_HANDLER。
UNW_FLAG_EHANDLER (0x1): 表示该函数有 EXCEPT_FILTER & EXCEPT_HANDLER。
UNW_FLAG_UHANDLER (0x2): 表示该函数有 FINALLY_HANDLER。
UNW_FLAG_CHAININFO (0x4): 表示该函数有多个 UNWIND_INFO,它们串接在一起(所谓的 chain)。
SizeOfProlog —— 表示该函数的 Prolog 指令的大小,单位是 byte。
CountOfCodes —— 表示当前 UNWIND_INFO 包含多少个 UNWIND_CODE 结构。
FrameRegister —— 如果函数建立了栈帧,它表示栈帧的索引(相对于 CONTEXT::RAX 的偏移,详情参考 RtlVirtualUnwind 源码)。否则该成员的值为0。
FrameOffset —— 表示 FrameRegister 距离函数最初栈顶(刚进入函数,还没有执行任何指令时的栈顶)的偏移,单位也是 byte。
UnwindCode —— 是一个 UNWIND_CODE 类型的数组。元素数量由 CountOfCodes 决定。
需要说明几点:
1. 如果 Flags 设置了 UNW_FLAG_EHANDLER 或 UNW_FLAG_UHANDLER,那么在最后一个 UNWIND_CODE 之后存放着 ExceptionHandler(相当于 x86 EXCEPTION_REGISTRATION::handler)和 ExceptionData(相当于 x86 EXCEPTION_REGISTRATION::scopetable)。
2. UnwindCode 数组详细记录了函数修改栈、保存非易失性寄存器的指令。
3. MSDN 中有 UNWIND_INFO 和 UNWIND_CODE 的详细说明,推荐阅读。
那 UNWIND_INFO 是如何与其描述的函数关联起来的呢?答案是:通过一个 RUNTIME_FUNCTION 结构体。
RUNTIME_FUNCTION::BeginAddress 同 RUNTIME_FUNCTION::EndAddress 一起以 RVA 形式描述了函数的范围。
RUNTIME_FUNCTION::UnwindData 就是 UNWIND_INFO 了,它也是一个 RVA 值。
PE+ 中的 ExceptionDirectory 中存放着所有函数的 RUNTIME_FUNCTION,按 RUNTIME_FUNCTION::BeginAddress 升序排列。一旦触发异常,系统可以通过 EXCEPT_POINT 的 RVA 在 ExceptionDirectory 中二分查找到 RUNTIME_FUNCTION,进而找到 UNWIND_INFO。
前面有提到,MSC 为几乎所有的函数都登记了完毕的信息,那是不是有一些特殊函数没有登记信息呢?
是的。x64 新增了一个概念,叫做“叶函数”。熟悉数据结构的朋友可能第一时间就联想到“叶节点”。没错,“叶函数”的含义跟“叶节点”很类似,叶函数不会有子函数,也就是说它不会再调用任何函数。另外 x64 对这个概念额外加了一些要求:不修改栈指针(比如分配栈空间)、没有使用 SEH。总结下来就是:既不调用函数、又没有修改栈指针,也没有使用 SEH 的函数就叫做“叶函数”。
叶函数可以没有登记信息,原因很简单,它根本就没信息需要登记~
还有一个 SCOPE_TABLE 结构,熟悉 x86 SEH 的朋友应该很眼熟 :-),它等同于 x86 SEH 中的 REGISTRATIOIN_RECORD::scopetable 的类型。其成员有:
Count —— 表示 ScopeRecord 数组的大小。
ScopeRecord —— 等同于 x86 中的 scopetable_entry 成员。其中,
BeginAddress 和 EndAddress 表示某个 __try 保护域的范围。
HandlerAddress 和 JumpTarget 表示 EXCEPTION_FILTER、EXCEPT_HANDLER 和 FINALLY_HANDLER。具体对应情况为:
对于 __try/__except 组合,HandlerAddress 代表 EXCEPT_FILTER,JumpTarget 代表 EXCEPT_HANDLER。
对于 __try/__finally 组合,HandlerAddress 代表 FINALLY_HANDLER,JumpTarget 等于 0。
这四个域通常都是 RVA,但当 EXCEPT_FILTER 简单地返回或等于 EXCEPTION_EXECUTE_HANDLER 时,HandlerAddress 可能直接等于 EXCEPTION_EXECUTE_HANDLER,而不再是一个 RVA。
我们可以通过 windbg 中的 .fnent 命令来查看某个函数的异常注册信息。比如,
1 kd> .fnent passThrough!SehTest
2 Debugger function entry 00000000`00778210 for:
3 d:\workspace\code\mycode\r0\passthrough\passthrough.c(51)
4 (fffffadf`f140f020) PassThrough!SehTest | (fffffadf`f140f0c0) PassThrough!Caller2
5 Exact matches:
6 PassThrough!SehTest (void)
7
8 BeginAddress = 00000000`00001020
9 EndAddress = 00000000`000010b2
10 UnwindInfoAddress = 00000000`00002668
11
12 Unwind info at fffffadf`f1410668, 10 bytes
13 version 1, flags 1, prolog 4, codes 1
14 handler routine: PassThrough!_C_specific_handler (fffffadf`f140f4ce), data 3
15 00: offs 4, unwind op 2, op info 4 UWOP_ALLOC_SMALL.
行8到行10描述的是 RUNTIME_FUNCTION。
行12到行15描述的是 UNWIND_INFO。
对于叶函数,输出是这样的,
kd> .fnent passthrough!LeafTest
No function entry for fffffadf`f240c080
到这里,异常注册就讲完了,我们认识了相关的数据结构和定位方法。下面我们进入异常分发流程。
二、异常分发
x64 异常分发过程使用的仍然是 KiDispatchException、RtlDispatchException、RtlpExecuteHandlerForException 等函数。
其中,KiDispatchException 中有关内核异常部分的代码完全没有变化,这里我偷懒直接拷贝《SEH分析笔记(X86篇)》中的部分描述,
原型:
对于内核异常,它的处理步骤如下:
如果 FirstChance 为 TRUE,那么,
1. 首先将该异常传达给内核调试器(KD),如果 KD 处理了该异常,那么函数返回。
2. KD 没有处理,调用 RtlDispatchException 进行异常分发。如果分发成功,RtlDispatchExcetpion 返回 TRUE,或者根本不返回。
3. RtlDispatchException 分发失败,那么再给 KD 一次处理机会,如果还是没有处理,那么 BUGCHECK。
如果 FirstChance 为 FALSE,那么将该异常传达给 KD,如果 KD 没有处理,那么 BUGCHECK。
它的源码实现位于 $WRK-v1.2\base\ntos\ke\amd64\exceptn.c:430。
RtlDispatchException 发生了一些改变。
从之前描述的异常注册信息的数据结构可以发现,x64 中已经不存在异常注册链这个概念了(虽然 _NT_TIB 结构体中还保留了 ExceptionList 域)。那 x64 中 RtlDispatchException 是如何遍历异常注册信息的呢?前面虽然有提到如何通过 EXCEPT_POINT 找到 UNWIND_INFO 结构,但是假如这个 UNWIND_INFO 没有处理该异常,如何继续遍历呢?
在解答这个问题之前,我们先来认识一个新函数和相关的数据结构,
RtlLookupFunctionEntry 的功能是查找指定地址所在函数的 RUNTIME_FUNCTION 和所在模块的基地址。它的参数分为为,
ControlPc —— 需要查找的指令地址,
ImageBase —— 返回的模块基地址,
HistoryTable —— 用于加速查找。
工作流程:
RtlLookupFunctionEntry 在搜索的过程会根据是否传入 HistoryTable 而采取不同的搜索方法:
如果传入 HistoryTable,则根据 HistoryTable->Search 表示的搜索方式在表中进行搜索:
如果搜索方式为 UNWIND_HISTORY_TABLE_NONE,那么不在 HistoryTable 中进行搜索。
如果搜索方式为 UNWIND_HISTORY_TABLE_GLOBAL,则首先在全局表 RtlpUnwindHistoryTable 开始搜索,如果搜索到,则结束搜索,函数返回。否则再在 HistoryTable 中搜索。
如果搜索方式为 UNWIND_HISTORY_TABLE_LOCAL,那么在 HistoryTable 中搜索。
如果上述过程中没有搜索到需要的结果,那么找到模块基地址,从模块的 PE+ 头结构中解析出 RUNTIME_FUNCTION。如果搜索方式为 UNWIND_HISTORY_TABLE_NONE,还会将解决加入到 HistoryTable。
之前的描述中 RtlDispatchException 定位 EXCEPT_POINT 所对应的 RUNTIME_FUNCTION 就是通过调用 RtlLookupFunctionEntry 实现的。
回到刚才的问题,如何推动遍历呢?为了解决这个问题,x64 又引进了一个新函数。现在我们有请 x64 SEH 核心成员 RtlVirtualUnwind 登场~
先来看看它的原型:
它的主要功能是:
根据传入的 ControlPc 和 ContextRecord 等参数虚拟(模拟)展开该函数,并返回该函数的一些信息,比如 HandlerData(SCOPE_TABLE)、EstablisherFrame(rsp 或 栈帧)。
流程是:
1. 通过 FunctionEntry 和 ImageBase 找到 UNWIND_INFO。根据 UNWIND_INFO 中记录的信息,查找 EstablisherFrame(即栈帧或者 rsp)。
2. 根据 ControlPc 分如下两种情况展开:
a. ControlPc >= EpilogOffset,即 ControlPc 在 Epilog 之中。那么把剩余的 Epilog 指令模拟执行完毕即可。
所谓模拟是指,如果下一条 EpiLog 指令是“sub rsp, 0x32”,那么将 ContextRecord->rsp 减去0x32。并不是真正执行 sub 指令。
b. ControlPc < EpilogOffset,那么把 Prolog 反向模拟回滚一遍即可。
所谓反向回滚是指,如果 Prolog 的指令是
mov [RSP + 8], RCX
push R15
push R14
push R13
那么反向回滚就是
pop ContextRecord->R13 (实际上是从 ContextRecord->Rsp 指向的内存中取出值存入 ContextRecord->R13,然后 ContextRecord->Rsp 加上8。并不是真正执行 pop)
pop ContextRecord->R14
pop ContextRecord->R15
mov ContextRecord->RCX, [ContextRecord->RSP+8]
然后把 ContextRecord->Rip 修改为 ControlPc 所在函数的返回地址,即父函数中的某一处 call 的下一条指令。
这样,ContextRecord 就被恢复成父函数在调用 ControlPc 所在函数之后的状态了。
3. 如果 HandlerType 包含 UNW_FLAG_EHANDLER 或 UNW_FLAG_UHANDLER,那么将 UNWIND_INFO::ExceptionData 赋给传出参数 HandlerData,并返回 UNWIND_INFO::ExceptionRoutine。
对于 MSC 编译器生成的模块,UNWIND_INFO::ExceptionRoutine 一般指向 nt!__C_specific_handler。UNWIND_INFO::ExceptionData 指向 ControlPc 所在函数的 SCOPE_TABLE。
RtlVirtualUnwind 的实现源码位于 $WRK-v1.2\base\ntos\rtl\amd64\exdsptch.c:1202。
RtlVirtualUnwind 返回后,RtlDispatchException 就可以根据 ContextRecord->Rip 找到父函数对应的 RUNTIME_FUNCTION,进而找到 UNWIND_INFO。就这样推动整个遍历过程。
这是一般情况,对于没有 UNWIND_INFO 的叶函数呢?
对于叶函数,RtlLookupFunctionEntry 返回 NULL,于是 RtlDispatchException 知道这是个叶函数,就找到该叶函数的父函数,从父函数继续遍历。也就是完全无视叶函数,因为叶函数对整个异常处理过程没有任何影响。
RtlDispatchException 调用 UNWIND_INFO::ExceptionHandler 依然是通过 RtlpExecuteHandlerForException,其函数原型没有变化:
该函数的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:84。
RtlpExecuteHandlerForException 的逻辑较 x86 版本没什么大变化,内部注册了一个异常处理函数 RtlpExceptionHandler。RtlpExceptionHandler 相当于 x86 中的 nt!ExecuteHandler2,其内部会返回 ExceptionNestedException 或 ExceptionContinueSearch。它的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:26。
需要一提的是,最后一个参数 DispatchContext 的类型是 DISPATCHER_CONTEXT,相对于 x86 版本,它扩充了很多,
成员分别为:
ControlPc —— 异常触发点。
ImagePase —— ControlPc 所在模块的基地址。
FunctionEntry —— ControlPc 所在函数的 RUNTIME_FUNCTION。
EstablisherFrame —— ControlPc 所在函数的栈帧(如果建立了栈帧)或 RSP。
TargetIp —— 解决异常的 EXCEPT_HANDLER 地址,该成员只在展开的过程中被使用。RtlpExecuteHandlerForException 没有使用它。
ContextRecord —— 供展开过程中使用,只有当展开过程中触发新异常(返回 ExceptionCollidedUnwind)时,才会被 RtlDispatchException 真正的使用到(参考 RtlDispatchException 处理 ExceptionCollidedUnwind 的代码)。
LanguageHandler —— ControlPc 所在函数的 UNWIND_INFO::ExceptionRoutine。
HandlerData —— ControlPc 所在函数的 UNWIND_INFO::ExceptionData。
ScopeIndex —— UNWIND_INFO::ExceptionData 中 SCOPE_TABLE::ScopeRecord 的索引,通常设置为0(注:请不要与 x86 中运行时不断改变的 EXCEPTION_REGISTRATION::trylevel 相混淆,ScopeIndex 不会在在函数执行过程中改变)
Fill0 —— 未用。
再看一下它的 .fnent 输出,
1 kd> .fnent nt!RtlpExecuteHandlerForException
2 Debugger function entry 00000000`01458210 for:
3 (fffff800`008bd950) nt!RtlpExecuteHandlerForException | (fffff800`008bd970) nt!RtlpUnwindHandler
4 Exact matches:
5 nt!RtlpExecuteHandlerForException (void)
6
7 BeginAddress = 00000000`000bd950
8 EndAddress = 00000000`000bd963
9 UnwindInfoAddress = 00000000`000dfeb8
10
11 Unwind info at fffff800`008dfeb8, 10 bytes
12 version 1, flags 3, prolog 4, codes 1
13 handler routine: nt!RtlpExceptionHandler (fffff800`008bd920), data 0
14 00: offs 4, unwind op 2, op info 4 UWOP_ALLOC_SMALL.
行12中显示 flags 等于3,即 UNW_FLAG_EHANDLER (0x1) | UNW_FLAG_UHANDLER (0x2),说明行13中显示的异常处理函数 nt!RtlpExceptionHandler 既负责解决异常,也负责展开。
RtlpExecuteHandlerForException 会调用 DISPATCHER_CONTEXT::LanguageHandler。对于 MSC 编译得到的模块,它是 nt!__C_specific_handler,我们来看看这个函数,
原型:
反汇编码:
nt!__C_specific_handler 相当于 x86 中的 nt!_except_handler3。从上面的反汇编代码也可以看出它的逻辑跟 nt!_except_handler3 基本上一致。
函数代码不长。主要分为两个大分支,一个分支处理异常,一个分支处理展开(我用横线分隔开了)。
异常解决的代码负责遍历 SCOPE_TABLE,依次调用 SCOPE_TABLE::ScopeRecord.HandlerAddress 代表的 EXCEPT_FILTER,并针对返回值做出相应的处理:
1. 返回 EXCEPTION_CONTINUE_EXECUTION,说明异常已经被 EXCEPT_FILTER 修复。返回 ExceptionContinueExecution。
2. 返回 EXCEPTION_CONTINUE_SEARCH,继续遍历下一个 ScopeRecord。
3. 返回 EXCEPTION_EXECUTE_HANDLER,说明当前 ScopeRecord.JumpTarget 代表的 EXCEPT_HANDLER 可以处理该异常。那么调用 RtlUnwindEx 进行展开。
熟悉 x86 的朋友可能会疑惑:在 x86 中 nt!_except_handler3 先进行全局展开,然后对本函数自身进行不完全的局部展开,最后执行 EXCEPT_HANDLER。而在 nt!__C_specific_handler 中却找不到执行 EXCEPT_HANDLER 的指令,这是怎么回事?
实际上,x64 对这个流程做了一些调整,EXCEPT_HANDLER 不是由 nt!__C_specific_handler 直接调用,而是作为参数传给 RtlUnwindEx,RtlUnwindEx 处理完展开之后才执行 EXCEPT_HANDLER。后续我们在讲展开的时候会看到具体的方法。
__C_specific_handler 的展开分支,是对 SCOPE_TABLE 进行展开,逻辑很简单,不多讲了。
更详细的信息,请参考上面反汇编代码中我附的注释。
另外还需要说一下 SCOPE_TABLE。
在 x86 中,遍历 scopetable 时是通过运行时动态改变的 EXCEPTION_REGISTRATION::trylevel 来确定应该首先遍历哪一个 scopetable_entry。而 x64 中没有等同于 trylevel 的数据,有的朋友可能会说“SCOPE_TABLE 中不是有每个 __try 保护域的范围 RVA 吗?通过范围不就可以确定在哪个 __try 中触发了异常吗?”。
我们可以先试试这种方法,以下面这段伪码为例,
上述伪码中总共有4个 __try,按照 x86 中的方法,SCOPE_TABLE 的内容应该是顺序排列的,像这样:
SCOPE_TABLE::Count 等于4,
SCOPE_TABLE::ScopeRecord[0] 表示行3开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[1] 表示行10开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[2] 表示行12开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[3] 表示行24开始的 __try/__finally。
假设行14处触发了异常,遍历过程应该是这样,
首先检查 ScopeRecord[0],发现其范围不包含 EXCEPT_POINT,继续下一个,
开始检查 ScopeRecord[1],范围匹配了。
那是不是该把异常交给 ScopeRecord[1] 处理呢?
不是!从伪码中可以很明显的看出,行14触发的异常应该首先由行12开始的 __try/__except,即 ScopeRecord[1] 处理。
可见这种方法是行不通的。
MSC 通过调整 SCOPE_TABLE::ScopeRecord 的排列顺序来解决这个问题:
SCOPE_TABLE::Count 等于4,
SCOPE_TABLE::ScopeRecord[0] 表示行3开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[1] 表示行12开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[2] 表示行10开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[3] 表示行24开始的 __try/__finally。
即对于嵌套的 __try/__except/__finally,ScopeRecord 的排列顺序是,最内层的 __try 排在前面,其次是次内层的,依次排到最外层。
这样就能正确的遍历 SCOPE_TABLE 了。
再用伪码完整的展示一下 SCOPE_TABLE 的布置,
SCOPE_TABLE::Count = 4。
SCOPE_TABLE::ScopeRecord[0].BeginAddress = RVA_L4; (行4的 RVA) // 第一个 __try
SCOPE_TABLE::ScopeRecord[0].EndAddress = RVA_L5;
SCOPE_TABLE::ScopeRecord[0].HandlerAddress = RVA_L6_EXCEPT_FILTER; (行6 __except 过滤代码首地址的 RVA)
SCOPE_TABLE::ScopeRecord[0].JumpTarget = RVA_L7;
SCOPE_TABLE::ScopeRecord[1].BeginAddress = RVA_L13; // 第三个 __try
SCOPE_TABLE::ScopeRecord[1].EndAddress = RVA_L15;
SCOPE_TABLE::ScopeRecord[1].HandlerAddress = RVA_L16_EXCEPT_FILTER;
SCOPE_TABLE::ScopeRecord[1].JumpTarget = RVA_L7;
SCOPE_TABLE::ScopeRecord[2].BeginAddress = RVA_L11; // 第二个 __try
SCOPE_TABLE::ScopeRecord[2].EndAddress = RVA_L19;
SCOPE_TABLE::ScopeRecord[2].HandlerAddress = RVA_L20_EXCEPT_FILTER;
SCOPE_TABLE::ScopeRecord[2].JumpTarget = RVA_L21;
SCOPE_TABLE::ScopeRecord[3].BeginAddress = RVA_L25; // 第四个 __try
SCOPE_TABLE::ScopeRecord[3].EndAddress = RVA_L26;
SCOPE_TABLE::ScopeRecord[3].HandlerAddress = RVA_L28;
SCOPE_TABLE::ScopeRecord[3].JumpTarget = 0;
我们再模拟一下 nt!__C_specific_handler 是如何遍历 SCOPE_TABLE 的:
1. 首先通过传入参数中的 pDispatcherContext->ControlPc 和 pDispatcherContext->ImageBase 计算出异常触发点的 RVA(简称 E_RVA)。参见 fffff800`008a430d 处的指令。
2. 通过 pDispatcherContext->ScopeIndex 确认是否需要遍历。如果需要遍历,则从它指定的 ScopeRecord 开始遍历。pDispatcherContext->ScopeIndex 一般都为0,只有返回 ExceptionCollidedUnwind 时,RtlDispatchException 才可能将它设置为其他值。
3. 通过比较 E_RVA 和 ScopeRecord[?].BeginAddress、ScopeRecord[?].EndAddress 来找到正确的处理函数,
首先 ScopeRecord[0] 范围不匹配,遍历下一个,
然后 ScopeRecord[1],发现范围匹配,并且是 __try/__except 组合。于是调用 ScopeRecord[1].HandlerAddress,假设它返回的是 EXCEPTION_CONTINUE_SEARCH,那么继续遍历下一个,
这次是 ScopeRecord[2],发现范围匹配,并且是 __try/__except 组合。于是调用 ScopeRecord[2].HandlerAddress,假设它返回的是 EXCEPTION_EXECUTE_HANDLER,那么说明找到了解决方案。
4. 调用 RtlUnwindEx,把 ScopeRecord[2].JumpTarget 对应的绝对地址作为 TargetIp 参数传给它。RtlUnwindEx 全局展开完毕后执行 TargetIp。
到这里,异常分发就大致讲述完毕。接下来是关于展开和解决的内容。
三、展开、解决
x64 中展开使用的函数有 RtlVirtualUnwind、RtlUnwindEx 和 RtlpExecuteHandlerForUnwind。其中 RtlVirtualUnwind 已经讲了,我们来看看余下的两个。
首先是 RtlUnwindEx,原型如下:
参数分别是:
TargetFrame —— 目标帧,即最后一个需要展开的帧。
TargetIp —— 前面有讲过,它就是 ScopeRecord[?].JumpTarget 代表的地址,即 EXCEPT_HANDLER。
ExceptionRecord —— 异常信息。
ReturnValue —— 传递给 TargetIp 的返回值,分析过程中没发现它有什么用处。
OriginalContext —— 虽然被声明为 IN,但是实际上 RtlUnwindEx 并没有使用它内部的数据,
HistoryTable —— 用于加速查找 RUNTIME_FUNCTION。
主要功能是:
从自身开始展开,到 TargetFrame 停止。然后跳转到 TargetIp 继续执行。
流程:
1. 申请一个类型为 CONTEXT 的局部变量 l_Context,调用 RtlCaptureContext 将当前自身的环境复制到 l_Context。
2. 通过 RtlVirtualUnwind 对 l_Context 进行模拟展开,推动遍历。对每个遍历到的 UNWIND_INFO,检查 UNWIND_INFO::Flags 是否包含 UNW_FLAG_UHANDLER。如果包含,则调用 UNWIND_INFO::ExceptionHandler 进行局部展开。否则继续遍历下一个。
循环本步骤,直到展开到 TargetFrame,即到达解决异常的 EXCEPT_HANDLER 所在的函数(简称为 ExceptionHandlerFunc)了。
3. 这时 l_Context 内已经是从 RtlUnwindEx 完整展开到 EXCEPT_HANDLER 的环境了。即此时 l_Context 已经是 ExceptionHandlerFunc 的执行环境了。
调用 RtlRestoreContext,用 l_Context 替换当前线程的执行环境,于是就跳转到 EXCEPT_HANDLER 继续执行。
这样就完美的从触发异常的环境跳到了新的环境中。
这个过程有点类似这种手法:
1. 将某台机器的系统 ghost 到一个 bak.gho 文件。
2. 把 bak.gho 恢复到一台临时机器,然后对这台临时机器做一些调整。调整完毕后制作一个临时机器的 bak_mod.gho。
3. 将 bak_mod.gho 恢复到原来那台机器。
这个流程很重要,我手绘了一副图帮助理解,
伪码:
图:
1. 异常解决流程,从 EXCEPT_POINT 到 RtlUnwindEx,途中已经找到能够解决该异常的 EXCEPT_HANDLER 了(以参数 TargetIp 表示),当前线程状态为 ThreadContext
+---------------------------------------+
| ...... |
| RtlRaiseStatus |调 |
| RtlDispatchException |用 |-> ThreadContext &
| RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler
| __C_specific_handler |向 |
| RtlUnwindEx v |
| |
+---------------------------------------+
2. RtlUnwindEx 将当前自身状态复制到 ThreadContext_Copy 中
+---------------------------------------+ +---------------------------------------+
| ...... | | ...... |
| RtlRaiseStatus |调 | | RtlRaiseStatus |调 |
| RtlDispatchException |用 |-> ThreadContext & | RtlDispatchException |用 |-> ThreadContext_Copy &
| RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler | RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler
| __C_specific_handler |向 | | __C_specific_handler |向 |
| RtlUnwindEx v | | RtlUnwindEx v |
| | | |
+---------------------------------------+ +---------------------------------------+
3. 用 ThreadContext_Copy 进行展开,一直展开到异常触发点停止。
+---------------------------------------+ +---------------------------------------+
| ..... | | ...... |
| RtlRaiseStatus |调 | | RtlRaiseStatus ^展 |
| RtlDispatchException |用 |-> ThreadContext | RtlDispatchException |开 |-> ThreadContext_Copy &
| RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler | RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler
| __C_specific_handler |向 | | __C_specific_handler |向 |
| RtlUnwindEx v | | RtlUnwindEx | |
| | | |
+---------------------------------------+ +---------------------------------------+
4. 将 ThreadContext_Copy.Rip 设置为 TargetIp,以 ThreadContext_Copy 为参数调用 RtlpRestoreContext。跳转到 TargetIp 继续执行。
+---------------------------------------+
| ...... |
| EXCEPT_HANDLER |-> ThreadContext (ThreadContext.Rip = TargetIp)
| |
+---------------------------------------+
这样就完成了展开和执行 EXCEPT_HANDLER 的工作。
RtlpExecuteHandlerForUnwind 没有什么改变,原型依旧:
它会注册一个异常处理函数 RtlpUnwindHandle,当触发新异常时 RtlpUnwindHandler 会返回 ExceptionCollidedUnwind。关于 ExceptionCollidedUnwind,我们后面还会详细讲述。
RtlpExecuteHandlerForUnwind 的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:199。
RtlpUnwindHandle 的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:136。
到这里,我们讲完了展开的逻辑。接下来我们要讲述两个比较特殊的返回值: ExceptionNestedException 和 ExceptionCollidedUnwind。
四、ExceptionNestedException 和 ExceptionCollidedUnwind
之所以专门讲述这两个返回值,是因为在分析过程中,我感觉常规情况的 SEH 流程理解起来并不困难,难理解的是这两种不一般的情况。它们不一般之处在于:在处理异常的过程中又触发了新的异常。
先来讲一下这两个返回值的含义:
ExceptionNestedException —— 在异常分发过程中触发新的异常,比如执行 EXCEPT_FILTER 时触发异常。
ExceptionCollidedUnwind —— 在展开过程中触发新的异常,比如执行 FINALLY_HANDLER 时触发异常。
首先来讲讲 ExceptionNestedException,以如下伪码为例:
上述代码会两次触发异常,第一次是行5的 ExRaiseStatus,第二次是行7的 ExRaiseStatus。为了方便区分,我将它们分别标记为 EXCEPT_POINT#1、EXCEPT_POINT#2。
我们来看一下这两个异常的处理流程:
1. ExRaiseStatus#1 会创建保存 EXCEPT_POINT#1 触发时的状态 Context#1,并构建一个 EXCEPTION_RECORD,然后将他们作为参数来调用 RtlDispatchException#1。(注:这种方式的的触发点是 ExRaiseStatus 内部,而非 SehTest 的第5行。即Context#1 记录的异常触发点是 ExRaiseStatus#1 内部)
2. RtlDispatchException#1 根据 Context#1 首先找到 EXCEPT_POINT#1 所在函数 ExRaiseStatus#1 的 UNWIND_INFO,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。
3. RtlDispatchException#1 遍历到 SehTest,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_EHANDLER,于是调用其 UNWIND_INFO::ExceptionHandler,即 __C_specific_handler$2。__C_specific_handler$2 遍历 SehTest 的 SCOPE_TABLE,发现唯一的一个 ScopeRecord。于是执行 ScopeRecord[0].HandlerAddress,即行7的 SehTest::EXCEPT_FILTER_1#1。此时的调用栈如下(竖线后的内容为函数的 UNWIND_INFO::Flags 和 UNWIND_INFO::ExceptionHandler,其中 Flags 缩写为 E、U、N):
(1) Caller | E & __C_specific_handler$1
(2) SehTest | E & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$5
(6) __C_specific_handler$2 | N
(7) EXCEPT_FILTER_1#1 | N
4. EXCEPT_FILTER#1 触发 EXCEPT_POINT#2。同步骤1类似,ExRaiseStatus 会调用 RtlDispatchException#2,这个过程中同样会创建保存 EXCEPT_POINT#2 的状态,我们称之为 Context#2。
5. RtlDispatchException#2 根据 Context#2 找到了 EXCEPT_POINT#2 所在函数 ExRaiseStatus#2,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。
6. RtlDispatchException#2 遍历到 EXCEPT_FILTER_1#1,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。(注:EXCEPT_FILTER 虽然代码形式上从属于 SehTest 函数,但实际上它是一个单独的函数,有自己的 UNWIND_INFO,跟 SEH 的 UNWIND_INFO 并不是同一个)
7. RtlDispatchException#2 遍历到 __C_specific_handler$2、RltpExecuteHandlerForException#1、RtlDispatchException#1、ExRaiseStatus#1,这些函数要么被标记为 UNW_FLAG_NHANDLER,要么 UNWIND_INFO::ExceptionHandler 返回 ExcetpionNestedException,结果都是继续遍历,所以不再一一讲述。继续遍历下一个。
8. RtlDispatchException#2 遍历到 SehTest,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_EHANDLER,于是调用其 UNWIND_INFO::ExceptionRoutine,即 __C_specific_handler$2,发现范围匹配,于是调用 EXCEPT_FILTER_1#1,于是又触发异常,这次是 #3 异常。此时的调用栈如下:
(1) Caller | E & __C_specific_handler$1
(2) SehTest | E & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$5
(6) __C_specific_handler$2 | N
(7) EXCEPT_FILTER_1#1 | N
(8) ExRaiseStatus#2 | N
(9) RtlDispatchException#2 | N
(10) RtlpExecuteHandlerForException#2 | EU & RtlpExceptionHandler$10
(11) __C_specific_handler$2 | N
(12) EXCEPT_FILTER_1#2 | N
(13) ExRaiseStatus#3 | N
9. #3 异常的处理流程同 #2 的处理流程类似,也会再遍历到 __C_specific_handler$2,也会再调用 EXCEPT_FILTER_1,于是会触发 #4 异常、#5 异常等等。最终内核栈溢出,BSOD。
以上就是 ExceptionNestedException 的产生以及处理的流程。过程中还有一些细节操作,为了描述简洁,我没有在上述过程中一一讲述。
再来看看 ExceptionCollidedUnwind。它比 ExceptionNestedException 更复杂一些,我们以如下伪码为例,
伪码中也有两处触发异常的地方,第一次在行5,第二次在行9。也分别标记为 EXCEPT_POINT#1 和 EXCEPT_POINT#2。处理流程:
1. ExRaiseStatus#1 创建保存 EXCEPT_POINT#1 的状态 Context#1,并构建一个 EXCEPTION_RECORD,然后将他们作为参数来调用 RtlDispatchException#1。
2. RtlDispatchException#1 根据 Context#1 开始遍历:
首先遍历到 EXCEPT_POINT#1 所在函数 ExRaiseStatus,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是遍历下一个。
然后遍历到 SehTest,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_UHANDLER,于是继续遍历下一个。
然后遍历到 Caller,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_EHANDLER,于是调用其 UNWIND_INFO::ExceptionRoutine 即 __C_specific_handler。__C_specific_handler 发现可以处理该异常,于是以 EXCEPT_HANDLER_2 为 TargetIp 参数调用 RtlUnwindEx。
3. RtlUnwindEx 从自身开始展开,展开到 SehTest,执行 FINALLY_HANDLER_1 时触发新异常。此时调用栈为:
(1) Caller | E & __C_specific_handler$1
(2) SehTest | U & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$5
(6) __C_specific_handler$1 | N
(7) RtlUnwindEx#1 | N
(8) RtlpExecuteHandlerForUnwind#1 | EU & RtlpUnwindHandler$8
(9) __C_specific_handler$2 | N
(10) FINALLY_HANDLER_1 | N
(11) ExRaiseStatus#2 | N
需要说明的是,调用栈(7) RtlUnwindEx 创建并初始化了一个 DISPATCHER_CONTEXT 变量(后续称之为 pDispatcherContextForUnwind),并作为参数传递给调用栈(8) RltpExecuteHandlerForUnwind,后者在调用(9) __C_specific_handler$2 之前将 pDispatcherContextForUnwind 保存在自己的栈中。此时 pDispatcherContextForUnwind 的内容表示的是调用栈(2) SehTest 的情况。后续步骤会用到这个 pDispatcherContextForUnwind。
4. (11) ExRaiseStatus#2 将 EXCEPT_POINT#2 触发时的状态保存到 Context#2,然后调用 RtlDispatchException#2 进行 EXCEPT_POINT#2 的分发。
5. RtlDispatchException#2 根据 Context#2 开始遍历,
首先遍历到 EXCEPT_POINT#2 所在函数 ExRaiseStatus#2,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是遍历下一个。
然后遍历到 FINALLY_HANDLER_1(同前面提到的 EXCEPT_FILTER 一样,FINALLY_HANDLER 实际上也是一个单独的函数,有自己的 RUNTIME_FUNCTION 和 UNWIND_INFO),发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是遍历下一个。
然后遍历到(9) __C_specific_handler$2,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。
然后遍历到(8) RtlpExecuteHandlerForUnwind#1,发现其 UNWIND_INFO::Flags 包含 UNW_FLAG_EHANDLER。于是调用其 UNWIND_INFO::ExceptionRoutine 即 RtlpUnwindHandler$8。RtlpUnwindHandler$8 会取出步骤3中所提到的 pDispatcherContextForUnwind,将其内容拷贝到自己的传出参数(参考 RtlpUnwindHandler 的函数原型)pDispatcherContext 中,然后返回 ExceptionCollidedUnwind。
6. RtlDispatchException#2 收到 ExceptionCollidedUnwind 后,从传回来的 pDispatchContext 中取出诸如 ControlPc、EstablisherFrame 等值(如步骤3所说,此时这些值反应的是(2) SehTest 的状态),用这些值来继续遍历。
首先遍历到(2) SehTest,调用 RtlpExecuteHandlerForException#2,进而调用 __C_specific_handler$2,但是发现 pDispatcherContext->ScopeIndex(步骤(9)中在调用(10) FINALLY_HANDLER_1 之前+1了,参考 __C_specific_handler 反汇编码)等于 pDispatcherContext->HandlerData->Count。于是继续遍历。
然后遍历到(1) Caller,调用 RtlpExecuteHandlerForException#2,进而调用 __C_specific_handler$1,发现它可以处理 #2 异常,于是以 EXCEPT_HANDLER#2 为 TargetIp 参数调用 RtlUnwindEx。此时调用栈如下:
(1) Caller | E & __C_specific_handler$1
(2) SehTest | U & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$6
(6) __C_specific_handler$1 | N
(7) RtlUnwindEx#1 | N
(8) RtlpExecuteHandlerForUnwind#1 | EU & RtlpUnwindHandler$8
(9) __C_specific_handler$2 | N
(10) FINALLY_HANDLER#1 | N
(11) ExRaiseStatus#2 | N
(12) RtlDispatchException#2 | N
(13) RtlpExecuteHandlerForException#2 | EU & RtlpExceptionHandler
(14) __C_specific_handler$1 | N
(15) RtlUnwindEx | N
7. (17) RtlUnwindEx 展开完毕后,通过 RtlRestoreContext 跳转到 EXCEPT_HANDLER#2 继续执行。
在上述过程中,我们可以发现,遍历过程中 RtlDispatchException 等系统函数被频繁遍历到。于是就有了前面提到的全局展开历史表 RtlpUnwindHistoryTable,这个表中存放着 RtlDispatchException、RtlUnwindEx 等函数的 RUNTIME_FUNCTION 和 ImageBase 信息,这样就不用每次都去解析 PE+ 中的 ExceptionDirectory,实现了加速。
到这里,我们就讲完了 x64 SEH 的实现。可以发现,x64 和 x86 的 SEH 思想或者说框架是一样的:
1. RtlDispatchException 和 RtlUnwindEx 都对异常注册信息进行遍历。前者是为了分发异常而遍历,后者是为了展开而遍历。
2. MSC 提供的异常处理函数按照“异常解决”和“展开”两个分支,对 SCOPE_TABLE/scopetable 进行遍历。前者是为了找到 EXCEPT_FILTER & EXCEPT_HANDLER,后者是为了找到 FINALLY_HANDLER。
3. RtlDispatchException 和 RtlUnwindEx 借助 MSC 提供的异常处理函数这个桥梁,配合处理异常。
主要的改变有两点:
1. RtlDispatchException 和 RtlUnwindEx 通过调用 RtlVirtualUnwind 推动遍历。
2. 所有的非叶函数都参与到 SEH,尽管大部分的函数都没有使用到 SEH。
以上我们主要讲述的是 x64 SEH 的内部实现。对于使用者,也有一个好消息,我们来看看,
C 代码:
反汇编码:
我们发现 SehTest 内部完全没有任何 SEH 的踪迹,不像 x86 那样会有创建、销毁 EXCEPTION_REGISTRATION_RECORD 和调整 EXCEPTION_REGISTRATION_RECORD::trylevel 等操作。
这样的好处就是使用者无需再担心性能损耗,可以放心大胆的使用 SEH 机制了。
附录一 boxr 扩展
为了方便自己分析,我写了一个简单的 windbg 扩展,提供了几个 x64 seh 常用功能:
!boxr.unwindinfo module-name unwindinfo_addr
功能:
用于查询指定 UNWIND_INFO 结构的详细信息。
参数说明:
module-name —— 待查询的 UNWIND_INFO 结构对应函数的模块名
unwindinfo_addr —— UNWIND_INFO 结构的绝对地址
!boxr.rtfn option module runtimefunction_addr
功能:
用于查询指定 RUNTIME_FUNCTION 结构的详细信息。(rtfn 表示 RunTime_FunctioN)
参数说明:
option —— 参数选项,目前支持两种:
/a 表示 module 参数为模块基地址
/n 表示 module 参数为模块名称
module —— RUNTIME_FUNCTION 结构对应函数所在的模块,具体形式根据 option 而定。
runtimefunction_addr —— 需要查询的 RUNTIME_FUNCTION 结构体的绝对地址。支持 @rax 操作方式,但不支持复杂的组合,比如 @rax+8。
使用的方法是:用 .extpath+ 命令将 boxr.dll 所在的目录添加到 windbg 的搜索路径中,然后就可以使用了。需要卸载时就 .unload。
简单说明一下这两个命令。
比如我们要查看下面这个函数的 UNWIND_INFO 信息:
操作步骤:
1. 使用 .fnent 命令获得 SehTest 的基本信息,
kd> .fnent passthrough!SehTest
Debugger function entry 00000000`00758210 for:
(fffffadf`f135d080) PassThrough!SehTest | (fffffadf`f135d180) PassThrough!LeafTest
Exact matches:
PassThrough!SehTest (void)
BeginAddress = 00000000`00001080
EndAddress = 00000000`00001175
UnwindInfoAddress = 00000000`000026b8
Unwind info at fffffadf`f135e6b8, 10 bytes
version 1, flags 3, prolog 4, codes 1
handler routine: PassThrough!_C_specific_handler (fffffadf`f135d5de), data 6
00: offs 4, unwind op 2, op info 4 UWOP_ALLOC_SMALL.
2. 使用 !boxr.unwindinfo 查询详细信息,
kd> !boxr.unwindinfo passthrough fffffadf`f135e6b8
_UNWIND_INFO for fffffadff135e6b8
Flags:
EU
ExceptionRoutine:
PassThrough!_C_specific_handler (fffffadf`f135d5de)
ScopeTable:
Count: 6
ScopeRecord[0] (fffffadff135e6c8)
BeginAddress:
PassThrough!SehTest+0x4 (fffffadf`f135d084)
EndAddress:
PassThrough!SehTest+0x1e (fffffadf`f135d09e)
HandlerAddress:
PassThrough!SehTest$filt$0 (fffffadf`f135d8a0)
JumpTarget:
PassThrough!SehTest+0x1e (fffffadf`f135d09e)
[省略中间3个 ScopeRecord 成员]
ScopeRecord[5] (fffffadff135e718)
BeginAddress:
PassThrough!SehTest+0x8b (fffffadf`f135d10b)
EndAddress:
PassThrough!SehTest+0xd7 (fffffadf`f135d157)
HandlerAddress:
PassThrough!SehTest$filt$5 (fffffadf`f135d960)
JumpTarget:
PassThrough!SehTest+0xd7 (fffffadf`f135d157)
!boxr.rtfn 的用法也类似,比如:
kd> !box.rtfn /n passThrough @rax
_RUNTIME_FUNCTION for fffffadff1113000
BeginAddress:
PassThrough!CollidedUnwind (fffffadf`f1110020)
EndAddress:
PassThrough!CollidedUnwind+0x38 (fffffadf`f1110058)
UnwindData:
fffffadff1111688
_UNWIND_INFO for fffffadff1111688
Flags:
U
ExceptionRoutine:
PassThrough!_C_specific_handler (fffffadf`f11104ee)
ScopeTable:
Count: 1
ScopeRecord[0] (fffffadff1111698)
BeginAddress:
PassThrough!CollidedUnwind+0x4 (fffffadf`f1110024)
EndAddress:
PassThrough!CollidedUnwind+0x10 (fffffadf`f1110030)
HandlerAddress:
PassThrough!CollidedUnwind$fin$0 (fffffadf`f1110750)
JumpTarget:
0
需要说明的是,我写这个扩展的目的仅仅是为了分析 x64 SEH 过程中能轻松的查看相关数据结构的详细信息,所以并没有在这个扩展上花很多时间。其代码是从 MS 例子代码的基础上增加了我需要的功能。应该有一些 BUG,但是对我来说不重要,已经满足我的需要了。源码也放在附件里,方便分析的朋友根据自己的需要进行修改。
另外有一个疑问:我编译的 x64 wrk1.2 内核无法对 .c代码进行源码调试,对 .asm 代码倒是可以,这是为什么?我看了一下编译选项,没看出什么猫腻。有经验的朋友分享一下吧,感谢 :-)
附录二 RtlUnwindEx 的反汇编代码和注释
由于无法源码调试,只好把它反汇编出来加上注释……
参考资料
[1] wrk 源码
[2] Improving Automated Analysis of Windows x64 Binaries, skape
[3] Programming against the x64 exception handling support, Skywing
[4] Exceptional Behavior - x64 Structured Exception Handling, The NT Insider
v1.0.0
boxcounter
历史:
v1.0.0, 2011-11-4:最初版本。
[不介意转载,但请注明出处 www.boxcounter.com
附件里有本文的原始稿,一样的内容,更好的高亮和排版。
本文的部分代码可能会因为论坛的自动换行变得很乱,需要的朋友手动复制到自己的代码编辑器就可以正常显示了]
在之前的《SEH分析笔记(X86篇)》中,我借助 wrk1.2 介绍了 x86 下 windows 系统内核中的 SEH 实现。这次我们来看看 x64 位 windows 系统内核中 SEH 的实现。
本文需要大家熟悉 x64 位系统的一些特性,比如调用约定、Prolog 和 Epilog。可以通过这几篇文章熟悉一下:
Overview of x64 Calling Conventions, MSDN
The history of calling conventions, part 5: amd64 , The Old New Thing
Everything You Need To Know To Start Programming 64-Bit Windows Systems, Matt Pietrek
首先回顾一下前一篇文章。
在 x86 windows 中,函数通过以下几个步骤来参与 SEH :
1. 在自身的栈空间中分配并初始化一个 EXCEPTION_REGISTRATION(_RECORD) 结构体。
2. 将该 EXCEPTION_REGISTRATION(_RECORD) 挂入当前线程的异常链表。
当某函数触发异常时,系统首先会通过调用 KiDispatchException 来给内核调试器一个机会,如果内核调试器没有处理该异常,则该机会被转给 RtlDispatchException,这个函数就开始分发该异常。分发过程为:
从当前线程的异常链表头开始遍历,对于每一个 SEH 注册信息(即 EXCEPTION_REGISTRATION(_RECORD)),调用其 Handler。根据 Handler 的返回值做相应的后续处理:
1. 返回 ExceptionContinueExecution,表示 Handler 已经修复了异常触发点,从异常触发点继续执行。
2. 返回 ExceptionContinueSearch,表示该 Handler 没有处理该异常,继续遍历异常链表。
3. Handler 没有修复异常触发点,但是却能处理该异常(某个 __except 过滤代码返回 EXCEPTION_EXECUTE_HANDLER)。这种情况下,处理完该异常后就从异常解决代码(__except 代码块)继续执行,Handler 不会返回。
以上是简略的 x86 SEH 流程,其中省略了很多细节,比如展开、错误处理、ExceptionNestedException 和 ExceptionCollidedUnwind 等等。
之所以在这里重温这个流程,是因为 x64 中 SEH 的流程总体思路也是如此,只是细节上做了一些修改。但这并不表示熟悉 x86 SEH 就能很轻松的掌握 x64 SEH。
本文分为四个部分:“异常注册”、“异常分发”、“展开、解决”和“ExceptionNestedException 和 ExceptionCollidedUnwind”。依然以 MSC 的增强版为分析对象。分析环境为:WDK 7600.16385.1,内置的 cl 的版本是15.00.30729.207,link 的版本是9.00.30729.207,测试虚拟机系统为 amd64 WinXP + wrk1.2。
在讲述之前,需要先定义几个名词,以简化后续的讲述。
RVA —— 熟悉 PE 格式的朋友都懂的,表示某个绝对地址相对于所在模块的基地址的偏移。
EXCEPT_POINT —— 异常触发点。
EXCEPT_FILTER —— __except 小括号内的异常过滤代码。
EXCEPT_HANDLER —— __except 大括号内的异常解决代码。
FINALLY_HANDLER —— __finally 大括号内的代码。
以下面的伪码为例,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[font=Consolas][color= #000000] [/color][color=#800080]1 [/color][color=#000000]__try [ /color ][color= #800080]2 [/color][color=#000080]{ [ /color ][color= #800080]3 [/color][color=#000000]__try [ /color ][color= #800080]4 [/color][color=#000080]{ [ /color ][color= #800080]5 [/color][color=#000080]*(([/color][color=#000000]ULONG[/color][color=#000080]*)[/color][color=#000000]NULL[/color][color=#000080]) = [/color][color=#800080]0[/color][color=#000080]; [ /color ][color= #800080]6 [/color][color=#000080]} [ /color ][color= #800080]7 [/color][color=#000000]__except[/color][color=#000080](([/color][color=#000000]STATUS_INVALID_PARAMETER [/color][color=#000080]== [/color][color=#000000]GetExceptionCode[/color][color=#000080]()) ? [/color][color=#000000]EXCEPTION_CONTINUE_SEARCH [/color][color=#000080]: [/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) [ /color ][color= #800080]8 [/color][color=#000080]{ [ /color ][color= #800080]9 [/color][color=#000080]... [ /color ][color= #800080]10 [/color][color=#000080]} [ /color ][color= #800080]11 [/color][color=#000080]} [ /color ][color= #800080]12 [/color][color=#000000]__finally [ /color ][color= #800080]13 [/color][color=#000080]{ [ /color ][color= #800080]14 [/color][color=#000080]... [ /color ][color= #800080]15 [/color][color=#000080]{[/color][/font] |
EXCEPT_POINT 指的是行5中的代码。
EXCEPT_FILTER 指的是行7中的“(STATUS_INVALID_PARAMETER == GetExceptionCode()) ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER”。
EXCEPT_HANDLER 指的是行8到行10中所有的代码。
FINALLY_HANDLER 指的是行13到行15中所有的代码。
一、异常注册
在 x64 windows 中,异常注册信息发生了巨大的改变。x86 中异常注册信息是在函数执行过程中在栈中分配并初始化的。x64 中变成这样:
异常注册信息不再是动态创建,而是编译过程中生成,链接时写入 PE+ 头中的 ExceptionDirectory(参考 winnt.h 中 IMAGE_RUNTIME_FUNCTION_ENTRY 的定义)。ExceptionDirectory 里包含几乎所有函数的栈操作、异常处理等信息。
来看看新异常注册信息的数据结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
[font=Consolas][color= #000000] [/color][color=#0000FF]typedef struct [/color][color=#000000]_RUNTIME_FUNCTION [/color][color=#000080]{ [ /color ][color= #000000]ULONG BeginAddress[/color][color=#000080]; [ /color ][color= #000000]ULONG EndAddress[/color][color=#000080]; [ /color ][color= #000000]ULONG UnwindData[/color][color=#000080]; } [ /color ][color= #000000]RUNTIME_FUNCTION[/color][color=#000080], *[/color][color=#000000]PRUNTIME_FUNCTION[/color][color=#000080]; [ /color ][color= #0000FF]typedef enum [/color][color=#000000]_UNWIND_OP_CODES [/color][color=#000080]{ [ /color ][color= #000000]UWOP_PUSH_NONVOL [/color][color=#000080]= [/color][color=#800080]0[/color][color=#000080], [ /color ][color= #000000]UWOP_ALLOC_LARGE[/color][color=#000080], [/color][color=#008000]// 1 [ /color ][color= #000000]UWOP_ALLOC_SMALL[/color][color=#000080], [/color][color=#008000]// 2 [ /color ][color= #000000]UWOP_SET_FPREG[/color][color=#000080], [/color][color=#008000]// 3 [ /color ][color= #000000]UWOP_SAVE_NONVOL[/color][color=#000080], [/color][color=#008000]// 4 [ /color ][color= #000000]UWOP_SAVE_NONVOL_FAR[/color][color=#000080], [/color][color=#008000]// 5 [ /color ][color= #000000]UWOP_SPARE_CODE1[/color][color=#000080], [/color][color=#008000]// 6 [ /color ][color= #000000]UWOP_SPARE_CODE2[/color][color=#000080], [/color][color=#008000]// 7 [ /color ][color= #000000]UWOP_SAVE_XMM128[/color][color=#000080], [/color][color=#008000]// 8 [ /color ][color= #000000]UWOP_SAVE_XMM128_FAR[/color][color=#000080], [/color][color=#008000]// 9 [ /color ][color= #000000]UWOP_PUSH_MACHFRAME [/color][color=#008000]// 10 [ /color ][color= #000080]} [/color][color=#000000]UNWIND_OP_CODES[/color][color=#000080], *[/color][color=#000000]PUNWIND_OP_CODES[/color][color=#000080]; [ /color ][color= #0000FF]typedef union [/color][color=#000000]_UNWIND_CODE [/color][color=#000080]{ [ /color ][color= #0000FF]struct [/color][color=#000080]{ [ /color ][color= #000000]UCHAR CodeOffset[/color][color=#000080]; [ /color ][color= #000000]UCHAR UnwindOp [/color][color=#000080]: [/color][color=#800080]4[/color][color=#000080]; [ /color ][color= #000000]UCHAR OpInfo [/color][color=#000080]: [/color][color=#800080]4[/color][color=#000080]; }; [ /color ][color= #000000]USHORT FrameOffset[/color][color=#000080]; } [ /color ][color= #000000]UNWIND_CODE[/color][color=#000080], *[/color][color=#000000]PUNWIND_CODE[/color][color=#000080]; [ /color ][color= #0000FF]#define [/color][color=#000000]UNW_FLAG_NHANDLER [/color][color=#800080]0x0 [ /color ][color= #0000FF]#define [/color][color=#000000]UNW_FLAG_EHANDLER [/color][color=#800080]0x1 [ /color ][color= #0000FF]#define [/color][color=#000000]UNW_FLAG_UHANDLER [/color][color=#800080]0x2 [ /color ][color= #0000FF]#define [/color][color=#000000]UNW_FLAG_CHAININFO [/color][color=#800080]0x4 [ /color ][color= #0000FF]typedef struct [/color][color=#000000]_UNWIND_INFO [/color][color=#000080]{ [ /color ][color= #000000]UCHAR Version [/color][color=#000080]: [/color][color=#800080]3[/color][color=#000080]; [ /color ][color= #000000]UCHAR Flags [/color][color=#000080]: [/color][color=#800080]5[/color][color=#000080]; [ /color ][color= #000000]UCHAR SizeOfProlog[/color][color=#000080]; [ /color ][color= #000000]UCHAR CountOfCodes[/color][color=#000080]; [ /color ][color= #000000]UCHAR FrameRegister [/color][color=#000080]: [/color][color=#800080]4[/color][color=#000080]; [ /color ][color= #000000]UCHAR FrameOffset [/color][color=#000080]: [/color][color=#800080]4[/color][color=#000080]; [ /color ][color= #000000]UNWIND_CODE UnwindCode[/color][color=#000080][[/color][color=#800080]1[/color][color=#000080]]; [ /color ][color= #008000]// // The unwind codes are followed by an optional DWORD aligned field that // contains the exception handler address or a function table entry if // chained unwind information is specified. If an exception handler address // is specified, then it is followed by the language specified exception // handler data. // // union { // struct { // ULONG ExceptionHandler; // ULONG ExceptionData[]; // }; // // RUNTIME_FUNCTION FunctionEntry; // }; // [ /color ][color= #000080]} [/color][color=#000000]UNWIND_INFO[/color][color=#000080], *[/color][color=#000000]PUNWIND_INFO[/color][color=#000080]; [ /color ][color= #0000FF]typedef struct [/color][color=#000000]_SCOPE_TABLE [/color][color=#000080]{ [ /color ][color= #000000]ULONG Count[/color][color=#000080]; [ /color ][color= #0000FF]struct [ /color ][color= #000080]{ [ /color ][color= #000000]ULONG BeginAddress[/color][color=#000080]; [ /color ][color= #000000]ULONG EndAddress[/color][color=#000080]; [ /color ][color= #000000]ULONG HandlerAddress[/color][color=#000080]; [ /color ][color= #000000]ULONG JumpTarget[/color][color=#000080]; } [ /color ][color= #000000]ScopeRecord[/color][color=#000080][[/color][color=#800080]1[/color][color=#000080]]; } [ /color ][color= #000000]SCOPE_TABLE[/color][color=#000080], *[/color][color=#000000]PSCOPE_TABLE[/color][color=#000080];[/color][/font] |
x64 中,MSC 为几乎所有的函数都登记了完备的信息,用来在展开过程中完整的回滚函数所做的栈、寄存器操作。登记的信息包括:
函数是否使用了 SEH、
函数使用的是什么组合的 SEH(__try/__except?__try/__finally?)、
函数申请了多少栈空间、
函数保存了哪些寄存器、
函数是否建立了栈帧,
等等,
同时也记录了这些操作的顺序(以保证回滚的时候不会乱套)。
这些信息就存储在 UNWIND_INFO 之中。
UNWIND_INFO 相当于 x86 下的 EXCEPTION_REGISTRATION。它的成员分别是:
Version —— 结构体的版本。
Flags —— 标志位,可以有这么几种取值:
UNW_FLAG_NHANDLER (0x0): 表示既没有 EXCEPT_FILTER 也没有 EXCEPT_HANDLER。
UNW_FLAG_EHANDLER (0x1): 表示该函数有 EXCEPT_FILTER & EXCEPT_HANDLER。
UNW_FLAG_UHANDLER (0x2): 表示该函数有 FINALLY_HANDLER。
UNW_FLAG_CHAININFO (0x4): 表示该函数有多个 UNWIND_INFO,它们串接在一起(所谓的 chain)。
SizeOfProlog —— 表示该函数的 Prolog 指令的大小,单位是 byte。
CountOfCodes —— 表示当前 UNWIND_INFO 包含多少个 UNWIND_CODE 结构。
FrameRegister —— 如果函数建立了栈帧,它表示栈帧的索引(相对于 CONTEXT::RAX 的偏移,详情参考 RtlVirtualUnwind 源码)。否则该成员的值为0。
FrameOffset —— 表示 FrameRegister 距离函数最初栈顶(刚进入函数,还没有执行任何指令时的栈顶)的偏移,单位也是 byte。
UnwindCode —— 是一个 UNWIND_CODE 类型的数组。元素数量由 CountOfCodes 决定。
需要说明几点:
1. 如果 Flags 设置了 UNW_FLAG_EHANDLER 或 UNW_FLAG_UHANDLER,那么在最后一个 UNWIND_CODE 之后存放着 ExceptionHandler(相当于 x86 EXCEPTION_REGISTRATION::handler)和 ExceptionData(相当于 x86 EXCEPTION_REGISTRATION::scopetable)。
2. UnwindCode 数组详细记录了函数修改栈、保存非易失性寄存器的指令。
3. MSDN 中有 UNWIND_INFO 和 UNWIND_CODE 的详细说明,推荐阅读。
那 UNWIND_INFO 是如何与其描述的函数关联起来的呢?答案是:通过一个 RUNTIME_FUNCTION 结构体。
RUNTIME_FUNCTION::BeginAddress 同 RUNTIME_FUNCTION::EndAddress 一起以 RVA 形式描述了函数的范围。
RUNTIME_FUNCTION::UnwindData 就是 UNWIND_INFO 了,它也是一个 RVA 值。
PE+ 中的 ExceptionDirectory 中存放着所有函数的 RUNTIME_FUNCTION,按 RUNTIME_FUNCTION::BeginAddress 升序排列。一旦触发异常,系统可以通过 EXCEPT_POINT 的 RVA 在 ExceptionDirectory 中二分查找到 RUNTIME_FUNCTION,进而找到 UNWIND_INFO。
前面有提到,MSC 为几乎所有的函数都登记了完毕的信息,那是不是有一些特殊函数没有登记信息呢?
是的。x64 新增了一个概念,叫做“叶函数”。熟悉数据结构的朋友可能第一时间就联想到“叶节点”。没错,“叶函数”的含义跟“叶节点”很类似,叶函数不会有子函数,也就是说它不会再调用任何函数。另外 x64 对这个概念额外加了一些要求:不修改栈指针(比如分配栈空间)、没有使用 SEH。总结下来就是:既不调用函数、又没有修改栈指针,也没有使用 SEH 的函数就叫做“叶函数”。
叶函数可以没有登记信息,原因很简单,它根本就没信息需要登记~
还有一个 SCOPE_TABLE 结构,熟悉 x86 SEH 的朋友应该很眼熟 :-),它等同于 x86 SEH 中的 REGISTRATIOIN_RECORD::scopetable 的类型。其成员有:
Count —— 表示 ScopeRecord 数组的大小。
ScopeRecord —— 等同于 x86 中的 scopetable_entry 成员。其中,
BeginAddress 和 EndAddress 表示某个 __try 保护域的范围。
HandlerAddress 和 JumpTarget 表示 EXCEPTION_FILTER、EXCEPT_HANDLER 和 FINALLY_HANDLER。具体对应情况为:
对于 __try/__except 组合,HandlerAddress 代表 EXCEPT_FILTER,JumpTarget 代表 EXCEPT_HANDLER。
对于 __try/__finally 组合,HandlerAddress 代表 FINALLY_HANDLER,JumpTarget 等于 0。
这四个域通常都是 RVA,但当 EXCEPT_FILTER 简单地返回或等于 EXCEPTION_EXECUTE_HANDLER 时,HandlerAddress 可能直接等于 EXCEPTION_EXECUTE_HANDLER,而不再是一个 RVA。
我们可以通过 windbg 中的 .fnent 命令来查看某个函数的异常注册信息。比如,
1 kd> .fnent passThrough!SehTest
2 Debugger function entry 00000000`00778210 for:
3 d:\workspace\code\mycode\r0\passthrough\passthrough.c(51)
4 (fffffadf`f140f020) PassThrough!SehTest | (fffffadf`f140f0c0) PassThrough!Caller2
5 Exact matches:
6 PassThrough!SehTest (void)
7
8 BeginAddress = 00000000`00001020
9 EndAddress = 00000000`000010b2
10 UnwindInfoAddress = 00000000`00002668
11
12 Unwind info at fffffadf`f1410668, 10 bytes
13 version 1, flags 1, prolog 4, codes 1
14 handler routine: PassThrough!_C_specific_handler (fffffadf`f140f4ce), data 3
15 00: offs 4, unwind op 2, op info 4 UWOP_ALLOC_SMALL.
行8到行10描述的是 RUNTIME_FUNCTION。
行12到行15描述的是 UNWIND_INFO。
对于叶函数,输出是这样的,
kd> .fnent passthrough!LeafTest
No function entry for fffffadf`f240c080
到这里,异常注册就讲完了,我们认识了相关的数据结构和定位方法。下面我们进入异常分发流程。
二、异常分发
x64 异常分发过程使用的仍然是 KiDispatchException、RtlDispatchException、RtlpExecuteHandlerForException 等函数。
其中,KiDispatchException 中有关内核异常部分的代码完全没有变化,这里我偷懒直接拷贝《SEH分析笔记(X86篇)》中的部分描述,
原型:
1
2
3
4
5
6
7
8
|
VOID KiDispatchException ( IN PEXCEPTION_RECORD ExceptionRecord, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN FirstChance ); |
对于内核异常,它的处理步骤如下:
如果 FirstChance 为 TRUE,那么,
1. 首先将该异常传达给内核调试器(KD),如果 KD 处理了该异常,那么函数返回。
2. KD 没有处理,调用 RtlDispatchException 进行异常分发。如果分发成功,RtlDispatchExcetpion 返回 TRUE,或者根本不返回。
3. RtlDispatchException 分发失败,那么再给 KD 一次处理机会,如果还是没有处理,那么 BUGCHECK。
如果 FirstChance 为 FALSE,那么将该异常传达给 KD,如果 KD 没有处理,那么 BUGCHECK。
它的源码实现位于 $WRK-v1.2\base\ntos\ke\amd64\exceptn.c:430。
RtlDispatchException 发生了一些改变。
从之前描述的异常注册信息的数据结构可以发现,x64 中已经不存在异常注册链这个概念了(虽然 _NT_TIB 结构体中还保留了 ExceptionList 域)。那 x64 中 RtlDispatchException 是如何遍历异常注册信息的呢?前面虽然有提到如何通过 EXCEPT_POINT 找到 UNWIND_INFO 结构,但是假如这个 UNWIND_INFO 没有处理该异常,如何继续遍历呢?
在解答这个问题之前,我们先来认识一个新函数和相关的数据结构,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
[font=Consolas][color= #000000] [/color][color=#0000FF]#define [/color][color=#000000]UNWIND_HISTORY_TABLE_SIZE [/color][color=#800080]12 [ /color ][color= #0000FF]typedef struct [/color][color=#000000]_UNWIND_HISTORY_TABLE_ENTRY [/color][color=#000080]{ [ /color ][color= #000000]ULONG64 ImageBase[/color][color=#000080]; [ /color ][color= #000000]PRUNTIME_FUNCTION FunctionEntry[/color][color=#000080]; } [ /color ][color= #000000]UNWIND_HISTORY_TABLE_ENTRY[/color][color=#000080], *[/color][color=#000000]PUNWIND_HISTORY_TABLE_ENTRY[/color][color=#000080]; [ /color ][color= #0000FF]#define [/color][color=#000000]UNWIND_HISTORY_TABLE_NONE [/color][color=#800080]0 [ /color ][color= #0000FF]#define [/color][color=#000000]UNWIND_HISTORY_TABLE_GLOBAL [/color][color=#800080]1 [ /color ][color= #0000FF]#define [/color][color=#000000]UNWIND_HISTORY_TABLE_LOCAL [/color][color=#800080]2 [ /color ][color= #0000FF]typedef struct [/color][color=#000000]_UNWIND_HISTORY_TABLE [/color][color=#000080]{ [ /color ][color= #000000]ULONG Count[/color][color=#000080]; [ /color ][color= #000000]UCHAR Search[/color][color=#000080]; [ /color ][color= #000000]ULONG64 LowAddress[/color][color=#000080]; [ /color ][color= #000000]ULONG64 HighAddress[/color][color=#000080]; [ /color ][color= #000000]UNWIND_HISTORY_TABLE_ENTRY Entry[/color][color=#000080][[/color][color=#000000]UNWIND_HISTORY_TABLE_SIZE[/color][color=#000080]]; } [ /color ][color= #000000]UNWIND_HISTORY_TABLE[/color][color=#000080], *[/color][color=#000000]PUNWIND_HISTORY_TABLE[/color][color=#000080]; [ /color ][color= #000000]PRUNTIME_FUNCTION RtlLookupFunctionEntry [ /color ][color= #000080]( [ /color ][color= #000000]IN ULONG64 ControlPc[/color][color=#000080], [ /color ][color= #000000]OUT PULONG64 ImageBase[/color][color=#000080], [ /color ][color= #000000]IN OUT PUNWIND_HISTORY_TABLE HistoryTable OPTIONAL [ /color ][color= #000080]);[/color][/font] |
RtlLookupFunctionEntry 的功能是查找指定地址所在函数的 RUNTIME_FUNCTION 和所在模块的基地址。它的参数分为为,
ControlPc —— 需要查找的指令地址,
ImageBase —— 返回的模块基地址,
HistoryTable —— 用于加速查找。
工作流程:
RtlLookupFunctionEntry 在搜索的过程会根据是否传入 HistoryTable 而采取不同的搜索方法:
如果传入 HistoryTable,则根据 HistoryTable->Search 表示的搜索方式在表中进行搜索:
如果搜索方式为 UNWIND_HISTORY_TABLE_NONE,那么不在 HistoryTable 中进行搜索。
如果搜索方式为 UNWIND_HISTORY_TABLE_GLOBAL,则首先在全局表 RtlpUnwindHistoryTable 开始搜索,如果搜索到,则结束搜索,函数返回。否则再在 HistoryTable 中搜索。
如果搜索方式为 UNWIND_HISTORY_TABLE_LOCAL,那么在 HistoryTable 中搜索。
如果上述过程中没有搜索到需要的结果,那么找到模块基地址,从模块的 PE+ 头结构中解析出 RUNTIME_FUNCTION。如果搜索方式为 UNWIND_HISTORY_TABLE_NONE,还会将解决加入到 HistoryTable。
之前的描述中 RtlDispatchException 定位 EXCEPT_POINT 所对应的 RUNTIME_FUNCTION 就是通过调用 RtlLookupFunctionEntry 实现的。
回到刚才的问题,如何推动遍历呢?为了解决这个问题,x64 又引进了一个新函数。现在我们有请 x64 SEH 核心成员 RtlVirtualUnwind 登场~
先来看看它的原型:
1
2
3
4
5
6
7
8
9
10
11
|
PEXCEPTION_ROUTINE RtlVirtualUnwind ( IN ULONG HandlerType, IN ULONG64 ImageBase, IN ULONG64 ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, IN OUT PCONTEXT ContextRecord, OUT PVOID *HandlerData, OUT PULONG64 EstablisherFrame, IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL ); |
它的主要功能是:
根据传入的 ControlPc 和 ContextRecord 等参数虚拟(模拟)展开该函数,并返回该函数的一些信息,比如 HandlerData(SCOPE_TABLE)、EstablisherFrame(rsp 或 栈帧)。
流程是:
1. 通过 FunctionEntry 和 ImageBase 找到 UNWIND_INFO。根据 UNWIND_INFO 中记录的信息,查找 EstablisherFrame(即栈帧或者 rsp)。
2. 根据 ControlPc 分如下两种情况展开:
a. ControlPc >= EpilogOffset,即 ControlPc 在 Epilog 之中。那么把剩余的 Epilog 指令模拟执行完毕即可。
所谓模拟是指,如果下一条 EpiLog 指令是“sub rsp, 0x32”,那么将 ContextRecord->rsp 减去0x32。并不是真正执行 sub 指令。
b. ControlPc < EpilogOffset,那么把 Prolog 反向模拟回滚一遍即可。
所谓反向回滚是指,如果 Prolog 的指令是
mov [RSP + 8], RCX
push R15
push R14
push R13
那么反向回滚就是
pop ContextRecord->R13 (实际上是从 ContextRecord->Rsp 指向的内存中取出值存入 ContextRecord->R13,然后 ContextRecord->Rsp 加上8。并不是真正执行 pop)
pop ContextRecord->R14
pop ContextRecord->R15
mov ContextRecord->RCX, [ContextRecord->RSP+8]
然后把 ContextRecord->Rip 修改为 ControlPc 所在函数的返回地址,即父函数中的某一处 call 的下一条指令。
这样,ContextRecord 就被恢复成父函数在调用 ControlPc 所在函数之后的状态了。
3. 如果 HandlerType 包含 UNW_FLAG_EHANDLER 或 UNW_FLAG_UHANDLER,那么将 UNWIND_INFO::ExceptionData 赋给传出参数 HandlerData,并返回 UNWIND_INFO::ExceptionRoutine。
对于 MSC 编译器生成的模块,UNWIND_INFO::ExceptionRoutine 一般指向 nt!__C_specific_handler。UNWIND_INFO::ExceptionData 指向 ControlPc 所在函数的 SCOPE_TABLE。
RtlVirtualUnwind 的实现源码位于 $WRK-v1.2\base\ntos\rtl\amd64\exdsptch.c:1202。
RtlVirtualUnwind 返回后,RtlDispatchException 就可以根据 ContextRecord->Rip 找到父函数对应的 RUNTIME_FUNCTION,进而找到 UNWIND_INFO。就这样推动整个遍历过程。
这是一般情况,对于没有 UNWIND_INFO 的叶函数呢?
对于叶函数,RtlLookupFunctionEntry 返回 NULL,于是 RtlDispatchException 知道这是个叶函数,就找到该叶函数的父函数,从父函数继续遍历。也就是完全无视叶函数,因为叶函数对整个异常处理过程没有任何影响。
RtlDispatchException 调用 UNWIND_INFO::ExceptionHandler 依然是通过 RtlpExecuteHandlerForException,其函数原型没有变化:
1
2
3
4
5
6
7
|
EXCEPTION_DISPOSITION RtlpExecuteHandlerForException ( IN PEXCEPTION_RECORD ExceptionRecord, IN PVOID EstablisherFrame, IN OUT PCONTEXT ContextRecord, IN OUT PVOID DispatcherContext ); |
该函数的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:84。
RtlpExecuteHandlerForException 的逻辑较 x86 版本没什么大变化,内部注册了一个异常处理函数 RtlpExceptionHandler。RtlpExceptionHandler 相当于 x86 中的 nt!ExecuteHandler2,其内部会返回 ExceptionNestedException 或 ExceptionContinueSearch。它的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:26。
需要一提的是,最后一个参数 DispatchContext 的类型是 DISPATCHER_CONTEXT,相对于 x86 版本,它扩充了很多,
1
2
3
4
5
6
7
8
9
10
11
12
13
|
typedef struct _DISPATCHER_CONTEXT { ULONG64 ControlPc; ULONG64 ImageBase; PRUNTIME_FUNCTION FunctionEntry; ULONG64 EstablisherFrame; ULONG64 TargetIp; PCONTEXT ContextRecord; PEXCEPTION_ROUTINE LanguageHandler; PVOID HandlerData; PUNWIND_HISTORY_TABLE HistoryTable; ULONG ScopeIndex; ULONG Fill0; } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; |
成员分别为:
ControlPc —— 异常触发点。
ImagePase —— ControlPc 所在模块的基地址。
FunctionEntry —— ControlPc 所在函数的 RUNTIME_FUNCTION。
EstablisherFrame —— ControlPc 所在函数的栈帧(如果建立了栈帧)或 RSP。
TargetIp —— 解决异常的 EXCEPT_HANDLER 地址,该成员只在展开的过程中被使用。RtlpExecuteHandlerForException 没有使用它。
ContextRecord —— 供展开过程中使用,只有当展开过程中触发新异常(返回 ExceptionCollidedUnwind)时,才会被 RtlDispatchException 真正的使用到(参考 RtlDispatchException 处理 ExceptionCollidedUnwind 的代码)。
LanguageHandler —— ControlPc 所在函数的 UNWIND_INFO::ExceptionRoutine。
HandlerData —— ControlPc 所在函数的 UNWIND_INFO::ExceptionData。
ScopeIndex —— UNWIND_INFO::ExceptionData 中 SCOPE_TABLE::ScopeRecord 的索引,通常设置为0(注:请不要与 x86 中运行时不断改变的 EXCEPTION_REGISTRATION::trylevel 相混淆,ScopeIndex 不会在在函数执行过程中改变)
Fill0 —— 未用。
再看一下它的 .fnent 输出,
1 kd> .fnent nt!RtlpExecuteHandlerForException
2 Debugger function entry 00000000`01458210 for:
3 (fffff800`008bd950) nt!RtlpExecuteHandlerForException | (fffff800`008bd970) nt!RtlpUnwindHandler
4 Exact matches:
5 nt!RtlpExecuteHandlerForException (void)
6
7 BeginAddress = 00000000`000bd950
8 EndAddress = 00000000`000bd963
9 UnwindInfoAddress = 00000000`000dfeb8
10
11 Unwind info at fffff800`008dfeb8, 10 bytes
12 version 1, flags 3, prolog 4, codes 1
13 handler routine: nt!RtlpExceptionHandler (fffff800`008bd920), data 0
14 00: offs 4, unwind op 2, op info 4 UWOP_ALLOC_SMALL.
行12中显示 flags 等于3,即 UNW_FLAG_EHANDLER (0x1) | UNW_FLAG_UHANDLER (0x2),说明行13中显示的异常处理函数 nt!RtlpExceptionHandler 既负责解决异常,也负责展开。
RtlpExecuteHandlerForException 会调用 DISPATCHER_CONTEXT::LanguageHandler。对于 MSC 编译得到的模块,它是 nt!__C_specific_handler,我们来看看这个函数,
原型:
1
2
3
4
5
6
7
|
EXCEPTION_DISPOSITION __C_specific_handler ( IN PEXCEPTION_RECORD pExceptionRecord, IN PVOID pEstablisherFrame, IN OUT PCONTEXT pContext, IN OUT PVOID pDispatcherContext ); |
反汇编码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
[font=Consolas][color= #000000] kd[/color][color=#0A246A]> [/color][color=#000000]uf nt!__C_specific_handler nt!__C_specific_handler[ /color ][color= #0A246A]: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a42d0 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]10h[/color][color=#0A246A]],[/color][color=#000000]rdx [/color][color=#008000]; 在栈上保存 pEstablisherFrame [ /color ][color= #000000]fffff800`[/color][color=#800080]008a42d5 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rsp fffff800`[ /color ][color= #800080]008a42d8 [/color][color=#0A246A]sub [/color][color=#000000]rsp[/color][color=#0A246A],[/color][color=#800080]88h [ /color ][color= #000000]fffff800`[/color][color=#800080]008a42df [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]8[/color][color=#0A246A]],[/color][color=#000000]rbx fffff800`[ /color ][color= #800080]008a42e3 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]10h[/color][color=#0A246A]],[/color][color=#000000]rbp fffff800`[ /color ][color= #800080]008a42e7 [/color][color=#0A246A]mov [/color][color=#000000]rbp[/color][color=#0A246A],qword ptr [[/color][color=#000000]r9[/color][color=#0A246A]] [/color][color=#008000]; rbp = pDispatcherContext->ControlPc [ /color ][color= #000000]fffff800`[/color][color=#800080]008a42ea [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]18h[/color][color=#0A246A]],[/color][color=#000000]rsi fffff800`[ /color ][color= #800080]008a42ee [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]20h[/color][color=#0A246A]],[/color][color=#000000]rdi fffff800`[ /color ][color= #800080]008a42f2 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]28h[/color][color=#0A246A]],[/color][color=#000000]r12 fffff800`[ /color ][color= #800080]008a42f6 [/color][color=#0A246A]mov [/color][color=#000000]r12[/color][color=#0A246A],qword ptr [[/color][color=#000000]r9[/color][color=#0A246A]+[/color][color=#800080]38h[/color][color=#0A246A]] [/color][color=#008000]; r12 = pDispatcherContext->HandlerData [ /color ][color= #000000]fffff800`[/color][color=#800080]008a42fa [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]30h[/color][color=#0A246A]],[/color][color=#000000]r13 fffff800`[ /color ][color= #800080]008a42fe [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]38h[/color][color=#0A246A]],[/color][color=#000000]r14 fffff800`[ /color ][color= #800080]008a4302 [/color][color=#0A246A]mov [/color][color=#000000]r14[/color][color=#0A246A],qword ptr [[/color][color=#000000]r9[/color][color=#0A246A]+[/color][color=#800080]8[/color][color=#0A246A]] [/color][color=#008000]; r14 = pDispatcherContext->ImageBase [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4306 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]40h[/color][color=#0A246A]],[/color][color=#000000]r15 fffff800`[ /color ][color= #800080]008a430a [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],[/color][color=#000000]r9 [/color][color=#008000]; r13 = pDispatcherContext [ /color ][color= #000000]fffff800`[/color][color=#800080]008a430d [/color][color=#0A246A]sub [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; l_OffsetInFunc = pDispatcherContext->ControlPc - pDispatcherContext->ImageBase [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4310 [/color][color=#0A246A]test byte ptr [[/color][color=#000000]rcx[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]],[/color][color=#800080]66h [/color][color=#008000]; pExceptionRecord->ExceptionFlags, EXCEPTION_UNWIND (0x66) [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4314 [/color][color=#0A246A]mov [/color][color=#000000]rsi[/color][color=#0A246A],[/color][color=#000000]rdx [/color][color=#008000]; rsi = pEstablisherFrame [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4317 [/color][color=#0A246A]mov [/color][color=#000000]r15[/color][color=#0A246A],[/color][color=#000000]rcx [/color][color=#008000]; r15 = pExceptionRecord [ /color ][color= #0A246A]< [/color][color=#000000]fffff800`[/color][color=#800080]008a431a [/color][color=#0A246A]jne [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xf5 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43c5[/color][color=#0A246A]) : : ------------------------------------------------------------------- : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x50[/color][color=#0A246A]: : [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4320 [/color][color=#000000]movsxd rdi[/color][color=#0A246A],dword ptr [[/color][color=#000000]r9[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]] [/color][color=#008000]; l_ScopeIndex (rdi) = pDispatcherContext->ScopeIndex [ /color ][color= #0A246A]: [/color][color=#000000]fffff800`[/color][color=#800080]008a4324 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]58h[/color][color=#0A246A]],[/color][color=#000000]rcx [/color][color=#008000]; [rax-58h] = pExceptionRecord,供给 GetExceptionCode(Information) 使用 [ /color ][color= #0A246A]: [/color][color=#000000]fffff800`[/color][color=#800080]008a4328 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]50h[/color][color=#0A246A]],[/color][color=#000000]r8 [/color][color=#008000]; [rax-50h] = pContext,供给 GetExceptionCode(Information) 使用 [ /color ][color= #0A246A]: [/color][color=#000000]fffff800`[/color][color=#800080]008a432c [/color][color=#0A246A]cmp [/color][color=#FF8000]edi[/color][color=#0A246A],dword ptr [[/color][color=#000000]r12[/color][color=#0A246A]] [/color][color=#008000]; cmp l_ScopeIndex, pDispatcherContext->HandlerData->Count [ /color ][color= #0A246A]: [/color][color=#000000]fffff800`[/color][color=#800080]008a4330 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rax = l_ScopeIndex [ /color ][color= #0A246A]:< [/color][color=#000000]fffff800`[/color][color=#800080]008a4333 [/color][color=#0A246A]jae [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x166 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4436[/color][color=#0A246A]) :: :: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x69[/color][color=#0A246A]: :: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4339 [/color][color=#0A246A]add [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; 这里 *2,下面紧接着 *8,目的是跳过指定数目的 ScopeRecord(大小为16字节) [ /color ][color= #0A246A]:: [/color][color=#000000]fffff800`[/color][color=#800080]008a433c [/color][color=#0A246A]lea [/color][color=#000000]rbx[/color][color=#0A246A],[[/color][color=#000000]r12[/color][color=#0A246A]+[/color][color=#000000]rax[/color][color=#0A246A]*[/color][color=#800080]8[/color][color=#0A246A]+[/color][color=#800080]0Ch[/color][color=#0A246A]] [/color][color=#008000]; rbx = &(pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].HandlerAddress) [ /color ][color= #0A246A]:: :: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x71[/color][color=#0A246A]: :: [ /color ][color= #008000]; 检查 ControlPc 处于哪个 __try 保护域,之步骤一 [ /color ][color= #0A246A]:: > [/color][color=#000000]fffff800`[/color][color=#800080]008a4341 [/color][color=#0A246A]mov [/color][color=#FF8000]eax[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]-[/color][color=#800080]8[/color][color=#0A246A]] [/color][color=#008000]; eax = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].BeginAddress [ /color ][color= #0A246A]:: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4344 [/color][color=#0A246A]cmp [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp l_OffsetInFunc, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].BeginAddress [ /color ][color= #0A246A]::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a4347 [/color][color=#0A246A]jb [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xdd [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43ad[/color][color=#0A246A]) ::: : ::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x79[/color][color=#0A246A]: ::: : [ /color ][color= #008000]; 检查 ControlPc 处于哪个 __try 保护域,之步骤二 [ /color ][color= #0A246A]::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4349 [/color][color=#0A246A]mov [/color][color=#FF8000]eax[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]-[/color][color=#800080]4[/color][color=#0A246A]] [/color][color=#008000]; eax = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].EndAddress [ /color ][color= #0A246A]::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a434c [/color][color=#0A246A]cmp [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp l_OffsetInFunc, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].EndAddress [ /color ][color= #0A246A]:::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a434f [/color][color=#0A246A]jae [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xdd [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43ad[/color][color=#0A246A]) :::: : :::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x81[/color][color=#0A246A]: :::: : [ /color ][color= #008000]; 判断是否是 __try/__finally(JumpTarget 为 NULL)。如果是,那么跳转到下一个 ScopeRecord 继续遍历。 [ /color ][color= #0A246A]:::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4351 [/color][color=#0A246A]cmp dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]],[/color][color=#800080]0 [/color][color=#008000]; cmp pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget, NULL [ /color ][color= #0A246A]::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a4355 [/color][color=#0A246A]je [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xdd [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43ad[/color][color=#0A246A]) ::::: : ::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x87[/color][color=#0A246A]: ::::: : [ /color ][color= #008000]; 到这里,已经找到与异常地址最匹配的 __try/__except [ /color ][color= #0A246A]::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4357 [/color][color=#0A246A]mov [/color][color=#FF8000]eax[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]] [/color][color=#008000]; eax = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].HandlerAddress [ /color ][color= #0A246A]::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4359 [/color][color=#0A246A]cmp [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#800080]1 [/color][color=#008000]; cmp pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].HandlerAddress, EXCEPTION_EXECUTE_HANDLER (0x1) [ /color ][color= #0A246A]:::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a435c [/color][color=#0A246A]je [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xa3 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4373[/color][color=#0A246A]) [/color][color=#008000]; 如果返回 EXCEPTION_EXECUTE_HANDLER 则跳转 [ /color ][color= #0A246A]:::::: : :::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x8e[/color][color=#0A246A]: :::::: : [ /color ][color= #008000]; 是 __try/__except,且过滤域并不是 EXCEPTION_EXECUTE_HANDLER,执行 HandlerAddress [ /color ][color= #0A246A]:::::: : [/color][color=#008000]; (注:HandlerAddress 指向的函数仍有可能会返回 EXCEPTION_EXECUTE_HANDLER) [ /color ][color= #0A246A]:::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a435e [/color][color=#0A246A]lea [/color][color=#000000]rcx[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]30h[/color][color=#0A246A]] :::::: : [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4363 [/color][color=#0A246A]add [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; rax = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].HandlerAddress + pDispatcherContext->ImageBase [ /color ][color= #0A246A]:::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4366 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rsi [/color][color=#008000]; rdx = pEstablisherFrame [ /color ][color= #0A246A]:::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a4369 [/color][color=#0A246A]call [/color][color=#000000]rax [/color][color=#008000]; 调用 EXCEPT_FILTER [ /color ][color= #0A246A]:::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a436b [/color][color=#0A246A]test [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#FF8000]eax [ /color ][color= #0A246A]::::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a436d [/color][color=#0A246A]js [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xee [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43be[/color][color=#0A246A]) [/color][color=#008000]; 返回 EXCEPTION_CONTINUE_EXECUTION (-1) 则跳转 [ /color ][color= #0A246A]::::::: : ::::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x9f[/color][color=#0A246A]: ::::::: : [ /color ][color= #000000]fffff800`[/color][color=#800080]008a436f [/color][color=#0A246A]test [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#FF8000]eax [ /color ][color= #0A246A]:::::::<: [/color][color=#000000]fffff800`[/color][color=#800080]008a4371 [/color][color=#0A246A]jle [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xdd [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43ad[/color][color=#0A246A]) [/color][color=#008000]; 返回 EXCEPTION_CONTINUE_SEARCH (0) 则跳转 [ /color ][color= #0A246A]::::::::: ::::::::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xa3[/color][color=#0A246A]: ::::::::: [ /color ][color= #008000]; 返回的是 EXCEPTION_EXECUTE_HANDLER [ /color ][color= #0A246A]:::::>::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4373 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]] [/color][color=#008000]; ecx = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4376 [/color][color=#0A246A]mov [/color][color=#000000]r8d[/color][color=#0A246A],[/color][color=#800080]1 [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a437c [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rsi [/color][color=#008000]; rdx = pEstablisherFrame [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a437f [/color][color=#0A246A]add [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; rcx = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget + pDispatcherContext->ImageBase [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4382 [/color][color=#0A246A]call [/color][color=#000000]nt!_NLG_Notify [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008b1460[/color][color=#0A246A]) ::::: ::: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4387 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]r13[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]] [/color][color=#008000]; rax = pDispatcherContext->HistoryTable [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a438b [/color][color=#0A246A]mov [/color][color=#FF8000]edx[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]] [/color][color=#008000]; edx = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a438e [/color][color=#000000]movsxd r9[/color][color=#0A246A],dword ptr [[/color][color=#000000]r15[/color][color=#0A246A]] [/color][color=#008000]; r9 = pExceptionRecord->ExceptionCode [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4391 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]28h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG_6 = pDispatcherContext->HistoryTable [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4396 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]r13[/color][color=#0A246A]+[/color][color=#800080]28h[/color][color=#0A246A]] [/color][color=#008000]; rax = pDispatcherContext->ContextRecord [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a439a [/color][color=#0A246A]add [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; rdx = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget + pDispatcherContext->ImageBase [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a439d [/color][color=#0A246A]mov [/color][color=#000000]r8[/color][color=#0A246A],[/color][color=#000000]r15 [/color][color=#008000]; r8 = pExceptionRecord [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43a0 [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]rsi [/color][color=#008000]; rcx = pEstablisherFrame [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43a3 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]20h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG_5 = pDispatcherContext->ContextRecord [ /color ][color= #0A246A]::::: ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43a8 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlUnwindEx [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891e80[/color][color=#0A246A]) [/color][color=#008000]; 这里不会返回 [ /color ][color= #0A246A]::::: ::: [/color][color=#008000]; RtlUnwindEx(pEstablisherFrame, [ /color ][color= #0A246A]::::: ::: [/color][color=#008000]; pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget + pDispatcherContext->ImageBase [ /color ][color= #0A246A]::::: ::: [/color][color=#008000]; pExceptionRecord, [ /color ][color= #0A246A]::::: ::: [/color][color=#008000]; pExceptionRecord->ExceptionCode [ /color ][color= #0A246A]::::: ::: [/color][color=#008000]; pDispatcherContext->ContextRecord, [ /color ][color= #0A246A]::::: ::: [/color][color=#008000]; pDispatcherContext->HistoryTable) [ /color ][color= #0A246A]::::: ::: ::::: ::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xdd[/color][color=#0A246A]: ::>>> :>: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a43ad [/color][color=#0A246A]inc [/color][color=#FF8000]edi [/color][color=#008000]; l_ScopeIndex += 1 [ /color ][color= #0A246A]:: : : [/color][color=#000000]fffff800`[/color][color=#800080]008a43af [/color][color=#0A246A]add [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#800080]10h [/color][color=#008000]; 调整到下一个 ScopeRecord::HandlerAddress [ /color ][color= #0A246A]:: : : [/color][color=#000000]fffff800`[/color][color=#800080]008a43b3 [/color][color=#0A246A]cmp [/color][color=#FF8000]edi[/color][color=#0A246A],dword ptr [[/color][color=#000000]r12[/color][color=#0A246A]] [/color][color=#008000]; cmp l_ScopeIndex, pDispatcherContext->HandlerData->Count [ /color ][color= #0A246A]:: : < [/color][color=#000000]fffff800`[/color][color=#800080]008a43b7 [/color][color=#0A246A]jb [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x71 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4341[/color][color=#0A246A]) :: : :: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xe9[/color][color=#0A246A]: :: : [ /color ][color= #008000]; pDispatcherContext->HandlerData 遍历完毕 [ /color ][color= #0A246A]::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a43b9 [/color][color=#0A246A]jmp [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x166 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4436[/color][color=#0A246A]) ::: : ::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xee[/color][color=#0A246A]: ::: > [ /color ][color= #000000]fffff800`[/color][color=#800080]008a43be [/color][color=#0A246A]xor [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#FF8000]eax [/color][color=#008000]; eax = ExceptionContinueExecution [ /color ][color= #0A246A]:::< [/color][color=#000000]fffff800`[/color][color=#800080]008a43c0 [/color][color=#0A246A]jmp [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x16b [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a443b[/color][color=#0A246A]) :::: :::: ------------------------------------------------------------------------------------- :::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0xf5[/color][color=#0A246A]: :::: [ /color ][color= #008000]; 设置了 EXCEPTION_UNWIND,当前是展开过程 [ /color ][color= #0A246A]>::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43c5 [/color][color=#000000]movsxd rdi[/color][color=#0A246A],dword ptr [[/color][color=#000000]r9[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]] [/color][color=#008000]; l_ScopeIndex (rdi) = pDispatcherContext->ScopeIndex [ /color ][color= #0A246A]::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43c9 [/color][color=#0A246A]mov [/color][color=#000000]rsi[/color][color=#0A246A],qword ptr [[/color][color=#000000]r9[/color][color=#0A246A]+[/color][color=#800080]20h[/color][color=#0A246A]] [/color][color=#008000]; rsi = pDispatcherContext->TargetIp [ /color ][color= #0A246A]::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43cd [/color][color=#0A246A]sub [/color][color=#000000]rsi[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; rsi = pDispatcherContext->TargetIp - pDispatcherContext->ImageBase [ /color ][color= #0A246A]::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43d0 [/color][color=#0A246A]cmp [/color][color=#FF8000]edi[/color][color=#0A246A],dword ptr [[/color][color=#000000]r12[/color][color=#0A246A]] [/color][color=#008000]; cmp l_ScopeIndex, pDispatcherContext->HandlerData->Count [ /color ][color= #0A246A]::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43d4 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rax = l_ScopeIndex [ /color ][color= #0A246A]:::< [/color][color=#000000]fffff800`[/color][color=#800080]008a43d7 [/color][color=#0A246A]jae [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x166 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4436[/color][color=#0A246A]) :::: :::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x109[/color][color=#0A246A]: :::: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a43d9 [/color][color=#0A246A]add [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; [ /color ][color= #0A246A]:::: [/color][color=#000000]fffff800`[/color][color=#800080]008a43dc [/color][color=#0A246A]lea [/color][color=#000000]rbx[/color][color=#0A246A],[[/color][color=#000000]r12[/color][color=#0A246A]+[/color][color=#000000]rax[/color][color=#0A246A]*[/color][color=#800080]8[/color][color=#0A246A]+[/color][color=#800080]8[/color][color=#0A246A]] [/color][color=#008000]; rbx = &(pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].EndAddress) [ /color ][color= #0A246A]:::: :::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x111[/color][color=#0A246A]: :::: [ /color ][color= #008000]; 检查 ControlPc 处于哪个 __try 保护域,之步骤一 [ /color ][color= #0A246A]:::: > [/color][color=#000000]fffff800`[/color][color=#800080]008a43e1 [/color][color=#0A246A]mov [/color][color=#FF8000]eax[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]-[/color][color=#800080]4[/color][color=#0A246A]] [/color][color=#008000]; eax = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].BeginAddress [ /color ][color= #0A246A]:::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a43e4 [/color][color=#0A246A]cmp [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp l_OffsetInFunc, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].BeginAddress [ /color ][color= #0A246A]::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a43e7 [/color][color=#0A246A]jb [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x15a [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a442a[/color][color=#0A246A]) ::::: : ::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x119[/color][color=#0A246A]: ::::: : [ /color ][color= #008000]; 检查 ControlPc 处于哪个 __try 保护域,之步骤二 [ /color ][color= #0A246A]::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a43e9 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]] [/color][color=#008000]; ecx = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].EndAddress [ /color ][color= #0A246A]::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a43eb [/color][color=#0A246A]cmp [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rcx [/color][color=#008000]; cmp l_OffsetInFunc, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].EndAddress [ /color ][color= #0A246A]:::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a43ee [/color][color=#0A246A]jae [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x15a [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a442a[/color][color=#0A246A]) :::::: : :::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x120[/color][color=#0A246A]: :::::: : [ /color ][color= #008000]; 到这里,已经找到与异常地址匹配的最内层(如果有多层) __try/__except [ /color ][color= #0A246A]:::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a43f0 [/color][color=#0A246A]cmp [/color][color=#000000]rsi[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp pDispatcherContext->TargetIp - pDispatcherContext->ImageBase, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].BeginAddress [ /color ][color= #0A246A]::::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a43f3 [/color][color=#0A246A]jb [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x131 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4401[/color][color=#0A246A]) ::::::: : ::::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x125[/color][color=#0A246A]: ::::::: : [ /color ][color= #000000]fffff800`[/color][color=#800080]008a43f5 [/color][color=#0A246A]cmp [/color][color=#000000]rsi[/color][color=#0A246A],[/color][color=#000000]rcx [/color][color=#008000]; cmp pDispatcherContext->TargetIp - pDispatcherContext->ImageBase, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].EndAddress [ /color ][color= #0A246A]:::::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a43f8 [/color][color=#0A246A]ja [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x131 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4401[/color][color=#0A246A]) :::::::: : :::::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x12a[/color][color=#0A246A]: :::::::: : [ /color ][color= #008000]; 如果标记了 EXCEPTION_TARGET_UNWIND,说明是最后一个需要局部展开的函数。但是该次局部展开只展开到 EXCEPT_HANDLER(不包含 EXCEPT_HANDLER),所以需要判断 TargetIp [ /color ][color= #0A246A]:::::::: : [/color][color=#000000]fffff800`[/color][color=#800080]008a43fa [/color][color=#0A246A]test byte ptr [[/color][color=#000000]r15[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]],[/color][color=#800080]20h [/color][color=#008000]; test pExceptionRecord->ExceptionFlags, EXCEPTION_TARGET_UNWIND (0x20) [ /color ][color= #0A246A]::::::::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a43ff [/color][color=#0A246A]jne [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x166 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4436[/color][color=#0A246A]) ::::::::: : ::::::::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x131[/color][color=#0A246A]: ::::::>>: : [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4401 [/color][color=#0A246A]mov [/color][color=#FF8000]eax[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]+[/color][color=#800080]8[/color][color=#0A246A]] [/color][color=#008000]; eax = pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget [ /color ][color= #0A246A]:::::: : : [/color][color=#000000]fffff800`[/color][color=#800080]008a4404 [/color][color=#0A246A]test [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#FF8000]eax [/color][color=#008000]; 判断 pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget 是否为 NULL,即是否是 __try/__finally [ /color ][color= #0A246A]:::::: :< : [/color][color=#000000]fffff800`[/color][color=#800080]008a4406 [/color][color=#0A246A]je [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x13f [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a440f[/color][color=#0A246A]) [/color][color=#008000]; 如果是 __try/__finally 则跳转 [ /color ][color= #0A246A]:::::: :: : :::::: :: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x138[/color][color=#0A246A]: :::::: :: : [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4408 [/color][color=#0A246A]cmp [/color][color=#000000]rsi[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp pDispatcherContext->TargetIp, pDispatcherContext->HandlerData->ScopeRecord[l_ScopeIndex].JumpTarget [ /color ][color= #0A246A]:::::: ::< : [/color][color=#000000]fffff800`[/color][color=#800080]008a440b [/color][color=#0A246A]je [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x166 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a4436[/color][color=#0A246A]) :::::: ::: : :::::: ::: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x13d[/color][color=#0A246A]: :::::: :::<: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a440d [/color][color=#0A246A]jmp [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x15a [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a442a[/color][color=#0A246A]) :::::: ::::: :::::: ::::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x13f[/color][color=#0A246A]: :::::: ::::: [ /color ][color= #008000]; 注意这里是先修改 pDispatcherContext->ScopeIndex,然后调用 EXCEPT_HANDLER。这样如果 EXCEPT_HANDLER 触发异常,后续展开就会跳过这个 EXCEPT_HANDLER。 [ /color ][color= #0A246A]:::::: :>::: [/color][color=#000000]fffff800`[/color][color=#800080]008a440f [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]98h[/color][color=#0A246A]] :::::: : ::: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4417 [/color][color=#0A246A]lea [/color][color=#FF8000]eax[/color][color=#0A246A],[[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]1[/color][color=#0A246A]] [/color][color=#008000]; eax = l_ScopeIndex + 1 [ /color ][color= #0A246A]:::::: : ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a441a [/color][color=#0A246A]mov [/color][color=#FF8000]cl[/color][color=#0A246A],[/color][color=#800080]1 [ /color ][color= #0A246A]:::::: : ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a441c [/color][color=#0A246A]mov dword ptr [[/color][color=#000000]r13[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]],[/color][color=#FF8000]eax [/color][color=#008000]; pDispatcherContext->ScopeIndex = eax [ /color ][color= #0A246A]:::::: : ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4420 [/color][color=#0A246A]mov [/color][color=#000000]r8d[/color][color=#0A246A],dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]] [/color][color=#008000]; r8d = pDispatcherContext->HandlerData->ScopeRecord[i].HandlerAddress [ /color ][color= #0A246A]:::::: : ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4424 [/color][color=#0A246A]add [/color][color=#000000]r8[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; r8 = pDispatcherContext->HandlerData->ScopeRecord[i].HandlerAddress + pDispatcherContext->ImageBase [ /color ][color= #0A246A]:::::: : ::: [/color][color=#000000]fffff800`[/color][color=#800080]008a4427 [/color][color=#0A246A]call [/color][color=#000000]r8 [/color][color=#008000]; 调用 __finally 处理块,会返回(注:对于 __try/__finally,HandlerAddress 保存的是 __finally 代码块的 RVA) [ /color ][color= #0A246A]:::::: : ::: :::::: : ::: [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x15a[/color][color=#0A246A]: ::::>> : :>: [ /color ][color= #000000]fffff800`[/color][color=#800080]008a442a [/color][color=#0A246A]inc [/color][color=#FF8000]edi [/color][color=#008000]; l_ScopeIndex += 1 [ /color ][color= #0A246A]:::: : : : [/color][color=#000000]fffff800`[/color][color=#800080]008a442c [/color][color=#0A246A]add [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#800080]10h [/color][color=#008000]; 调整到下一个 ScopeRecord::HandlerAddress [ /color ][color= #0A246A]:::: : : : [/color][color=#000000]fffff800`[/color][color=#800080]008a4430 [/color][color=#0A246A]cmp [/color][color=#FF8000]edi[/color][color=#0A246A],dword ptr [[/color][color=#000000]r12[/color][color=#0A246A]] [/color][color=#008000]; cmp l_ScopeIndex, pDispatcherContext->HandlerData->Count [ /color ][color= #0A246A]:::: : : < [/color][color=#000000]fffff800`[/color][color=#800080]008a4434 [/color][color=#0A246A]jb [/color][color=#000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x111 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008a43e1[/color][color=#0A246A]) :::: : : :::: : : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x166[/color][color=#0A246A]: >>:> > > [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4436 [/color][color=#0A246A]mov [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#800080]1 [/color][color=#008000]; eax = ExceptionContinueSearch (0n1) [ /color ][color= #0A246A]: : [ /color ][color= #000000]nt!__C_specific_handler[/color][color=#0A246A]+[/color][color=#800080]0x16b[/color][color=#0A246A]: > [ /color ][color= #000000]fffff800`[/color][color=#800080]008a443b [/color][color=#0A246A]mov [/color][color=#000000]r15[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4440 [/color][color=#0A246A]mov [/color][color=#000000]r14[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]50h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4445 [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]58h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a444a [/color][color=#0A246A]mov [/color][color=#000000]r12[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]60h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a444f [/color][color=#0A246A]mov [/color][color=#000000]rdi[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]68h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4454 [/color][color=#0A246A]mov [/color][color=#000000]rsi[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]70h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4459 [/color][color=#0A246A]mov [/color][color=#000000]rbp[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]78h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a445e [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]80h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]008a4466 [/color][color=#0A246A]add [/color][color=#000000]rsp[/color][color=#0A246A],[/color][color=#800080]88h [ /color ][color= #000000]fffff800`[/color][color=#800080]008a446d [/color][color=#000000]ret[/color][/font] |
nt!__C_specific_handler 相当于 x86 中的 nt!_except_handler3。从上面的反汇编代码也可以看出它的逻辑跟 nt!_except_handler3 基本上一致。
函数代码不长。主要分为两个大分支,一个分支处理异常,一个分支处理展开(我用横线分隔开了)。
异常解决的代码负责遍历 SCOPE_TABLE,依次调用 SCOPE_TABLE::ScopeRecord.HandlerAddress 代表的 EXCEPT_FILTER,并针对返回值做出相应的处理:
1. 返回 EXCEPTION_CONTINUE_EXECUTION,说明异常已经被 EXCEPT_FILTER 修复。返回 ExceptionContinueExecution。
2. 返回 EXCEPTION_CONTINUE_SEARCH,继续遍历下一个 ScopeRecord。
3. 返回 EXCEPTION_EXECUTE_HANDLER,说明当前 ScopeRecord.JumpTarget 代表的 EXCEPT_HANDLER 可以处理该异常。那么调用 RtlUnwindEx 进行展开。
熟悉 x86 的朋友可能会疑惑:在 x86 中 nt!_except_handler3 先进行全局展开,然后对本函数自身进行不完全的局部展开,最后执行 EXCEPT_HANDLER。而在 nt!__C_specific_handler 中却找不到执行 EXCEPT_HANDLER 的指令,这是怎么回事?
实际上,x64 对这个流程做了一些调整,EXCEPT_HANDLER 不是由 nt!__C_specific_handler 直接调用,而是作为参数传给 RtlUnwindEx,RtlUnwindEx 处理完展开之后才执行 EXCEPT_HANDLER。后续我们在讲展开的时候会看到具体的方法。
__C_specific_handler 的展开分支,是对 SCOPE_TABLE 进行展开,逻辑很简单,不多讲了。
更详细的信息,请参考上面反汇编代码中我附的注释。
另外还需要说一下 SCOPE_TABLE。
在 x86 中,遍历 scopetable 时是通过运行时动态改变的 EXCEPTION_REGISTRATION::trylevel 来确定应该首先遍历哪一个 scopetable_entry。而 x64 中没有等同于 trylevel 的数据,有的朋友可能会说“SCOPE_TABLE 中不是有每个 __try 保护域的范围 RVA 吗?通过范围不就可以确定在哪个 __try 中触发了异常吗?”。
我们可以先试试这种方法,以下面这段伪码为例,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
1 VOID SehTest() 2 { 3 __try // 1 4 { 5 } 6 __except() 7 { 8 } 9 10 __try // 2 11 { 12 __try // 3 13 { 14 ... 15 } 16 __except() 17 { 18 } 19 } 20 __except() 21 { 22 } 23 24 __try // 4 25 { 26 } 27 __finally() 28 { 29 } 30} |
上述伪码中总共有4个 __try,按照 x86 中的方法,SCOPE_TABLE 的内容应该是顺序排列的,像这样:
SCOPE_TABLE::Count 等于4,
SCOPE_TABLE::ScopeRecord[0] 表示行3开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[1] 表示行10开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[2] 表示行12开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[3] 表示行24开始的 __try/__finally。
假设行14处触发了异常,遍历过程应该是这样,
首先检查 ScopeRecord[0],发现其范围不包含 EXCEPT_POINT,继续下一个,
开始检查 ScopeRecord[1],范围匹配了。
那是不是该把异常交给 ScopeRecord[1] 处理呢?
不是!从伪码中可以很明显的看出,行14触发的异常应该首先由行12开始的 __try/__except,即 ScopeRecord[1] 处理。
可见这种方法是行不通的。
MSC 通过调整 SCOPE_TABLE::ScopeRecord 的排列顺序来解决这个问题:
SCOPE_TABLE::Count 等于4,
SCOPE_TABLE::ScopeRecord[0] 表示行3开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[1] 表示行12开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[2] 表示行10开始的 __try/__except,
SCOPE_TABLE::ScopeRecord[3] 表示行24开始的 __try/__finally。
即对于嵌套的 __try/__except/__finally,ScopeRecord 的排列顺序是,最内层的 __try 排在前面,其次是次内层的,依次排到最外层。
这样就能正确的遍历 SCOPE_TABLE 了。
再用伪码完整的展示一下 SCOPE_TABLE 的布置,
SCOPE_TABLE::Count = 4。
SCOPE_TABLE::ScopeRecord[0].BeginAddress = RVA_L4; (行4的 RVA) // 第一个 __try
SCOPE_TABLE::ScopeRecord[0].EndAddress = RVA_L5;
SCOPE_TABLE::ScopeRecord[0].HandlerAddress = RVA_L6_EXCEPT_FILTER; (行6 __except 过滤代码首地址的 RVA)
SCOPE_TABLE::ScopeRecord[0].JumpTarget = RVA_L7;
SCOPE_TABLE::ScopeRecord[1].BeginAddress = RVA_L13; // 第三个 __try
SCOPE_TABLE::ScopeRecord[1].EndAddress = RVA_L15;
SCOPE_TABLE::ScopeRecord[1].HandlerAddress = RVA_L16_EXCEPT_FILTER;
SCOPE_TABLE::ScopeRecord[1].JumpTarget = RVA_L7;
SCOPE_TABLE::ScopeRecord[2].BeginAddress = RVA_L11; // 第二个 __try
SCOPE_TABLE::ScopeRecord[2].EndAddress = RVA_L19;
SCOPE_TABLE::ScopeRecord[2].HandlerAddress = RVA_L20_EXCEPT_FILTER;
SCOPE_TABLE::ScopeRecord[2].JumpTarget = RVA_L21;
SCOPE_TABLE::ScopeRecord[3].BeginAddress = RVA_L25; // 第四个 __try
SCOPE_TABLE::ScopeRecord[3].EndAddress = RVA_L26;
SCOPE_TABLE::ScopeRecord[3].HandlerAddress = RVA_L28;
SCOPE_TABLE::ScopeRecord[3].JumpTarget = 0;
我们再模拟一下 nt!__C_specific_handler 是如何遍历 SCOPE_TABLE 的:
1. 首先通过传入参数中的 pDispatcherContext->ControlPc 和 pDispatcherContext->ImageBase 计算出异常触发点的 RVA(简称 E_RVA)。参见 fffff800`008a430d 处的指令。
2. 通过 pDispatcherContext->ScopeIndex 确认是否需要遍历。如果需要遍历,则从它指定的 ScopeRecord 开始遍历。pDispatcherContext->ScopeIndex 一般都为0,只有返回 ExceptionCollidedUnwind 时,RtlDispatchException 才可能将它设置为其他值。
3. 通过比较 E_RVA 和 ScopeRecord[?].BeginAddress、ScopeRecord[?].EndAddress 来找到正确的处理函数,
首先 ScopeRecord[0] 范围不匹配,遍历下一个,
然后 ScopeRecord[1],发现范围匹配,并且是 __try/__except 组合。于是调用 ScopeRecord[1].HandlerAddress,假设它返回的是 EXCEPTION_CONTINUE_SEARCH,那么继续遍历下一个,
这次是 ScopeRecord[2],发现范围匹配,并且是 __try/__except 组合。于是调用 ScopeRecord[2].HandlerAddress,假设它返回的是 EXCEPTION_EXECUTE_HANDLER,那么说明找到了解决方案。
4. 调用 RtlUnwindEx,把 ScopeRecord[2].JumpTarget 对应的绝对地址作为 TargetIp 参数传给它。RtlUnwindEx 全局展开完毕后执行 TargetIp。
到这里,异常分发就大致讲述完毕。接下来是关于展开和解决的内容。
三、展开、解决
x64 中展开使用的函数有 RtlVirtualUnwind、RtlUnwindEx 和 RtlpExecuteHandlerForUnwind。其中 RtlVirtualUnwind 已经讲了,我们来看看余下的两个。
首先是 RtlUnwindEx,原型如下:
1
2
3
4
5
6
7
8
9
|
VOID RtlUnwindEx ( IN PVOID TargetFrame OPTIONAL, IN PVOID TargetIp OPTIONAL, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PVOID ReturnValue, IN PCONTEXT OriginalContext, IN PUNWIND_HISTORY_TABLE HistoryTable OPTIONAL ); |
参数分别是:
TargetFrame —— 目标帧,即最后一个需要展开的帧。
TargetIp —— 前面有讲过,它就是 ScopeRecord[?].JumpTarget 代表的地址,即 EXCEPT_HANDLER。
ExceptionRecord —— 异常信息。
ReturnValue —— 传递给 TargetIp 的返回值,分析过程中没发现它有什么用处。
OriginalContext —— 虽然被声明为 IN,但是实际上 RtlUnwindEx 并没有使用它内部的数据,
HistoryTable —— 用于加速查找 RUNTIME_FUNCTION。
主要功能是:
从自身开始展开,到 TargetFrame 停止。然后跳转到 TargetIp 继续执行。
流程:
1. 申请一个类型为 CONTEXT 的局部变量 l_Context,调用 RtlCaptureContext 将当前自身的环境复制到 l_Context。
2. 通过 RtlVirtualUnwind 对 l_Context 进行模拟展开,推动遍历。对每个遍历到的 UNWIND_INFO,检查 UNWIND_INFO::Flags 是否包含 UNW_FLAG_UHANDLER。如果包含,则调用 UNWIND_INFO::ExceptionHandler 进行局部展开。否则继续遍历下一个。
循环本步骤,直到展开到 TargetFrame,即到达解决异常的 EXCEPT_HANDLER 所在的函数(简称为 ExceptionHandlerFunc)了。
3. 这时 l_Context 内已经是从 RtlUnwindEx 完整展开到 EXCEPT_HANDLER 的环境了。即此时 l_Context 已经是 ExceptionHandlerFunc 的执行环境了。
调用 RtlRestoreContext,用 l_Context 替换当前线程的执行环境,于是就跳转到 EXCEPT_HANDLER 继续执行。
这样就完美的从触发异常的环境跳到了新的环境中。
这个过程有点类似这种手法:
1. 将某台机器的系统 ghost 到一个 bak.gho 文件。
2. 把 bak.gho 恢复到一台临时机器,然后对这台临时机器做一些调整。调整完毕后制作一个临时机器的 bak_mod.gho。
3. 将 bak_mod.gho 恢复到原来那台机器。
这个流程很重要,我手绘了一副图帮助理解,
伪码:
1
2
3
4
5
6
7
|
__try { ExRaiseStatus(STATUS_INVALID_PARAMETER); } __except(EXCEPTION_EXECUTE_HANDLER) { } |
图:
1. 异常解决流程,从 EXCEPT_POINT 到 RtlUnwindEx,途中已经找到能够解决该异常的 EXCEPT_HANDLER 了(以参数 TargetIp 表示),当前线程状态为 ThreadContext
+---------------------------------------+
| ...... |
| RtlRaiseStatus |调 |
| RtlDispatchException |用 |-> ThreadContext &
| RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler
| __C_specific_handler |向 |
| RtlUnwindEx v |
| |
+---------------------------------------+
2. RtlUnwindEx 将当前自身状态复制到 ThreadContext_Copy 中
+---------------------------------------+ +---------------------------------------+
| ...... | | ...... |
| RtlRaiseStatus |调 | | RtlRaiseStatus |调 |
| RtlDispatchException |用 |-> ThreadContext & | RtlDispatchException |用 |-> ThreadContext_Copy &
| RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler | RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler
| __C_specific_handler |向 | | __C_specific_handler |向 |
| RtlUnwindEx v | | RtlUnwindEx v |
| | | |
+---------------------------------------+ +---------------------------------------+
3. 用 ThreadContext_Copy 进行展开,一直展开到异常触发点停止。
+---------------------------------------+ +---------------------------------------+
| ..... | | ...... |
| RtlRaiseStatus |调 | | RtlRaiseStatus ^展 |
| RtlDispatchException |用 |-> ThreadContext | RtlDispatchException |开 |-> ThreadContext_Copy &
| RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler | RtlpExecuteHandlerForException |方 | TargetIp = ExceptionHandler
| __C_specific_handler |向 | | __C_specific_handler |向 |
| RtlUnwindEx v | | RtlUnwindEx | |
| | | |
+---------------------------------------+ +---------------------------------------+
4. 将 ThreadContext_Copy.Rip 设置为 TargetIp,以 ThreadContext_Copy 为参数调用 RtlpRestoreContext。跳转到 TargetIp 继续执行。
+---------------------------------------+
| ...... |
| EXCEPT_HANDLER |-> ThreadContext (ThreadContext.Rip = TargetIp)
| |
+---------------------------------------+
这样就完成了展开和执行 EXCEPT_HANDLER 的工作。
RtlpExecuteHandlerForUnwind 没有什么改变,原型依旧:
1
2
3
4
5
6
7
|
EXCEPTION_DISPOSITION RtlpExecuteHandlerForUnwind ( IN PEXCEPTION_RECORD ExceptionRecord, IN PVOID EstablisherFrame, IN OUT PCONTEXT ContextRecord, IN OUT PVOID DispatcherContext ); |
它会注册一个异常处理函数 RtlpUnwindHandle,当触发新异常时 RtlpUnwindHandler 会返回 ExceptionCollidedUnwind。关于 ExceptionCollidedUnwind,我们后面还会详细讲述。
RtlpExecuteHandlerForUnwind 的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:199。
RtlpUnwindHandle 的实现源码位于 $\WRK-v1.2\base\ntos\rtl\amd64\xcptmisc.asm:136。
到这里,我们讲完了展开的逻辑。接下来我们要讲述两个比较特殊的返回值: ExceptionNestedException 和 ExceptionCollidedUnwind。
四、ExceptionNestedException 和 ExceptionCollidedUnwind
之所以专门讲述这两个返回值,是因为在分析过程中,我感觉常规情况的 SEH 流程理解起来并不困难,难理解的是这两种不一般的情况。它们不一般之处在于:在处理异常的过程中又触发了新的异常。
先来讲一下这两个返回值的含义:
ExceptionNestedException —— 在异常分发过程中触发新的异常,比如执行 EXCEPT_FILTER 时触发异常。
ExceptionCollidedUnwind —— 在展开过程中触发新的异常,比如执行 FINALLY_HANDLER 时触发异常。
首先来讲讲 ExceptionNestedException,以如下伪码为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[font=Consolas][color= #000000] [/color][color=#800080]1 [/color][color=#000000]VOID SehTest[/color][color=#000080]() [ /color ][color= #800080]2 [/color][color=#000080]{ [ /color ][color= #800080]3 [/color][color=#000000]__try [ /color ][color= #800080]4 [/color][color=#000080]{ [ /color ][color= #800080]5 [/color][color=#000000]ExRaiseStatus[/color][color=#000080](); [ /color ][color= #800080]6 [/color][color=#000080]} [ /color ][color= #800080]7 [/color][color=#000000]__except[/color][color=#000080]([/color][color=#000000]ExRaiseStatus[/color][color=#000080](), [/color][color=#000000]EXCEPTION_CONTINUE_SEARCH[/color][color=#000080]) [/color][color=#008000]// EXCEPT_FILTER_1 [ /color ][color= #800080]8 [/color][color=#000080]{ [/color][color=#008000]// EXCEPT_HANDLER_1 [ /color ][color= #800080]9 [/color][color=#000080]} [ /color ][color= #800080]10 [/color][color=#000080]} [ /color ][color= #800080]11 12 [ /color ][color= #000000]VOID Caller[/color][color=#000080]() [ /color ][color= #800080]13 [/color][color=#000080]{ [ /color ][color= #800080]14 [/color][color=#000000]__try [ /color ][color= #800080]15 [/color][color=#000080]{ [ /color ][color= #800080]16 [/color][color=#000000]SehTest[/color][color=#000080](); [ /color ][color= #800080]17 [/color][color=#000080]} [ /color ][color= #800080]18 [/color][color=#000000]__except[/color][color=#000080]([/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) [/color][color=#008000]// EXCEPT_FILTER_2 [ /color ][color= #800080]19 [/color][color=#000080]{ [/color][color=#008000]// EXCEPT_HANDLER_2 [ /color ][color= #800080]20 [/color][color=#000080]} [ /color ][color= #800080]21 [/color][color=#000080]}[/color][/font] |
上述代码会两次触发异常,第一次是行5的 ExRaiseStatus,第二次是行7的 ExRaiseStatus。为了方便区分,我将它们分别标记为 EXCEPT_POINT#1、EXCEPT_POINT#2。
我们来看一下这两个异常的处理流程:
1. ExRaiseStatus#1 会创建保存 EXCEPT_POINT#1 触发时的状态 Context#1,并构建一个 EXCEPTION_RECORD,然后将他们作为参数来调用 RtlDispatchException#1。(注:这种方式的的触发点是 ExRaiseStatus 内部,而非 SehTest 的第5行。即Context#1 记录的异常触发点是 ExRaiseStatus#1 内部)
2. RtlDispatchException#1 根据 Context#1 首先找到 EXCEPT_POINT#1 所在函数 ExRaiseStatus#1 的 UNWIND_INFO,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。
3. RtlDispatchException#1 遍历到 SehTest,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_EHANDLER,于是调用其 UNWIND_INFO::ExceptionHandler,即 __C_specific_handler$2。__C_specific_handler$2 遍历 SehTest 的 SCOPE_TABLE,发现唯一的一个 ScopeRecord。于是执行 ScopeRecord[0].HandlerAddress,即行7的 SehTest::EXCEPT_FILTER_1#1。此时的调用栈如下(竖线后的内容为函数的 UNWIND_INFO::Flags 和 UNWIND_INFO::ExceptionHandler,其中 Flags 缩写为 E、U、N):
(1) Caller | E & __C_specific_handler$1
(2) SehTest | E & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$5
(6) __C_specific_handler$2 | N
(7) EXCEPT_FILTER_1#1 | N
4. EXCEPT_FILTER#1 触发 EXCEPT_POINT#2。同步骤1类似,ExRaiseStatus 会调用 RtlDispatchException#2,这个过程中同样会创建保存 EXCEPT_POINT#2 的状态,我们称之为 Context#2。
5. RtlDispatchException#2 根据 Context#2 找到了 EXCEPT_POINT#2 所在函数 ExRaiseStatus#2,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。
6. RtlDispatchException#2 遍历到 EXCEPT_FILTER_1#1,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。(注:EXCEPT_FILTER 虽然代码形式上从属于 SehTest 函数,但实际上它是一个单独的函数,有自己的 UNWIND_INFO,跟 SEH 的 UNWIND_INFO 并不是同一个)
7. RtlDispatchException#2 遍历到 __C_specific_handler$2、RltpExecuteHandlerForException#1、RtlDispatchException#1、ExRaiseStatus#1,这些函数要么被标记为 UNW_FLAG_NHANDLER,要么 UNWIND_INFO::ExceptionHandler 返回 ExcetpionNestedException,结果都是继续遍历,所以不再一一讲述。继续遍历下一个。
8. RtlDispatchException#2 遍历到 SehTest,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_EHANDLER,于是调用其 UNWIND_INFO::ExceptionRoutine,即 __C_specific_handler$2,发现范围匹配,于是调用 EXCEPT_FILTER_1#1,于是又触发异常,这次是 #3 异常。此时的调用栈如下:
(1) Caller | E & __C_specific_handler$1
(2) SehTest | E & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$5
(6) __C_specific_handler$2 | N
(7) EXCEPT_FILTER_1#1 | N
(8) ExRaiseStatus#2 | N
(9) RtlDispatchException#2 | N
(10) RtlpExecuteHandlerForException#2 | EU & RtlpExceptionHandler$10
(11) __C_specific_handler$2 | N
(12) EXCEPT_FILTER_1#2 | N
(13) ExRaiseStatus#3 | N
9. #3 异常的处理流程同 #2 的处理流程类似,也会再遍历到 __C_specific_handler$2,也会再调用 EXCEPT_FILTER_1,于是会触发 #4 异常、#5 异常等等。最终内核栈溢出,BSOD。
以上就是 ExceptionNestedException 的产生以及处理的流程。过程中还有一些细节操作,为了描述简洁,我没有在上述过程中一一讲述。
再来看看 ExceptionCollidedUnwind。它比 ExceptionNestedException 更复杂一些,我们以如下伪码为例,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
[font=Consolas][color= #000000] [/color][color=#800080]1 [/color][color=#000000]VOID SehTest[/color][color=#000080]() [ /color ][color= #800080]2 [/color][color=#000080]{ [ /color ][color= #800080]3 [/color][color=#000000]__try [ /color ][color= #800080]4 [/color][color=#000080]{ [ /color ][color= #800080]5 [/color][color=#000000]ExRaiseStatus[/color][color=#000080](); [ /color ][color= #800080]6 [/color][color=#000080]} [ /color ][color= #800080]7 [/color][color=#000000]__finally [ /color ][color= #800080]8 [/color][color=#000080]{ [/color][color=#008000]// FINALLY_HANDLER_1 [ /color ][color= #800080]9 [/color][color=#000000]ExRaiseStatus[/color][color=#000080](); [ /color ][color= #800080]10 [/color][color=#000080]} [ /color ][color= #800080]11 [/color][color=#000080]} [ /color ][color= #800080]12 13 [ /color ][color= #000000]VOID Caller[/color][color=#000080]() [ /color ][color= #800080]14 [/color][color=#000080]{ [ /color ][color= #800080]15 [/color][color=#000000]__try [ /color ][color= #800080]16 [/color][color=#000080]{ [ /color ][color= #800080]17 [/color][color=#000000]SehTest[/color][color=#000080](); [ /color ][color= #800080]18 [/color][color=#000080]} [ /color ][color= #800080]19 [/color][color=#000000]__except[/color][color=#000080]([/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) [/color][color=#008000]// EXCEPT_FILTER_2 [ /color ][color= #800080]20 [/color][color=#000080]{ [/color][color=#008000]// EXCEPT_HANDLER_2 [ /color ][color= #800080]21 [/color][color=#000080]} [ /color ][color= #800080]22 [/color][color=#000080]}[/color][/font] |
伪码中也有两处触发异常的地方,第一次在行5,第二次在行9。也分别标记为 EXCEPT_POINT#1 和 EXCEPT_POINT#2。处理流程:
1. ExRaiseStatus#1 创建保存 EXCEPT_POINT#1 的状态 Context#1,并构建一个 EXCEPTION_RECORD,然后将他们作为参数来调用 RtlDispatchException#1。
2. RtlDispatchException#1 根据 Context#1 开始遍历:
首先遍历到 EXCEPT_POINT#1 所在函数 ExRaiseStatus,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是遍历下一个。
然后遍历到 SehTest,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_UHANDLER,于是继续遍历下一个。
然后遍历到 Caller,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_EHANDLER,于是调用其 UNWIND_INFO::ExceptionRoutine 即 __C_specific_handler。__C_specific_handler 发现可以处理该异常,于是以 EXCEPT_HANDLER_2 为 TargetIp 参数调用 RtlUnwindEx。
3. RtlUnwindEx 从自身开始展开,展开到 SehTest,执行 FINALLY_HANDLER_1 时触发新异常。此时调用栈为:
(1) Caller | E & __C_specific_handler$1
(2) SehTest | U & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$5
(6) __C_specific_handler$1 | N
(7) RtlUnwindEx#1 | N
(8) RtlpExecuteHandlerForUnwind#1 | EU & RtlpUnwindHandler$8
(9) __C_specific_handler$2 | N
(10) FINALLY_HANDLER_1 | N
(11) ExRaiseStatus#2 | N
需要说明的是,调用栈(7) RtlUnwindEx 创建并初始化了一个 DISPATCHER_CONTEXT 变量(后续称之为 pDispatcherContextForUnwind),并作为参数传递给调用栈(8) RltpExecuteHandlerForUnwind,后者在调用(9) __C_specific_handler$2 之前将 pDispatcherContextForUnwind 保存在自己的栈中。此时 pDispatcherContextForUnwind 的内容表示的是调用栈(2) SehTest 的情况。后续步骤会用到这个 pDispatcherContextForUnwind。
4. (11) ExRaiseStatus#2 将 EXCEPT_POINT#2 触发时的状态保存到 Context#2,然后调用 RtlDispatchException#2 进行 EXCEPT_POINT#2 的分发。
5. RtlDispatchException#2 根据 Context#2 开始遍历,
首先遍历到 EXCEPT_POINT#2 所在函数 ExRaiseStatus#2,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是遍历下一个。
然后遍历到 FINALLY_HANDLER_1(同前面提到的 EXCEPT_FILTER 一样,FINALLY_HANDLER 实际上也是一个单独的函数,有自己的 RUNTIME_FUNCTION 和 UNWIND_INFO),发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是遍历下一个。
然后遍历到(9) __C_specific_handler$2,发现其 UNWIND_INFO::Flags 为 UNW_FLAG_NHANDLER,于是继续遍历。
然后遍历到(8) RtlpExecuteHandlerForUnwind#1,发现其 UNWIND_INFO::Flags 包含 UNW_FLAG_EHANDLER。于是调用其 UNWIND_INFO::ExceptionRoutine 即 RtlpUnwindHandler$8。RtlpUnwindHandler$8 会取出步骤3中所提到的 pDispatcherContextForUnwind,将其内容拷贝到自己的传出参数(参考 RtlpUnwindHandler 的函数原型)pDispatcherContext 中,然后返回 ExceptionCollidedUnwind。
6. RtlDispatchException#2 收到 ExceptionCollidedUnwind 后,从传回来的 pDispatchContext 中取出诸如 ControlPc、EstablisherFrame 等值(如步骤3所说,此时这些值反应的是(2) SehTest 的状态),用这些值来继续遍历。
首先遍历到(2) SehTest,调用 RtlpExecuteHandlerForException#2,进而调用 __C_specific_handler$2,但是发现 pDispatcherContext->ScopeIndex(步骤(9)中在调用(10) FINALLY_HANDLER_1 之前+1了,参考 __C_specific_handler 反汇编码)等于 pDispatcherContext->HandlerData->Count。于是继续遍历。
然后遍历到(1) Caller,调用 RtlpExecuteHandlerForException#2,进而调用 __C_specific_handler$1,发现它可以处理 #2 异常,于是以 EXCEPT_HANDLER#2 为 TargetIp 参数调用 RtlUnwindEx。此时调用栈如下:
(1) Caller | E & __C_specific_handler$1
(2) SehTest | U & __C_specific_handler$2
(3) ExRaiseStatus#1 | N
(4) RtlDispatchException#1 | N
(5) RtlpExecuteHandlerForException#1 | EU & RtlpExceptionHandler$6
(6) __C_specific_handler$1 | N
(7) RtlUnwindEx#1 | N
(8) RtlpExecuteHandlerForUnwind#1 | EU & RtlpUnwindHandler$8
(9) __C_specific_handler$2 | N
(10) FINALLY_HANDLER#1 | N
(11) ExRaiseStatus#2 | N
(12) RtlDispatchException#2 | N
(13) RtlpExecuteHandlerForException#2 | EU & RtlpExceptionHandler
(14) __C_specific_handler$1 | N
(15) RtlUnwindEx | N
7. (17) RtlUnwindEx 展开完毕后,通过 RtlRestoreContext 跳转到 EXCEPT_HANDLER#2 继续执行。
在上述过程中,我们可以发现,遍历过程中 RtlDispatchException 等系统函数被频繁遍历到。于是就有了前面提到的全局展开历史表 RtlpUnwindHistoryTable,这个表中存放着 RtlDispatchException、RtlUnwindEx 等函数的 RUNTIME_FUNCTION 和 ImageBase 信息,这样就不用每次都去解析 PE+ 中的 ExceptionDirectory,实现了加速。
到这里,我们就讲完了 x64 SEH 的实现。可以发现,x64 和 x86 的 SEH 思想或者说框架是一样的:
1. RtlDispatchException 和 RtlUnwindEx 都对异常注册信息进行遍历。前者是为了分发异常而遍历,后者是为了展开而遍历。
2. MSC 提供的异常处理函数按照“异常解决”和“展开”两个分支,对 SCOPE_TABLE/scopetable 进行遍历。前者是为了找到 EXCEPT_FILTER & EXCEPT_HANDLER,后者是为了找到 FINALLY_HANDLER。
3. RtlDispatchException 和 RtlUnwindEx 借助 MSC 提供的异常处理函数这个桥梁,配合处理异常。
主要的改变有两点:
1. RtlDispatchException 和 RtlUnwindEx 通过调用 RtlVirtualUnwind 推动遍历。
2. 所有的非叶函数都参与到 SEH,尽管大部分的函数都没有使用到 SEH。
以上我们主要讲述的是 x64 SEH 的内部实现。对于使用者,也有一个好消息,我们来看看,
C 代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[font=Consolas][color= #000000] VOID SehTest[/color][color=#000080]() { [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]ExRaiseStatus[/color][color=#000080]([/color][color=#000000]STATUS_INVALID_PARAMETER[/color][color=#000080]); [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __try \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } [ /color ][color= #000000]__except[/color][color=#000080](([/color][color=#000000]STATUS_INVALID_PARAMETER [/color][color=#000080]== [/color][color=#000000]GetExceptionCode[/color][color=#000080]()) ? [/color][color=#000000]EXCEPTION_CONTINUE_SEARCH [/color][color=#000080]: [/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) { [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __except \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } } [ /color ][color= #000000]__finally DbgPrint[ /color ][color= #000080]([/color][color=#808080]"%u [%s] __finally \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } }[ /color ][ /font ] |
反汇编码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[font=Consolas][color= #000000] kd[/color][color=#0A246A]> [/color][color=#000000]uf passthrough!SehTest PassThrough!SehTest[ /color ][color= #0A246A]: [ /color ][color= #000000]fffffadf`f1100020 [/color][color=#0A246A]sub [/color][color=#000000]rsp[/color][color=#0A246A],[/color][color=#800080]38h [ /color ][color= #000000]fffffadf`f1100024 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#800080]0C000000Dh [ /color ][color= #000000]fffffadf`f1100029 [/color][color=#0A246A]call qword ptr [[/color][color=#000000]PassThrough!_imp_ExRaiseStatus [/color][color=#0A246A]([/color][color=#000000]fffffadf`f1101050[/color][color=#0A246A])] [ /color ][color= #000000]fffffadf`f110002f [/color][color=#0A246A]lea [/color][color=#000000]r8[/color][color=#0A246A],[[/color][color=#000000]PassThrough! ?? [/color][color=#0A246A]::[/color][color=#000000]FNODOBFM[/color][color=#0A246A]::[/color][color=#000000]`string` [/color][color=#0A246A]([/color][color=#000000]fffffadf`f1100500[/color][color=#0A246A])] [ /color ][color= #000000]fffffadf`f1100036 [/color][color=#0A246A]mov [/color][color=#FF8000]edx[/color][color=#0A246A],[/color][color=#800080]39h [ /color ][color= #000000]fffffadf`f110003b [/color][color=#0A246A]lea [/color][color=#000000]rcx[/color][color=#0A246A],[[/color][color=#000000]PassThrough! ?? [/color][color=#0A246A]::[/color][color=#000000]FNODOBFM[/color][color=#0A246A]::[/color][color=#000000]`string` [/color][color=#0A246A]([/color][color=#000000]fffffadf`f1100540[/color][color=#0A246A])] [ /color ][color= #000000]fffffadf`f1100042 [/color][color=#0A246A]call [/color][color=#000000]PassThrough!DbgPrint [/color][color=#0A246A]([/color][color=#000000]fffffadf`f11004a6[/color][color=#0A246A]) [ /color ][color= #000000]fffffadf`f1100047 [/color][color=#0A246A]jmp [/color][color=#000000]PassThrough!SehTest[/color][color=#0A246A]+[/color][color=#800080]0x42 [/color][color=#0A246A]([/color][color=#000000]fffffadf`f1100062[/color][color=#0A246A]) [ /color ][color= #000000]PassThrough!SehTest[/color][color=#0A246A]+[/color][color=#800080]0x42[/color][color=#0A246A]: [ /color ][color= #000000]fffffadf`f1100062 [/color][color=#0A246A]lea [/color][color=#000000]r8[/color][color=#0A246A],[[/color][color=#000000]PassThrough! ?? [/color][color=#0A246A]::[/color][color=#000000]FNODOBFM[/color][color=#0A246A]::[/color][color=#000000]`string` [/color][color=#0A246A]([/color][color=#000000]fffffadf`f1100500[/color][color=#0A246A])] [ /color ][color= #000000]fffffadf`f1100069 [/color][color=#0A246A]mov [/color][color=#FF8000]edx[/color][color=#0A246A],[/color][color=#800080]42h [ /color ][color= #000000]fffffadf`f110006e [/color][color=#0A246A]lea [/color][color=#000000]rcx[/color][color=#0A246A],[[/color][color=#000000]PassThrough! ?? [/color][color=#0A246A]::[/color][color=#000000]FNODOBFM[/color][color=#0A246A]::[/color][color=#000000]`string` [/color][color=#0A246A]([/color][color=#000000]fffffadf`f1100570[/color][color=#0A246A])] [ /color ][color= #000000]fffffadf`f1100075 [/color][color=#0A246A]call [/color][color=#000000]PassThrough!DbgPrint [/color][color=#0A246A]([/color][color=#000000]fffffadf`f11004a6[/color][color=#0A246A]) [ /color ][color= #000000]fffffadf`f110007a [/color][color=#0A246A]add [/color][color=#000000]rsp[/color][color=#0A246A],[/color][color=#800080]38h [ /color ][color= #000000]fffffadf`f110007e ret[/color][/font] |
我们发现 SehTest 内部完全没有任何 SEH 的踪迹,不像 x86 那样会有创建、销毁 EXCEPTION_REGISTRATION_RECORD 和调整 EXCEPTION_REGISTRATION_RECORD::trylevel 等操作。
这样的好处就是使用者无需再担心性能损耗,可以放心大胆的使用 SEH 机制了。
附录一 boxr 扩展
为了方便自己分析,我写了一个简单的 windbg 扩展,提供了几个 x64 seh 常用功能:
!boxr.unwindinfo module-name unwindinfo_addr
功能:
用于查询指定 UNWIND_INFO 结构的详细信息。
参数说明:
module-name —— 待查询的 UNWIND_INFO 结构对应函数的模块名
unwindinfo_addr —— UNWIND_INFO 结构的绝对地址
!boxr.rtfn option module runtimefunction_addr
功能:
用于查询指定 RUNTIME_FUNCTION 结构的详细信息。(rtfn 表示 RunTime_FunctioN)
参数说明:
option —— 参数选项,目前支持两种:
/a 表示 module 参数为模块基地址
/n 表示 module 参数为模块名称
module —— RUNTIME_FUNCTION 结构对应函数所在的模块,具体形式根据 option 而定。
runtimefunction_addr —— 需要查询的 RUNTIME_FUNCTION 结构体的绝对地址。支持 @rax 操作方式,但不支持复杂的组合,比如 @rax+8。
使用的方法是:用 .extpath+ 命令将 boxr.dll 所在的目录添加到 windbg 的搜索路径中,然后就可以使用了。需要卸载时就 .unload。
简单说明一下这两个命令。
比如我们要查看下面这个函数的 UNWIND_INFO 信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
[font=Consolas][color= #000000] VOID SehTest[/color][color=#000080]() { [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __try \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } [ /color ][color= #000000]__except[/color][color=#000080]([/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) { [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __except \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]CollidedUnwind[/color][color=#000080](); } [ /color ][color= #000000]__except[/color][color=#000080]([/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) { [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __except \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } } [ /color ][color= #000000]__except[/color][color=#000080]([/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) { [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __except \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } } [ /color ][color= #000000]__finally [ /color ][color= #000080]{ [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __finally \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __try \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); [ /color ][color= #000000]__try [ /color ][color= #000080]{ [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __try \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } [ /color ][color= #000000]__finally [ /color ][color= #000080]{ [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __finally \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } } [ /color ][color= #000000]__except[/color][color=#000080]([/color][color=#000000]EXCEPTION_EXECUTE_HANDLER[/color][color=#000080]) { [ /color ][color= #000000]DbgPrint[/color][color=#000080]([/color][color=#808080]"%u [%s] __except \n"[/color][color=#000080], [/color][color=#000000]__LINE__[/color][color=#000080], [/color][color=#000000]__FILE__[/color][color=#000080]); } [ /color ][color= #0000FF]return[/color][color=#000080]; }[ /color ][ /font ] |
操作步骤:
1. 使用 .fnent 命令获得 SehTest 的基本信息,
kd> .fnent passthrough!SehTest
Debugger function entry 00000000`00758210 for:
(fffffadf`f135d080) PassThrough!SehTest | (fffffadf`f135d180) PassThrough!LeafTest
Exact matches:
PassThrough!SehTest (void)
BeginAddress = 00000000`00001080
EndAddress = 00000000`00001175
UnwindInfoAddress = 00000000`000026b8
Unwind info at fffffadf`f135e6b8, 10 bytes
version 1, flags 3, prolog 4, codes 1
handler routine: PassThrough!_C_specific_handler (fffffadf`f135d5de), data 6
00: offs 4, unwind op 2, op info 4 UWOP_ALLOC_SMALL.
2. 使用 !boxr.unwindinfo 查询详细信息,
kd> !boxr.unwindinfo passthrough fffffadf`f135e6b8
_UNWIND_INFO for fffffadff135e6b8
Flags:
EU
ExceptionRoutine:
PassThrough!_C_specific_handler (fffffadf`f135d5de)
ScopeTable:
Count: 6
ScopeRecord[0] (fffffadff135e6c8)
BeginAddress:
PassThrough!SehTest+0x4 (fffffadf`f135d084)
EndAddress:
PassThrough!SehTest+0x1e (fffffadf`f135d09e)
HandlerAddress:
PassThrough!SehTest$filt$0 (fffffadf`f135d8a0)
JumpTarget:
PassThrough!SehTest+0x1e (fffffadf`f135d09e)
[省略中间3个 ScopeRecord 成员]
ScopeRecord[5] (fffffadff135e718)
BeginAddress:
PassThrough!SehTest+0x8b (fffffadf`f135d10b)
EndAddress:
PassThrough!SehTest+0xd7 (fffffadf`f135d157)
HandlerAddress:
PassThrough!SehTest$filt$5 (fffffadf`f135d960)
JumpTarget:
PassThrough!SehTest+0xd7 (fffffadf`f135d157)
!boxr.rtfn 的用法也类似,比如:
kd> !box.rtfn /n passThrough @rax
_RUNTIME_FUNCTION for fffffadff1113000
BeginAddress:
PassThrough!CollidedUnwind (fffffadf`f1110020)
EndAddress:
PassThrough!CollidedUnwind+0x38 (fffffadf`f1110058)
UnwindData:
fffffadff1111688
_UNWIND_INFO for fffffadff1111688
Flags:
U
ExceptionRoutine:
PassThrough!_C_specific_handler (fffffadf`f11104ee)
ScopeTable:
Count: 1
ScopeRecord[0] (fffffadff1111698)
BeginAddress:
PassThrough!CollidedUnwind+0x4 (fffffadf`f1110024)
EndAddress:
PassThrough!CollidedUnwind+0x10 (fffffadf`f1110030)
HandlerAddress:
PassThrough!CollidedUnwind$fin$0 (fffffadf`f1110750)
JumpTarget:
0
需要说明的是,我写这个扩展的目的仅仅是为了分析 x64 SEH 过程中能轻松的查看相关数据结构的详细信息,所以并没有在这个扩展上花很多时间。其代码是从 MS 例子代码的基础上增加了我需要的功能。应该有一些 BUG,但是对我来说不重要,已经满足我的需要了。源码也放在附件里,方便分析的朋友根据自己的需要进行修改。
另外有一个疑问:我编译的 x64 wrk1.2 内核无法对 .c代码进行源码调试,对 .asm 代码倒是可以,这是为什么?我看了一下编译选项,没看出什么猫腻。有经验的朋友分享一下吧,感谢 :-)
附录二 RtlUnwindEx 的反汇编代码和注释
由于无法源码调试,只好把它反汇编出来加上注释……
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
|
[font=Consolas][color= #000000] VOID RtlUnwindEx [ /color ][color= #000080]( [ /color ][color= #008000]/* rcx */ [/color][color=#000000]IN PVOID pEstablisherFrame OPTIONAL[/color][color=#000080], [ /color ][color= #008000]/* rdx */ [/color][color=#000000]IN PVOID pJumpTargetIp OPTIONAL[/color][color=#000080], [ /color ][color= #008000]/* r8 */ [/color][color=#000000]IN PEXCEPTION_RECORD pExceptionRecord OPTIONAL[/color][color=#000080], [ /color ][color= #008000]/* r9 */ [/color][color=#000000]IN PVOID ReturnValue[/color][color=#000080], [ /color ][color= #008000]/* rsp+28 */ [/color][color=#000000]IN PCONTEXT pOriginalContext[/color][color=#000080], [ /color ][color= #008000]/* rsp+30 */ [/color][color=#000000]IN PUNWIND_HISTORY_TABLE pHistoryTable OPTIONAL [ /color ][color= #000080]);[/color][/font] [font=Consolas][color= #000000] kd[/color][color=#0A246A]> [/color][color=#000000]uf nt!RtlUnwindEx nt!RtlUnwindEx[ /color ][color= #0A246A]: [ /color ][color= #000000]fffff800`[/color][color=#800080]00891e70 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]20h[/color][color=#0A246A]],[/color][color=#000000]r9 fffff800`[ /color ][color= #800080]00891e75 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]18h[/color][color=#0A246A]],[/color][color=#000000]r8 fffff800`[ /color ][color= #800080]00891e7a [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]10h[/color][color=#0A246A]],[/color][color=#000000]rdx fffff800`[ /color ][color= #800080]00891e7f [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rsp fffff800`[ /color ][color= #800080]00891e82 [/color][color=#0A246A]sub [/color][color=#000000]rsp[/color][color=#0A246A],[/color][color=#800080]678h [ /color ][color= #000000]fffff800`[/color][color=#800080]00891e89 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]8[/color][color=#0A246A]],[/color][color=#000000]rbx fffff800`[ /color ][color= #800080]00891e8d [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]10h[/color][color=#0A246A]],[/color][color=#000000]rbp fffff800`[ /color ][color= #800080]00891e91 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]18h[/color][color=#0A246A]],[/color][color=#000000]rsi fffff800`[ /color ][color= #800080]00891e95 [/color][color=#0A246A]mov [/color][color=#000000]rsi[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A0h[/color][color=#0A246A]] [/color][color=#008000]; rsi = pOriginalContext [ /color ][color= #000000]fffff800`[/color][color=#800080]00891e9d [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]20h[/color][color=#0A246A]],[/color][color=#000000]rdi fffff800`[ /color ][color= #800080]00891ea1 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]28h[/color][color=#0A246A]],[/color][color=#000000]r12 fffff800`[ /color ][color= #800080]00891ea5 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]40h[/color][color=#0A246A]],[/color][color=#000000]r15 fffff800`[ /color ][color= #800080]00891ea9 [/color][color=#0A246A]mov [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rcx fffff800`[ /color ][color= #800080]00891eac [/color][color=#0A246A]mov [/color][color=#000000]r15[/color][color=#0A246A],[/color][color=#000000]rdx fffff800`[ /color ][color= #800080]00891eaf [/color][color=#0A246A]lea [/color][color=#000000]rdx[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]] [/color][color=#008000]; rsp+40 为 l_HighLimit [ /color ][color= #000000]fffff800`[/color][color=#800080]00891eb4 [/color][color=#0A246A]lea [/color][color=#000000]rcx[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]50h[/color][color=#0A246A]] [/color][color=#008000]; rsp+50 为 l_LowLimit [ /color ][color= #000000]fffff800`[/color][color=#800080]00891eb9 [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]r8 fffff800`[ /color ][color= #800080]00891ebc [/color][color=#0A246A]mov [/color][color=#000000]rdi[/color][color=#0A246A],[/color][color=#000000]rsi fffff800`[ /color ][color= #800080]00891ebf [/color][color=#0A246A]lea [/color][color=#000000]r12[/color][color=#0A246A],[[/color][color=#000000]rax[/color][color=#0A246A]-[/color][color=#800080]518h[/color][color=#0A246A]] [/color][color=#008000]; r12 = &l_Context [ /color ][color= #000000]fffff800`[/color][color=#800080]00891ec6 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlpGetStackLimits [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00890da0[/color][color=#0A246A]) [ /color ][color= #000000]fffff800`[/color][color=#800080]00891ecb [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]rsi fffff800`[ /color ][color= #800080]00891ece [/color][color=#0A246A]call [/color][color=#000000]nt!RtlCaptureContext [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008bd150[/color][color=#0A246A]) [ /color ][color= #000000]fffff800`[/color][color=#800080]00891ed3 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A8h[/color][color=#0A246A]] [/color][color=#008000]; rax = pHistoryTable [ /color ][color= #000000]fffff800`[/color][color=#800080]00891edb [/color][color=#0A246A]test [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rax [ /color ][color= #0A246A]< [/color][color=#000000]fffff800`[/color][color=#800080]00891ede [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x74 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891ee4[/color][color=#0A246A]) [ /color ][color= #000000]. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x70[/color][color=#0A246A]: [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891ee0 [/color][color=#0A246A]mov byte ptr [[/color][color=#000000]rax[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]],[/color][color=#800080]1 [/color][color=#008000]; pHistoryTable->Search = UNWIND_HISTORY_TABLE_GLOBAL [ /color ][color= #000000]. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x74[/color][color=#0A246A]: > [ /color ][color= #000000]fffff800`[/color][color=#800080]00891ee4 [/color][color=#0A246A]xor [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#FF8000]ecx [ /color ][color= #000000]fffff800`[/color][color=#800080]00891ee6 [/color][color=#0A246A]test [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rbx [/color][color=#008000]; 判断 pExceptionRecord 是否为 NULL [ /color ][color= #0A246A]< [/color][color=#000000]fffff800`[/color][color=#800080]00891ee9 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0xbc [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891f2c[/color][color=#0A246A]) [ /color ][color= #000000]. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x7b[/color][color=#0A246A]: [ /color ][color= #000000]. [/color][color=#008000]; pExceptionRecord 等于 NULL [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891eeb [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsi[/color][color=#0A246A]+[/color][color=#800080]0F8h[/color][color=#0A246A]] [/color][color=#008000]; rax = pOriginalContext->Rip [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891ef2 [/color][color=#0A246A]lea [/color][color=#000000]rbx[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0C0h[/color][color=#0A246A]] [/color][color=#008000]; rbx = &l_ExceptionRecord [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891efa [/color][color=#0A246A]mov dword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0C0h[/color][color=#0A246A]],[/color][color=#800080]0C0000027h [/color][color=#008000]; l_ExceptionRecord.ExceptionCode = STATUS_UNWIND (0xC0000027) [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f05 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0D0h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; l_ExceptionRecord.ExceptionAddress = pOriginalContext->Rip [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f0d [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A8h[/color][color=#0A246A]] [/color][color=#008000]; rax = pHistoryTable [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f15 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]690h[/color][color=#0A246A]],[/color][color=#000000]rbx [/color][color=#008000]; [r8-home] = &l_ExceptionRecord ???? [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f1d [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0C8h[/color][color=#0A246A]],[/color][color=#000000]rcx [/color][color=#008000]; l_ExceptionRecord.ExceptionRecord = NULL [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f25 [/color][color=#0A246A]mov dword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0D8h[/color][color=#0A246A]],[/color][color=#FF8000]ecx [/color][color=#008000]; l_ExceptionRecord.NumberParameters = 0 [ /color ][color= #000000]. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0xbc[/color][color=#0A246A]: > [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f2c [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rbx = &[rcx-home] [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f34 [/color][color=#0A246A]mov [/color][color=#FF8000]esi[/color][color=#0A246A],[/color][color=#800080]2 [/color][color=#008000]; l_ExceptionFlags(esi) = EXCEPTION_UNWINDING (2) [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f39 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#800080]6 [/color][color=#008000]; ecx = EXCEPTION_EXIT_UNWIND (6) [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f3e [/color][color=#0A246A]test [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rbp [/color][color=#008000]; 判断 pEstablisherFrame 是否为 NULL [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f41 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]648h[/color][color=#0A246A]],[/color][color=#000000]r13 [/color][color=#008000]; 保存 r13 [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f49 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]640h[/color][color=#0A246A]],[/color][color=#000000]r14 [/color][color=#008000]; 保存 r14 [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f51 [/color][color=#0A246A]cmove [/color][color=#FF8000]esi[/color][color=#0A246A],[/color][color=#FF8000]ecx [/color][color=#008000]; if (NULL == pEstablisherFrame) { l_ExceptionFlags = EXCEPTION_EXIT_UNWIND (6) } [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f54 [/color][color=#0A246A]xchg [/color][color=#FF8000]ax[/color][color=#0A246A],[/color][color=#FF8000]ax [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f58 [/color][color=#0A246A]xchg [/color][color=#FF8000]ax[/color][color=#0A246A],[/color][color=#FF8000]ax [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f5c [/color][color=#0A246A]xchg [/color][color=#FF8000]ax[/color][color=#0A246A],[/color][color=#FF8000]ax [ /color ][color= #000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0xf0[/color][color=#0A246A]: > [ /color ][color= #000000]fffff800`[/color][color=#800080]00891f60 [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]0F8h[/color][color=#0A246A]] [/color][color=#008000]; r13 = pOriginalContext->Rip [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f67 [/color][color=#0A246A]lea [/color][color=#000000]rdx[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]60h[/color][color=#0A246A]] [/color][color=#008000]; rdx = &l_pImageBase [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f6c [/color][color=#0A246A]mov [/color][color=#000000]r8[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; r8 = pHistoryTable [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f6f [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]r13 . fffff800`[ /color ][color= #800080]00891f72 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]68h[/color][color=#0A246A]],[/color][color=#000000]r13 . fffff800`[ /color ][color= #800080]00891f77 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlLookupFunctionEntry [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00890e60[/color][color=#0A246A]) [ /color ][color= #000000]. [/color][color=#008000]; l_pFunctionEntry = RtlLookupFunctionEntry(pOriginalContext->Rip, [ /color ][color= #000000]. [/color][color=#008000]; &l_pImageBase, [ /color ][color= #000000]. [/color][color=#008000]; pHistoryTable) [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f7c [/color][color=#0A246A]test [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; 判断 l_pFunctionEntry (eax) 是否为 NULL [ /color ][color= #000000]. fffff800`[/color][color=#800080]00891f7f [/color][color=#0A246A]mov [/color][color=#000000]r14[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; r14 = l_pFunctionEntry [ /color ][color= #0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00891f82 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x3ab [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]0089221b[/color][color=#0A246A]) [ /color ][color= #000000]. . . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x118[/color][color=#0A246A]: [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891f88 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rdx = pOriginalContext [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891f8b [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]r12 [/color][color=#008000]; rcx = &l_Context [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891f8e [/color][color=#0A246A]call [/color][color=#000000]nt!RtlpCopyContext [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891080[/color][color=#0A246A]) [ /color ][color= #000000]. . [/color][color=#008000]; RtlpCopyContext(&l_Context, pOriginalContext) [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891f93 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]60h[/color][color=#0A246A]] [/color][color=#008000]; rdx = l_pImageBase [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891f98 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]38h[/color][color=#0A246A]],[/color][color=#800080]0 [/color][color=#008000]; _ARG_8 = 0 [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fa1 [/color][color=#0A246A]lea [/color][color=#000000]rax[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rax = &[rcx-home],这里被用作局部变量 l_pEstablisherFrame 空间 [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fa9 [/color][color=#0A246A]mov [/color][color=#000000]r9[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; r9 = l_pFunctionEntry [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fac [/color][color=#0A246A]mov [/color][color=#000000]r8[/color][color=#0A246A],[/color][color=#000000]r13 [/color][color=#008000]; r8 = pOriginalContext->Rip [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891faf [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]30h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG7 = &l_pEstablisherFrame [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fb4 [/color][color=#0A246A]lea [/color][color=#000000]rax[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]58h[/color][color=#0A246A]] [/color][color=#008000]; rax = &l_pHandlerData [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fb9 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#800080]2 [/color][color=#008000]; ecx = UNW_FLAG_UHANDLER (2) [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fbe [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]28h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG_6 = &l_pHandlerData [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fc3 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]20h[/color][color=#0A246A]],[/color][color=#000000]r12 [/color][color=#008000]; _ARG_5 = &l_Context [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fc8 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlVirtualUnwind [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891380[/color][color=#0A246A]) [ /color ][color= #000000]. . [/color][color=#008000]; l_pExceptionRoutine = RtlVirtualUnwind(UNW_FLAG_UHANDLER, [ /color ][color= #000000]. . [/color][color=#008000]; l_pImageBase, [ /color ][color= #000000]. . [/color][color=#008000]; pOriginalContext->Rip, [ /color ][color= #000000]. . [/color][color=#008000]; l_pFunctionEntry, [ /color ][color= #000000]. . [/color][color=#008000]; &l_Context, [ /color ][color= #000000]. . [/color][color=#008000]; &l_pHandlerData, [ /color ][color= #000000]. . [/color][color=#008000]; &l_pEstablisherFrame, [ /color ][color= #000000]. . [/color][color=#008000]; NULL); [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fcd [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rbx = l_pEstablisherFrame [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fd5 [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; rcx = l_pExceptionRoutine [ /color ][color= #000000]. . fffff800`[/color][color=#800080]00891fd8 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]],[/color][color=#000000]rax . . fffff800`[ /color ][color= #800080]00891fdd [/color][color=#0A246A]test [/color][color=#FF8000]bl[/color][color=#0A246A],[/color][color=#800080]7 [/color][color=#008000]; 检查 l_pEstablisherFrame 是否对齐 [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00891fe0 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x431 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922a1[/color][color=#0A246A]) [ /color ][color= #000000].. . .. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x176[/color][color=#0A246A]: [ /color ][color= #000000].. . fffff800`[/color][color=#800080]00891fe6 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]50h[/color][color=#0A246A]] [/color][color=#008000]; cmp l_pEstablisherFrame, l_LowLimit [ /color ][color= #000000]..[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00891feb [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x184 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891ff4[/color][color=#0A246A]) [ /color ][color= #000000]... . ... . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x17d[/color][color=#0A246A]: [ /color ][color= #000000]... . fffff800`[/color][color=#800080]00891fed [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]] [/color][color=#008000]; cmp l_pEstablisherFrame, l_HighLimit [ /color ][color= #000000]...[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00891ff2 [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x1d3 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892043[/color][color=#0A246A]) [ /color ][color= #000000].... . .... . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x184[/color][color=#0A246A]: [ /color ][color= #000000].... . [/color][color=#008000]; 检查 l_pEstablisherFrame 是否合法 [ /color ][color= #000000]..[/color][color=#0A246A]>[/color][color=#000000]. . fffff800`[/color][color=#800080]00891ff4 [/color][color=#0A246A]mov [/color][color=#FF8000]cl[/color][color=#0A246A],byte ptr [/color][color=#FF8000]gs[/color][color=#0A246A]:[[/color][color=#800080]20DEh[/color][color=#0A246A]] [/color][color=#008000]; cl = _KPCR->DpcRoutineActive [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00891ffc [/color][color=#0A246A]test [/color][color=#FF8000]cl[/color][color=#0A246A],[/color][color=#FF8000]cl [/color][color=#008000]; 判断当前是否在执行 DPC [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]00891ffe [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x431 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922a1[/color][color=#0A246A]) [/color][color=#008000]; 如果是在执行 DPC 则失败??? [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x194[/color][color=#0A246A]: [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892004 [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]] [/color][color=#008000]; rcx = l_HighLimit [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892009 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rcx[/color][color=#0A246A]-[/color][color=#800080]28h[/color][color=#0A246A]] [/color][color=#008000]; rax = l_KernelStackCtrl->Previous.StackBase [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089200d [/color][color=#0A246A]test [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; 判断 l_KernelStackCtrl->Previous.StackBase 是否为 NULL [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]00892010 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x431 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922a1[/color][color=#0A246A]) [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1a6[/color][color=#0A246A]: [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892016 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rcx[/color][color=#0A246A]-[/color][color=#800080]20h[/color][color=#0A246A]] [/color][color=#008000]; rdx = l_KernelStackCtrl->Previous.StackLimit [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089201a [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rbx = l_pEstablisherFrame [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892022 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rdx [/color][color=#008000]; cmp l_pEstablisherFrame, l_KernelStackCtrl->Previous.StackLimit [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]00892025 [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x431 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922a1[/color][color=#0A246A]) [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1bb[/color][color=#0A246A]: [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089202b [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp l_pEstablisherFrame, l_KernelStackCtrl->Previous.StackBase [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]0089202e [/color][color=#0A246A]jae [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x431 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922a1[/color][color=#0A246A]) [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1c4[/color][color=#0A246A]: [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892034 [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]] [/color][color=#008000]; rcx = l_pExceptionRoutine [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892039 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]50h[/color][color=#0A246A]],[/color][color=#000000]rdx [/color][color=#008000]; l_LowLimit = l_KernelStackCtrl->Previous.StackLimit [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089203e [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; l_HighLimit = l_KernelStackCtrl->Previous.StackBase [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1d3[/color][color=#0A246A]: [ /color ][color= #000000].. [/color][color=#0A246A]> [/color][color=#000000]. fffff800`[/color][color=#800080]00892043 [/color][color=#0A246A]test [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rbp [/color][color=#008000]; 判断 pEstablisherFrame 是否为 NULL [ /color ][color= #000000].. [/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00892046 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x1e1 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892051[/color][color=#0A246A]) [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1d8[/color][color=#0A246A]: [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892048 [/color][color=#0A246A]cmp [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rbx [/color][color=#008000]; cmp pEstablisherFrame, l_pEstablisherFrame [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]0089204b [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x431 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922a1[/color][color=#0A246A]) [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1e1[/color][color=#0A246A]: [ /color ][color= #000000].. [/color][color=#0A246A]> [/color][color=#000000]. fffff800`[/color][color=#800080]00892051 [/color][color=#0A246A]test [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]rcx [/color][color=#008000]; 判断 l_pExceptionRoutine 是否为 NULL [ /color ][color= #000000].. [/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00892054 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x39b [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]0089220b[/color][color=#0A246A]) [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x1ea[/color][color=#0A246A]: [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089205a [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]58h[/color][color=#0A246A]] [/color][color=#008000]; r13 = l_pHandlerData [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089205f [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]90h[/color][color=#0A246A]],[/color][color=#000000]r15 [/color][color=#008000]; [rsp+90] = pJumpTargetIp [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]00892067 [/color][color=#0A246A]xor [/color][color=#000000]r15d[/color][color=#0A246A],[/color][color=#000000]r15d .. . . fffff800`[ /color ][color= #800080]0089206a [/color][color=#0A246A]xchg [/color][color=#FF8000]ax[/color][color=#0A246A],[/color][color=#FF8000]ax [ /color ][color= #000000].. . . fffff800`[/color][color=#800080]0089206d [/color][color=#0A246A]xchg [/color][color=#FF8000]ax[/color][color=#0A246A],[/color][color=#FF8000]ax [ /color ][color= #000000].. . . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x200[/color][color=#0A246A]: [ /color ][color= #000000].. . [/color][color=#0A246A]> [/color][color=#000000]. fffff800`[/color][color=#800080]00892070 [/color][color=#0A246A]cmp [/color][color=#000000]rbp[/color][color=#0A246A],[/color][color=#000000]rbx [/color][color=#008000]; cmp pEstablisherFrame, l_pEstablisherFrame [ /color ][color= #000000].. .[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]00892073 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x208 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892078[/color][color=#0A246A]) [ /color ][color= #000000].. .. . . .. .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x205[/color][color=#0A246A]: [ /color ][color= #000000].. .. . . fffff800`[/color][color=#800080]00892075 [/color][color=#0A246A]or [/color][color=#FF8000]esi[/color][color=#0A246A],[/color][color=#800080]20h [/color][color=#008000]; l_ExceptionFlags |= EXCEPTION_TARGET_UNWIND (0x20) [ /color ][color= #000000].. .. . . .. .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x208[/color][color=#0A246A]: [ /color ][color= #000000].. .[/color][color=#0A246A]> [/color][color=#000000]. . fffff800`[/color][color=#800080]00892078 [/color][color=#0A246A]mov [/color][color=#000000]r10[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]690h[/color][color=#0A246A]] [/color][color=#008000]; r10 = &l_ExceptionRecord [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]00892080 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]698h[/color][color=#0A246A]] [/color][color=#008000]; rax = ReturnValue [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]00892088 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0A0h[/color][color=#0A246A]],[/color][color=#000000]rcx [/color][color=#008000]; l_DispatcherContext.LanguageHandler = l_pExceptionRoutine [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]00892090 [/color][color=#0A246A]mov dword ptr [[/color][color=#000000]r10[/color][color=#0A246A]+[/color][color=#800080]4[/color][color=#0A246A]],[/color][color=#FF8000]esi [/color][color=#008000]; l_ExceptionRecord.ExceptionFlags = l_ExceptionFlags [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]00892094 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]78h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; pOriginalContext->Rax = ReturnValue [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]00892098 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]68h[/color][color=#0A246A]] [/color][color=#008000]; rax = pOriginalContext->Rip [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]0089209d [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]70h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; l_DispatcherContext.ControlPc = pOriginalContext->Rip [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920a2 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]60h[/color][color=#0A246A]] [/color][color=#008000]; rax = l_pImageBase [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920a7 [/color][color=#0A246A]lea [/color][color=#000000]r9[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]70h[/color][color=#0A246A]] [/color][color=#008000]; r9 = &l_DispatcherContext [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920ac [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]78h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; l_DispatcherContext.ImageBase = l_pImageBase [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920b1 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A8h[/color][color=#0A246A]] [/color][color=#008000]; rax = pHistoryTable [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920b9 [/color][color=#0A246A]mov [/color][color=#000000]r8[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; r8 = pOriginalContext [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920bc [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rbx [/color][color=#008000]; rdx = l_pEstablisherFrame [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920bf [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]r10 [/color][color=#008000]; rcx = &l_ExceptionRecord [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920c2 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]80h[/color][color=#0A246A]],[/color][color=#000000]r14 [/color][color=#008000]; l_DispatcherContext.FunctionEntry = l_pFunctionEntry [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920ca [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0B0h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; l_DispatcherContext.HistoryTable = pHistoryTable [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920d2 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]88h[/color][color=#0A246A]],[/color][color=#000000]rbx [/color][color=#008000]; l_DispatcherContext.EstablisherFrame = l_pEstablisherFrame [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920da [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]98h[/color][color=#0A246A]],[/color][color=#000000]rdi [/color][color=#008000]; l_DispatcherContext.ContextRecord = pOriginalContext [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920e2 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0A8h[/color][color=#0A246A]],[/color][color=#000000]r13 [/color][color=#008000]; l_DispatcherContext.HandlerData = l_pHandlerData [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920ea [/color][color=#0A246A]mov dword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0B8h[/color][color=#0A246A]],[/color][color=#000000]r15d [/color][color=#008000]; l_DispatcherContext.ScopeIndex = 0 [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920f2 [/color][color=#0A246A]and [/color][color=#FF8000]esi[/color][color=#0A246A],[/color][color=#800080]0FFFFFF9Fh [/color][color=#008000]; l_ExceptionFlags &= ~(EXCEPTION_TARGET_UNWIND|EXCEPTION_COLLIDED_UNWIND) [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920f5 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlpExecuteHandlerForUnwind [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008bd9d0[/color][color=#0A246A]) [ /color ][color= #000000].. . . . [/color][color=#008000]; RtlpExecuteHandlerForUnwind(&l_ExceptionRecord, [ /color ][color= #000000].. . . . [/color][color=#008000]; l_pEstablisherFrame, [ /color ][color= #000000].. . . . [/color][color=#008000]; pOriginalContext, [ /color ][color= #000000].. . . . [/color][color=#008000]; &l_DispatcherContext); [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008920fa [/color][color=#0A246A]dec [/color][color=#FF8000]eax [ /color ][color= #000000].. .[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]008920fc [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x368 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008921d8[/color][color=#0A246A]) [/color][color=#008000]; 如果返回 ExceptionContinueSearch 则跳转 [ /color ][color= #000000].. .. . . .. .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x292[/color][color=#0A246A]: [ /color ][color= #000000].. .. . . fffff800`[/color][color=#800080]00892102 [/color][color=#0A246A]cmp [/color][color=#FF8000]eax[/color][color=#0A246A],[/color][color=#800080]2 [/color][color=#008000]; cmp eax, ExceptionCollidedUnwind (3 - 1) [ /color ][color= #000000].. ..[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]00892105 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x426 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892296[/color][color=#0A246A]) [ /color ][color= #000000].. ... . . .. ... . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x29b[/color][color=#0A246A]: [ /color ][color= #000000].. ... . . [/color][color=#008000]; ExceptionCollidedUnwind 的情况 [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089210b [/color][color=#0A246A]mov [/color][color=#000000]r8[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]70h[/color][color=#0A246A]] [/color][color=#008000]; r8 = l_DispatcherContext.ControlPc [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892110 [/color][color=#0A246A]mov [/color][color=#000000]r10[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]78h[/color][color=#0A246A]] [/color][color=#008000]; r10 = l_DispatcherContext.ImageBase [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892115 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]98h[/color][color=#0A246A]] [/color][color=#008000]; rdx = l_DispatcherContext.ContextRecord [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089211d [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A0h[/color][color=#0A246A]] [/color][color=#008000]; rcx = pOriginalContext [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892125 [/color][color=#0A246A]mov [/color][color=#000000]r14[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]80h[/color][color=#0A246A]] [/color][color=#008000]; r14 = l_DispatcherContext.FunctionEntry [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089212d [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]68h[/color][color=#0A246A]],[/color][color=#000000]r8 .. ... . . fffff800`[ /color ][color= #800080]00892132 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]60h[/color][color=#0A246A]],[/color][color=#000000]r10 .. ... . . fffff800`[ /color ][color= #800080]00892137 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlpCopyContext [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891080[/color][color=#0A246A]) [ /color ][color= #000000].. ... . . [/color][color=#008000]; RtlpCopyContext(pOriginalContext, l_DispatcherContext.ContextRecord); [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089213c [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rcx [/color][color=#008000]; rdx = pOriginalContext [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089213f [/color][color=#0A246A]mov [/color][color=#000000]rdi[/color][color=#0A246A],[/color][color=#000000]rcx [/color][color=#008000]; rdi = pOriginalContext [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892142 [/color][color=#0A246A]lea [/color][color=#000000]rcx[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]160h[/color][color=#0A246A]] [/color][color=#008000]; rcx = &l_Context [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089214a [/color][color=#0A246A]lea [/color][color=#000000]r12[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]160h[/color][color=#0A246A]] [/color][color=#008000]; r12 = &l_Context [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892152 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlpCopyContext [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891080[/color][color=#0A246A]) [ /color ][color= #000000].. ... . . [/color][color=#008000]; RtlpCopyContext(&l_Context, pOriginalContext); [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892157 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]38h[/color][color=#0A246A]],[/color][color=#800080]0 [/color][color=#008000]; _ARG_8 = NULL [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892160 [/color][color=#0A246A]lea [/color][color=#000000]rax[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rax = &l_pEstablisherFrame [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892168 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]30h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG_7 = &l_pEstablisherFrame [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089216d [/color][color=#0A246A]lea [/color][color=#000000]rax[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]58h[/color][color=#0A246A]] [/color][color=#008000]; rax = &l_pHandlerData [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892172 [/color][color=#0A246A]mov [/color][color=#000000]r9[/color][color=#0A246A],[/color][color=#000000]r14 [/color][color=#008000]; r9 = l_DispatcherContext.FunctionEntry [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892175 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]28h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG_6 = &l_pHandlerData [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089217a [/color][color=#0A246A]lea [/color][color=#000000]rax[/color][color=#0A246A],[[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]160h[/color][color=#0A246A]] [/color][color=#008000]; rax = &l_Context [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892182 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]r10 [/color][color=#008000]; rdx = l_DispatcherContext.ImageBase [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892185 [/color][color=#0A246A]xor [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#FF8000]ecx [/color][color=#008000]; ecx = UNW_FLAG_NHANDLER (0) [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892187 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]20h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; _ARG_5 = &l_Context [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]0089218c [/color][color=#0A246A]call [/color][color=#000000]nt!RtlVirtualUnwind [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891380[/color][color=#0A246A]) [ /color ][color= #000000].. ... . . [/color][color=#008000]; RtlVirtualUnwind(UNW_FLAG_NHANDLER, [ /color ][color= #000000].. ... . . [/color][color=#008000]; l_DispatcherContext.ImageBase, [ /color ][color= #000000].. ... . . [/color][color=#008000]; l_DispatcherContext.ControlPc, [ /color ][color= #000000].. ... . . [/color][color=#008000]; l_DispatcherContext.FunctionEntry, [ /color ][color= #000000].. ... . . [/color][color=#008000]; &l_Context, [ /color ][color= #000000].. ... . . [/color][color=#008000]; &l_pHandlerData, [ /color ][color= #000000].. ... . . [/color][color=#008000]; &l_pEstablisherFrame, [ /color ][color= #000000].. ... . . [/color][color=#008000]; NULL); [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892191 [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]88h[/color][color=#0A246A]] [/color][color=#008000]; rbx = l_DispatcherContext.EstablisherFrame [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]00892199 [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0A0h[/color][color=#0A246A]] [/color][color=#008000]; rcx = l_DispatcherContext.LanguageHandler [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921a1 [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0A8h[/color][color=#0A246A]] [/color][color=#008000]; r13 = l_DispatcherContext.HandlerData [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921a9 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0B0h[/color][color=#0A246A]] [/color][color=#008000]; rax = l_DispatcherContext.HistoryTable [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921b1 [/color][color=#0A246A]mov [/color][color=#000000]r15d[/color][color=#0A246A],dword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]0B8h[/color][color=#0A246A]] [/color][color=#008000]; r15d = l_DispatcherContext.ScopeIndex [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921b9 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]],[/color][color=#000000]rbx [/color][color=#008000]; l_pEstablisherFrame = l_DispatcherContext.EstablisherFrame [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921c1 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]],[/color][color=#000000]rcx [/color][color=#008000]; l_pExceptionRoutine = l_DispatcherContext.LanguageHandler [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921c6 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]58h[/color][color=#0A246A]],[/color][color=#000000]r13 [/color][color=#008000]; l_pHandlerData = l_DispatcherContext.HandlerData [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921cb [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A8h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; pHistoryTable = l_DispatcherContext.HistoryTable [ /color ][color= #000000].. ... . . fffff800`[/color][color=#800080]008921d3 [/color][color=#0A246A]or [/color][color=#FF8000]esi[/color][color=#0A246A],[/color][color=#800080]40h [/color][color=#008000]; l_ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND (40) [ /color ][color= #000000].. ...[/color][color=#0A246A]< [/color][color=#000000]. . fffff800`[/color][color=#800080]008921d6 [/color][color=#0A246A]jmp [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x382 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008921f2[/color][color=#0A246A]) [ /color ][color= #000000].. .... . . .. .... . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x368[/color][color=#0A246A]: [ /color ][color= #000000].. .[/color][color=#0A246A]>[/color][color=#000000].. . . fffff800`[/color][color=#800080]008921d8 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rbp [/color][color=#008000]; cmp l_DispatcherContext.EstablisherFrame, pEstablisherFrame [ /color ][color= #000000].. . ..[/color][color=#0A246A]<[/color][color=#000000]. . fffff800`[/color][color=#800080]008921db [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x37d [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008921ed[/color][color=#0A246A]) [ /color ][color= #000000].. . .... . .. . .... . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x36d[/color][color=#0A246A]: [ /color ][color= #000000].. . .... . fffff800`[/color][color=#800080]008921dd [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]] [/color][color=#008000]; rcx = l_pExceptionRoutine [ /color ][color= #000000].. . .... . fffff800`[/color][color=#800080]008921e2 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rax = pOriginalContext [ /color ][color= #000000].. . .... . fffff800`[/color][color=#800080]008921e5 [/color][color=#0A246A]mov [/color][color=#000000]rdi[/color][color=#0A246A],[/color][color=#000000]r12 [/color][color=#008000]; rdi = &l_Context [ /color ][color= #000000].. . .... . fffff800`[/color][color=#800080]008921e8 [/color][color=#0A246A]mov [/color][color=#000000]r12[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; r12 = pOriginalContext [ /color ][color= #000000].. . .v.. . fffff800`[/color][color=#800080]008921eb [/color][color=#0A246A]jmp [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x382 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008921f2[/color][color=#0A246A]) [ /color ][color= #000000].. . .... . .. . .... . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x37d[/color][color=#0A246A]: [ /color ][color= #000000].. . ..[/color][color=#0A246A]>[/color][color=#000000]. . fffff800`[/color][color=#800080]008921ed [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]48h[/color][color=#0A246A]] [/color][color=#008000]; rcx = l_pExceptionRoutine [ /color ][color= #000000].. . .. . . .. . .. . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x382[/color][color=#0A246A]: [ /color ][color= #000000].. . .[/color][color=#0A246A]> [/color][color=#000000]. . fffff800`[/color][color=#800080]008921f2 [/color][color=#0A246A]test [/color][color=#000000]sil[/color][color=#0A246A],[/color][color=#800080]40h [/color][color=#008000]; test sil, EXCEPTION_COLLIDED_UNWIND (40) [ /color ][color= #000000].. . . [/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]008921f6 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x200 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892070[/color][color=#0A246A]) [ /color ][color= #000000].. . . . .. . . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x38c[/color][color=#0A246A]: [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]008921fc [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]68h[/color][color=#0A246A]] [/color][color=#008000]; r13 = pOriginalContext->Rip [ /color ][color= #000000].. . . . fffff800`[/color][color=#800080]00892201 [/color][color=#0A246A]mov [/color][color=#000000]r15[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]688h[/color][color=#0A246A]] [/color][color=#008000]; r15 = pJumpTargetIp [ /color ][color= #000000].. . .[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00892209 [/color][color=#0A246A]jmp [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x3c7 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892237[/color][color=#0A246A]) [ /color ][color= #000000].. . .. . .. . .. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x39b[/color][color=#0A246A]: [ /color ][color= #000000].. [/color][color=#0A246A]> [/color][color=#000000].. . fffff800`[/color][color=#800080]0089220b [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rbp [/color][color=#008000]; cmp l_DispatcherContext.EstablisherFrame, pEstablisherFrame [ /color ][color= #000000].. .[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]0089220e [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x3c7 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892237[/color][color=#0A246A]) [ /color ][color= #000000].. .. . .. .. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3a0[/color][color=#0A246A]: [ /color ][color= #000000].. .. . fffff800`[/color][color=#800080]00892210 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rax = &l_Context [ /color ][color= #000000].. .. . fffff800`[/color][color=#800080]00892213 [/color][color=#0A246A]mov [/color][color=#000000]rdi[/color][color=#0A246A],[/color][color=#000000]r12 [/color][color=#008000]; rdi = pOriginalContext [ /color ][color= #000000].. .. . fffff800`[/color][color=#800080]00892216 [/color][color=#0A246A]mov [/color][color=#000000]r12[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; r12 = &l_Context [ /color ][color= #000000].. .[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00892219 [/color][color=#0A246A]jmp [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x3c7 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892237[/color][color=#0A246A]) [ /color ][color= #000000].. .. . .. .. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3ab[/color][color=#0A246A]: >[ /color ][color= #000000]. .. . fffff800`[/color][color=#800080]0089221b [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]98h[/color][color=#0A246A]] [/color][color=#008000]; rcx = pOriginalContext->Rsp [ /color ][color= #000000]. .. . fffff800`[/color][color=#800080]00892222 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rcx[/color][color=#0A246A]] [/color][color=#008000]; rax = pOriginalContext->Rsp[0] [ /color ][color= #000000]. .. . fffff800`[/color][color=#800080]00892225 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]0F8h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; pOriginalContext->Rip = pOriginalContext->Rsp[0] [ /color ][color= #000000]. .. . fffff800`[/color][color=#800080]0089222c [/color][color=#0A246A]lea [/color][color=#000000]rax[/color][color=#0A246A],[[/color][color=#000000]rcx[/color][color=#0A246A]+[/color][color=#800080]8[/color][color=#0A246A]] [/color][color=#008000]; rax = pOriginalContext->Rsp + 8 [ /color ][color= #000000]. .. . fffff800`[/color][color=#800080]00892230 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]98h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; pOriginalContext->Rsp = pOriginalContext->Rsp + 8 (跳过返回值) [ /color ][color= #000000]. .. . . .. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3c7[/color][color=#0A246A]: [ /color ][color= #000000]. .[/color][color=#0A246A]> [/color][color=#000000]. fffff800`[/color][color=#800080]00892237 [/color][color=#0A246A]test [/color][color=#FF8000]bl[/color][color=#0A246A],[/color][color=#800080]7 [/color][color=#008000]; 检查 l_DispatcherContext.EstablisherFrame 是否对齐 [ /color ][color= #000000]. .[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]0089223a [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x444 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922b4[/color][color=#0A246A]) [ /color ][color= #000000]. .. . . .. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3cc[/color][color=#0A246A]: [ /color ][color= #000000]. .. . fffff800`[/color][color=#800080]0089223c [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]50h[/color][color=#0A246A]] [/color][color=#008000]; cmp l_DispatcherContext.EstablisherFrame, l_LowLimit [ /color ][color= #000000]. ..[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00892241 [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x3da [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]0089224a[/color][color=#0A246A]) [ /color ][color= #000000]. ... . . ... . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3d3[/color][color=#0A246A]: [ /color ][color= #000000]. ... . fffff800`[/color][color=#800080]00892243 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]] [/color][color=#008000]; cmp l_DispatcherContext.EstablisherFrame, l_HighLimit [ /color ][color= #000000]. ...[/color][color=#0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]00892248 [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x414 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892284[/color][color=#0A246A]) [ /color ][color= #000000]. .... . . .... . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3da[/color][color=#0A246A]: [ /color ][color= #000000]. ..[/color][color=#0A246A]>[/color][color=#000000]. . fffff800`[/color][color=#800080]0089224a [/color][color=#0A246A]mov [/color][color=#FF8000]al[/color][color=#0A246A],byte ptr [/color][color=#FF8000]gs[/color][color=#0A246A]:[[/color][color=#800080]20DEh[/color][color=#0A246A]] [/color][color=#008000]; al = _KPCR->DpcRoutineActive [ /color ][color= #000000]. .. . . fffff800`[/color][color=#800080]00892252 [/color][color=#0A246A]test [/color][color=#FF8000]al[/color][color=#0A246A],[/color][color=#FF8000]al [ /color ][color= #000000]. .. .[/color][color=#0A246A]<[/color][color=#000000]. fffff800`[/color][color=#800080]00892254 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x43c [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922ac[/color][color=#0A246A]) [ /color ][color= #000000]. .. ... . .. ... nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3e6[/color][color=#0A246A]: [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]00892256 [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]] [/color][color=#008000]; rcx = l_HighLimit [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]0089225b [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rcx[/color][color=#0A246A]-[/color][color=#800080]28h[/color][color=#0A246A]] [/color][color=#008000]; rax = l_KernelStackCtrl->Previous.StackBase [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]0089225f [/color][color=#0A246A]test [/color][color=#000000]rax[/color][color=#0A246A],[/color][color=#000000]rax . .. .[ /color ][color= #0A246A]<[/color][color=#000000]. fffff800`[/color][color=#800080]00892262 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x43c [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922ac[/color][color=#0A246A]) [ /color ][color= #000000]. .. ... . .. ... nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x3f4[/color][color=#0A246A]: [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]00892264 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rcx[/color][color=#0A246A]-[/color][color=#800080]20h[/color][color=#0A246A]] [/color][color=#008000]; rdx = l_KernelStackCtrl->Previous.StackLimit [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]00892268 [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rbx = l_pEstablisherFrame [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]00892270 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rdx [/color][color=#008000]; cmp l_pEstablisherFrame, l_KernelStackCtrl->Previous.StackLimit [ /color ][color= #000000]. .[/color][color=#0A246A]< [/color][color=#000000]... fffff800`[/color][color=#800080]00892273 [/color][color=#0A246A]jb [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x444 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922b4[/color][color=#0A246A]) [ /color ][color= #000000]. .. ... . .. ... nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x405[/color][color=#0A246A]: [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]00892275 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rax [/color][color=#008000]; cmp l_pEstablisherFrame, l_KernelStackCtrl->Previous.StackBase [ /color ][color= #000000]. .[/color][color=#0A246A]< [/color][color=#000000]... fffff800`[/color][color=#800080]00892278 [/color][color=#0A246A]jae [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x444 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922b4[/color][color=#0A246A]) [ /color ][color= #000000]. .. ... . .. ... nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x40a[/color][color=#0A246A]: [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]0089227a [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]50h[/color][color=#0A246A]],[/color][color=#000000]rdx [/color][color=#008000]; l_LowLimit = l_KernelStackCtrl->Previous.StackLimit [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]0089227f [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]40h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; l_HighLimit = l_KernelStackCtrl->Previous.StackBase [ /color ][color= #000000]. .. ... . .. ... nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x414[/color][color=#0A246A]: [ /color ][color= #000000]. .. [/color][color=#0A246A]>[/color][color=#000000].. fffff800`[/color][color=#800080]00892284 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rbp [/color][color=#008000]; cmp l_pEstablisherFrame, pEstablisherFrame [ /color ][color= #000000]. .. [/color][color=#0A246A]<[/color][color=#000000].. fffff800`[/color][color=#800080]00892287 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x449 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922b9[/color][color=#0A246A]) [ /color ][color= #000000]. .. ... . .. ... nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x419[/color][color=#0A246A]: [ /color ][color= #000000]. .. ... fffff800`[/color][color=#800080]00892289 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]6A8h[/color][color=#0A246A]] [/color][color=#008000]; rax = pHistoryTable [ /color ][color= #000000]. .. ..[/color][color=#0A246A]^ [/color][color=#000000]fffff800`[/color][color=#800080]00892291 [/color][color=#0A246A]jmp [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0xf0 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00891f60[/color][color=#0A246A]) [ /color ][color= #000000]. .. .. . .. .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x426[/color][color=#0A246A]: [ /color ][color= #000000]. [/color][color=#0A246A]>[/color][color=#000000]. .. fffff800`[/color][color=#800080]00892296 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#800080]0C0000026h [/color][color=#008000]; ecx = STATUS_INVALID_DISPOSITION [ /color ][color= #000000]. . .. fffff800`[/color][color=#800080]0089229b [/color][color=#0A246A]call [/color][color=#000000]nt!RtlRaiseStatus [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00889df0[/color][color=#0A246A]) [ /color ][color= #000000]. . .. fffff800`[/color][color=#800080]008922a0 [/color][color=#0A246A]int [/color][color=#800080]3 [ /color ][color= #000000]. . .. . . .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x431[/color][color=#0A246A]: > [ /color ][color= #000000]. .. fffff800`[/color][color=#800080]008922a1 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#800080]0C0000028h [/color][color=#008000]; ecx = STATUS_BAD_STACK [ /color ][color= #000000]. .. fffff800`[/color][color=#800080]008922a6 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlRaiseStatus [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00889df0[/color][color=#0A246A]) [ /color ][color= #000000]. .. fffff800`[/color][color=#800080]008922ab [/color][color=#0A246A]int [/color][color=#800080]3 [ /color ][color= #000000]. .. . .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x43c[/color][color=#0A246A]: [ /color ][color= #000000]. .[/color][color=#0A246A]> [/color][color=#000000]fffff800`[/color][color=#800080]008922ac [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]680h[/color][color=#0A246A]] [/color][color=#008000]; rbx = l_pEstablisherFrame [ /color ][color= #000000]. . . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x444[/color][color=#0A246A]: > [ /color ][color= #000000]. fffff800`[/color][color=#800080]008922b4 [/color][color=#0A246A]cmp [/color][color=#000000]rbx[/color][color=#0A246A],[/color][color=#000000]rbp [/color][color=#008000]; cmp l_pEstablisherFrame, pEstablisherFrame [ /color ][color= #0A246A]< [/color][color=#000000]. fffff800`[/color][color=#800080]008922b7 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x479 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922e9[/color][color=#0A246A]) [ /color ][color= #000000]. . . . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x449[/color][color=#0A246A]: [ /color ][color= #000000]. [/color][color=#0A246A]> [/color][color=#000000]fffff800`[/color][color=#800080]008922b9 [/color][color=#0A246A]mov [/color][color=#000000]rax[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]698h[/color][color=#0A246A]] [/color][color=#008000]; rax = ReturnValue [ /color ][color= #000000]. fffff800`[/color][color=#800080]008922c1 [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]690h[/color][color=#0A246A]] [/color][color=#008000]; rbx = pExceptionRecord [ /color ][color= #000000]. fffff800`[/color][color=#800080]008922c9 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]78h[/color][color=#0A246A]],[/color][color=#000000]rax [/color][color=#008000]; pOriginalContext->Rax, ReturnValue [ /color ][color= #000000]. fffff800`[/color][color=#800080]008922cd [/color][color=#0A246A]cmp dword ptr [[/color][color=#000000]rbx[/color][color=#0A246A]],[/color][color=#800080]80000029h [/color][color=#008000]; cmp pExceptionRecord->ExceptionCode, STATUS_UNWIND_CONSOLIDATE [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]fffff800`[/color][color=#800080]008922d3 [/color][color=#0A246A]je [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x46c [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922dc[/color][color=#0A246A]) [ /color ][color= #000000].. .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x465[/color][color=#0A246A]: [ /color ][color= #000000].. fffff800`[/color][color=#800080]008922d5 [/color][color=#0A246A]mov qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]0F8h[/color][color=#0A246A]],[/color][color=#000000]r15 [/color][color=#008000]; pOriginalContext->Rip, pJumpTargetIp [ /color ][color= #000000].. .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x46c[/color][color=#0A246A]: [ /color ][color= #000000].[/color][color=#0A246A]> [/color][color=#000000]fffff800`[/color][color=#800080]008922dc [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rbx [/color][color=#008000]; rdx = pExceptionRecord [ /color ][color= #000000]. fffff800`[/color][color=#800080]008922df [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rcx = pOriginalContext [ /color ][color= #000000]. fffff800`[/color][color=#800080]008922e2 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlRestoreContext [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008bd290[/color][color=#0A246A]) [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]fffff800`[/color][color=#800080]008922e7 [/color][color=#0A246A]jmp [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x4a0 [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00892310[/color][color=#0A246A]) [ /color ][color= #000000].. .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x479[/color][color=#0A246A]: >[ /color ][color= #000000]. fffff800`[/color][color=#800080]008922e9 [/color][color=#0A246A]cmp [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rdi[/color][color=#0A246A]+[/color][color=#800080]0F8h[/color][color=#0A246A]] [/color][color=#008000]; pOriginalContext->Rip [ /color ][color= #000000].[/color][color=#0A246A]< [/color][color=#000000]fffff800`[/color][color=#800080]008922f0 [/color][color=#0A246A]jne [/color][color=#000000]nt!RtlUnwindEx[/color][color=#0A246A]+[/color][color=#800080]0x48d [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008922fd[/color][color=#0A246A]) [ /color ][color= #000000].. .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x482[/color][color=#0A246A]: [ /color ][color= #000000].. fffff800`[/color][color=#800080]008922f2 [/color][color=#0A246A]mov [/color][color=#FF8000]ecx[/color][color=#0A246A],[/color][color=#800080]0C00000FFh [/color][color=#008000]; ecx = STATUS_BAD_FUNCTION_TABLE [ /color ][color= #000000].. fffff800`[/color][color=#800080]008922f7 [/color][color=#0A246A]call [/color][color=#000000]nt!RtlRaiseStatus [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]00889df0[/color][color=#0A246A]) [ /color ][color= #000000].. fffff800`[/color][color=#800080]008922fc [/color][color=#0A246A]int [/color][color=#800080]3 [ /color ][color= #000000].. .. nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x48d[/color][color=#0A246A]: [ /color ][color= #000000].[/color][color=#0A246A]> [/color][color=#000000]fffff800`[/color][color=#800080]008922fd [/color][color=#0A246A]mov [/color][color=#000000]rcx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]690h[/color][color=#0A246A]] [/color][color=#008000]; rcx = pExceptionRecord [ /color ][color= #000000]. fffff800`[/color][color=#800080]00892305 [/color][color=#0A246A]xor [/color][color=#000000]r8d[/color][color=#0A246A],[/color][color=#000000]r8d [/color][color=#008000]; r8d = 0 [ /color ][color= #000000]. fffff800`[/color][color=#800080]00892308 [/color][color=#0A246A]mov [/color][color=#000000]rdx[/color][color=#0A246A],[/color][color=#000000]rdi [/color][color=#008000]; rdx = pOriginalContext [ /color ][color= #000000]. fffff800`[/color][color=#800080]0089230b [/color][color=#0A246A]call [/color][color=#000000]nt!ZwRaiseException [/color][color=#0A246A]([/color][color=#000000]fffff800`[/color][color=#800080]008b9b80[/color][color=#0A246A]) [ /color ][color= #000000]. [/color][color=#008000]; ZwRaiseException(pExceptionRecord, pOriginalContext, FALSE); [ /color ][color= #000000]. . nt!RtlUnwindEx[ /color ][color= #0A246A]+[/color][color=#800080]0x4a0[/color][color=#0A246A]: > [ /color ][color= #000000]fffff800`[/color][color=#800080]00892310 [/color][color=#0A246A]mov [/color][color=#000000]r15[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]638h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892318 [/color][color=#0A246A]mov [/color][color=#000000]r14[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]640h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892320 [/color][color=#0A246A]mov [/color][color=#000000]r13[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]648h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892328 [/color][color=#0A246A]mov [/color][color=#000000]r12[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]650h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892330 [/color][color=#0A246A]mov [/color][color=#000000]rdi[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]658h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892338 [/color][color=#0A246A]mov [/color][color=#000000]rsi[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]660h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892340 [/color][color=#0A246A]mov [/color][color=#000000]rbp[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]668h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892348 [/color][color=#0A246A]mov [/color][color=#000000]rbx[/color][color=#0A246A],qword ptr [[/color][color=#000000]rsp[/color][color=#0A246A]+[/color][color=#800080]670h[/color][color=#0A246A]] [ /color ][color= #000000]fffff800`[/color][color=#800080]00892350 [/color][color=#0A246A]add [/color][color=#000000]rsp[/color][color=#0A246A],[/color][color=#800080]678h [ /color ][color= #000000]fffff800`[/color][color=#800080]00892357 [/color][color=#000000]ret[/color][/font] |
参考资料
[1] wrk 源码
[2] Improving Automated Analysis of Windows x64 Binaries, skape
[3] Programming against the x64 exception handling support, Skywing
[4] Exceptional Behavior - x64 Structured Exception Handling, The NT Insider