简介

KiUserExceptionDispatcher 是SEH分发器的用户模式的负责函数。当一个异常发生的时候,该异常将生成一个异常事件,内核检查该异常是否是由于执行用户模式代码导致的。如果是这样的话,内核修改栈上的trap frame,因此当内核从中断或者异常返回的时候,线程将从KiUserExceptionDispatcher 函数执行而不是导致异常的指令。内核将另外安排几个参数(一个 PCONTEXT 和一个 PEXCEPTION_RECORD),它们描述了异常发生时机器的状态,而且在线程返回到用户模式之前被传递给KiUserExceptionDispatcher 函数。
一旦内核模式栈展开,而且指令转移到用户模式的KiUserExceptionDispatcher
函数,该函数通过调用一个本地的函数RtlDispatchException来处理异常,RtlDispatchException是用户模式异常处理逻辑中的核心函数。如果异常被成功分发的话(也就是SHE
链表中有一个函数宣称可以处理该异常), RtlDispatchException调用RtlRestoreContext
函数实现最终的用户模式上下文的设置,该函数只是加载给定的上下文中的寄存器到到处理器的体系结构执行状态中。 否则,通过调用 NtRaiseException
函数,异常重新被提交到内核模式,这是最后一次机会了。在内核停止该进程之前,这给了用户模式调试器(如果有的话)一个处理该异常的最后机会。
(内核内部在安排KiUserExceptionDispatcher执行之前给了用户模式调试器和内核模式调试器第一次处理该异常的机会)

原型和伪码

改函数位于模块ntdll.dll,声明如下:

VOID KiUserExceptionDispatcher(__in PEXCEPTION_RECORD ExceptionRecord,__in PCONTEXT ContextRecord)

下面是汇编代码:

.text:7C958550 ; __stdcall KiUserExceptionDispatcher(x, x)
.text:7C958550 public _KiUserExceptionDispatcher@8
.text:7C958550 _KiUserExceptionDispatcher@8 proc near ; DATA XREF: .text:off_7C94C618o
.text:7C958550
.text:7C958550 var_C = dword ptr -0Ch
.text:7C958550 var_8 = dword ptr -
.text:7C958550 var_4 = dword ptr -
.text:7C958550 arg_0 = dword ptr
.text:7C958550
.text:7C958550 mov ecx, [esp+arg_0] ; CONTEXT
.text:7C958554 mov ebx, [esp+] ; EXCEPTION_RECORD
.text:7C958557 push ecx
.text:7C958558 push ebx
.text:7C958559 call _RtlDispatchException@8 ; RtlDispatchException(x,x)
.text:7C95855E or al, al
.text:7C958560 jz short loc_7C95856E ;如果返回FALSE
.text:7C958562 pop ebx ; ebx = EXCEPTION_RECORD
.text:7C958563 pop ecx ; ecx = CONTEXT
.text:7C958564 push
.text:7C958566 push ecx ; ecx = CONTEXT
.text:7C958567 call _ZwContinue@8 ;已经处理好了,按照CONTEXT 中设置的值继续执行就好了,此函数不返回
.text:7C95856C jmp short loc_7C958579
.text:7C95856E ; ---------------------------------------------------------------------------
.text:7C95856E
.text:7C95856E loc_7C95856E: ; 没有找到处理函数,提交一个异常->FirstChance = FALSE
.text:7C95856E pop ebx ; ebx = EXCEPTION_RECORD
.text:7C95856F pop ecx ; ecx = CONTEXT
.text:7C958570 push
.text:7C958572 push ecx
.text:7C958573 push ebx
.text:7C958574 call _ZwRaiseException@12 ; ZwRaiseException(x,x,x)
.text:7C958574 _KiUserExceptionDispatcher@8 endp ; sp-analysis failed
.text:7C958574
.text:7C958579 ; ---------------------------------------------------------------------------
.text:7C958579 retn .text:0000000078EA124A public KiUserExceptionDispatcher
.text:0000000078EA124A KiUserExceptionDispatcher proc near ; DATA XREF: .rdata:0000000078F54BB0o
.text:0000000078EA124A ; .rdata:off_78F56298o
.text:0000000078EA124A cld
.text:0000000078EA124B mov rax, cs:Wow64PrepareForException
.text:0000000078EA1252 test rax, rax
.text:0000000078EA1255 jz short loc_78EA1266
.text:0000000078EA1257 mov rcx, rsp
.text:0000000078EA125A add rcx, 4F0h ; rcx 为第一个参数ExceptionRecord 0x4F0 为其CONTEXT 的大小
.text:0000000078EA1261 mov rdx, rsp ; rdx 为第二个参数,指向CONTEXT 结构
.text:0000000078EA1264 call rax ; Wow64PrepareForException
.text:0000000078EA1266
.text:0000000078EA1266 loc_78EA1266:
.text:0000000078EA1266 mov rcx, rsp
.text:0000000078EA1269 add rcx, 4F0h ;ExceptionRecord
.text:0000000078EA1270 mov rdx, rsp ;ContextRecord
.text:0000000078EA1273 call RtlDispatchException ;分发该异常RtlDispatchException(ExceptionRecord,ContextRecord);
.text:0000000078EA1278 test al, al
.text:0000000078EA127A jz short loc_78EA1288
.text:0000000078EA127C mov rcx, rsp ; ContextRecord
.text:0000000078EA127F xor edx, edx ; ExceptionRecord-->0
.text:0000000078EA1281 call RtlRestoreContext
.text:0000000078EA1286 jmp short loc_78EA129D
.text:0000000078EA1288 ; ---------------------------------------------------------------------------
.text:0000000078EA1288
.text:0000000078EA1288 loc_78EA1288:
.text:0000000078EA1288 mov rcx, rsp
.text:0000000078EA128B add rcx, 4F0h
.text:0000000078EA1292 mov rdx, rsp
.text:0000000078EA1295 xor r8b, r8b
.text:0000000078EA1298 call ZwRaiseException ;ZwRaiseException(ExceptionRecord,ContextRecord,FALSE);
.text:0000000078EA129D
.text:0000000078EA129D loc_78EA129D:
.text:0000000078EA129D mov ecx, eax
.text:0000000078EA129F call RtlRaiseStatus ; RtlRaiseStatus(上面的函数的返回值);
.text:0000000078EA12A4 nop
.text:0000000078EA12A5 jmp short $+
.text:0000000078EA12A7 ; ---------------------------------------------------------------------------
.text:0000000078EA12A7
.text:0000000078EA12A7 loc_78EA12A7:
.text:0000000078EA12A7 nop
.text:0000000078EA12A7 KiUserExceptionDispatcher endp ; sp-analysis failed

