简介

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. Go MongoDB官方数据库驱动之增删改查

    package main import ( "context" "fmt" "log" "go.mongodb.org/mongo ...

  2. 【基本知识】FMS有限状态机设计

    有限状态机是Verilog中十分基本也是十分重要的知识.本文对有限状态机做了一个简单介绍. 1.状态机三要素 有限状态机具有三个要素:状态跳转.跳转判断.状态操作: 1)状态跳转:现态跳转到次态: 2 ...

  3. 【leetcode-135,62,63 动态规划】分发糖果 ,不同路径

    分发糖果 老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分. 你需要按照以下要求,帮助老师给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果. 相邻的孩 ...

  4. mysql存储过程简单例子

    1.之前经常在oracle数据库中使用存储过程,换到mysql后用的不多,但是有时候也用,大致记录一下,基本和oracle的一样. CREATE DEFINER = `root`@`%` PROCED ...

  5. MVC的Views中使用递归生成Html【转】

    在开发过程中往往会有一个需求,就是将一个树状的数据结构在视图中表示出来.例如最传统的多级分类,系统中有一系列根分类,每个分类中又带有一些子分类,而我们的目标便是在页面上生成一个由ul和li嵌套组成的H ...

  6. pandas-03 DataFrame()中的iloc和loc用法

    pandas-03 DataFrame()中的iloc和loc用法 简单的说: iloc,即index locate 用index索引进行定位,所以参数是整型,如:df.iloc[10:20, 3:5 ...

  7. koa2---koa-bodyparser中间件

    对于POST请求的处理,koa-bodyparser中间件可以把koa2上下文的formData数据解析到ctx.request.body中 安装: npm install --save koa-bo ...

  8. day 02 预科

    目录 什么是编程语言 什么是编程 为什么要编程 计算机的组成 CPU 存储器 I/O设备(Input/Output设备) 输入设备 输出设备 多核CPU 32位和64位 机械硬盘工作原理 机械手臂 磁 ...

  9. 第9章 运行TensorFlow

    目录 第9章 运行TensorFlow 创建一个计算图并在会话中执行 管理图 节点值的生命周期 TensorFlow中的线性回归 实现梯度下降 给训练算法提供数据 保存和恢复模型 用TensorBoa ...

  10. linux服务器管理常用命令

    1.ps命令 (Processes Status) ps这个命令是查看系统进程,ps 是显示瞬间行程的状态,并不动态连续. ==============ps 的参数说明================ ...