下面是c++伪码:

VOID
KiUserExceptionDispatcher(__in PEXCEPTION_RECORD ExceptionRecord,__in PCONTEXT ContextRecord)
{
NTSTATUS Status; //
// (A custom calling convention is used that does not pass the parameter
// values in a C-compatible fashion.)
// #if defined(_WIN64) //
// 如果Wow64.dll 注册它的帮助函数来处理异常事件,调用这个函数 if (Wow64PrepareForException)
Wow64PrepareForException(
ExceptionRecord,
ContextRecord
); #endif if (RtlDispatchException(
ExceptionRecord,
ContextRecord))
{
#if defined(_WIN64)
RtlRestoreContext( ContextRecord );
#else
NtContinue(
ContextRecord,
FALSE
);
#endif Status = (NTSTATUS)ContextRecord->Rax; RtlRaiseStatus( Status ); //
// No return from RtlRaiseStatus.
// } Status = NtRaiseException(
ContextRecord,
ExceptionRecord,
FALSE
); RtlRaiseStatus( Status ); //
// No return from RtlRaiseStatus.
//
}

参数

  • PCONTEXT ContextRecord
    这个结构包含有关最近发生的异常的详细信息,这些信息独立于C P U,具体参考《Windows异常相关数据结构
  • PEXCEPTION_RECORD ExceptionRecord
    包含处理器特定的寄存器数据。系统使用上下文结构执行各种内部操作,具体参考《Windows异常相关数据结构

这两个参数对我们进行异常调试和dmp分析很有用,可以得到异常信息和还原调用栈

Windows异常分发函数---KiUserExceptionDispatcher的更多相关文章

  1. Windows内核读书笔记——Windows异常分发处理机制

    本篇读书笔记主要参考自<深入解析Windows操作系统>和<软件调试>这两本书. IDT是处理异常,实现操作系统与CPU的交互的关口. 系统在初始化阶段会去填写这个结构. ID ...

  2. Windows异常分发

    当有异常发生时,CPU会通过IDT表找到异常处理函数,即内核中的KiTrapXX系列函数,然后转去执行.但是,KiTrapXX函数通常只是对异常做简单的表征和描述,为了支持调试和软件自己定义的异常处理 ...

  3. Windows异常的分发处理流程

    根据异常来源,一般分硬件异常和软件异常,它们处理的流程大致一样,下面简单讲一下. 如果是硬件异常,CPU会根据中断类型号转而执行对应的中断处理程序.CPU会在IDT中查找对应的函数来处理,各个异常处理 ...

  4. 4.5 HOOK分发函数

    4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...

  5. hook键盘驱动中的分发函数实现键盘输入数据的拦截

    我自己在看<寒江独钓>这本书的时候,书中除了给出了利用过滤的方式来拦截键盘数据之外,也提到了另外一种方法,就是hook键盘分发函数,将它替换成我们自己的,然后再自己的分发函数中获取这个数据 ...

  6. [内核编程] 4.5 HOOK分发函数

    4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...

  7. 反调试——Windows异常-SEH

    反调试--Windows异常-SEH 概念: SEH:Structured Exception Handling SEH是Windows默认的异常处理机制 如何使用 在代码中使用 __try​​__e ...

  8. 《寒江独钓_Windows内核安全编程》中修改类驱动分发函数

    最近在阅读<寒江独钓_Windows内核安全编程>一书的过程中,发现修改类驱动分发函数这一技术点,书中只给出了具体思路和部分代码,没有完整的例子. 按照作者的思路和代码,将例子补充完整,发 ...

  9. mfc 调用Windows的API函数实现同步异步串口通信(源码)

    在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...

随机推荐

  1. redis源码分析(六)--cluster集群同步

    Redis集群消息 作为支持集群模式的缓存系统,Redis集群中的各个节点需要定期地进行通信,以维持各个节点关于其它节点信息的实时性与一致性.如前一篇文章介绍的,Redis在专用的端口监听集群其它节点 ...

  2. DS 红黑树详解

    通过上篇博客知道,二叉搜索树的局限在于不能完成自平衡,从而导致不能一直保持高性能. AVL树则定义了平衡因子绝对值不能大于1,使二叉搜索树达到了严格的高度平衡. 还有一种能自我调整的二叉搜索树, 红黑 ...

  3. 挂载一个NFS共享

    在 system2 上挂载一个来自 system1.group8.example.com 的NFS共享,并符合下列要求: 1./public 挂载在下面的目录上 /mnt/nfsmount 2./pr ...

  4. C#各种字段类型对比

    一.常量.只读字段.静态字段和静态只读字段对比 public class ModelClass { //常量在定义时必须赋初始值 //public const string constField; p ...

  5. 用C#实现Rabbitmq应用的小实例

    RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件).RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的.所有主要 ...

  6. springboot 接口参数校验

    前言 在开发接口的时候,参数校验是必不可少的.参数的类型,长度等规则,在开发初期都应该由产品经理或者技术负责人等来约定.如果不对入参做校验,很有可能会因为一些不合法的参数而导致系统出现异常. 上一篇文 ...

  7. loadrunner通过字符串左右边界提取字符串

    /****** *函数名称:strcut *函数说明:通过左边界.右边界,从字符串中截取子字符串 *注意事项:会申请新的内存,需要手动释放 ******/ void strcut(char *strS ...

  8. Exception和RuntimeException区别

    Exception:强制性要求用户必须进行处理: RuntimeException:是Exception的子类,由用户选择是否进行处理:

  9. JAVA基础之JavaEE与MVC

    所谓的架构.模式都是方便开发和查看的,分工明确的,理解每层的具体的意义! 一.JavaEE: 1.Java EE,Java 平台企业版(Java Platform Enterprise Edition ...

  10. 嵌入式应用开发第四阶段-基于rk3399的视频监控系统

    一.需求分析 伴随着嵌入式技术.图像处理技术和无线网络传输技术的发展,传统模拟视频监控系统和基于PC的远程视频监控系统由于自身的不足,已经无法满足现代社会应用中不断涌现出来的新需求,于是基于嵌入式技术 ...