简介

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. JAVA字符串比较,BigDecimal比较

    import java.math.BigDecimal; public class StrCompareTo { public static void main(String[] args) { Sy ...

  2. 如何删除mysql注释

    Linux命令删除注释 先把库表导出成一个.sql文件,然后使用sed命令删除注释.此种适用于mysql端口不开外网的情况. $ cat create_table.sql create table t ...

  3. 【开发工具】- 推荐一款好用的文本编辑器[Sublime Text]

    作为一个程序员除了IDE外,文本编辑器也是必不可少的一个开发工具.之前一直在用的是NotePad++.EditPlus,这两款编辑器,但是总感觉差点什么,昨天在知乎上看到有人推荐Sublime Tex ...

  4. 使用虹软ArcFac,java 离线SDK 进行人脸识别

    公司项目需要人脸识别登录,需要支持离线识别,所以无法使用在线的人脸识别的API,于是使用到了离线SDK来对比识别人脸相识度. 获取人脸抓拍的图片需要对接设备,这里不做记录,假设我们已经获取到了人脸图片 ...

  5. ES读写索引内幕分析

    一.简介 ES中的索引都进行分片,每个分片都会保存多个副本.这些副本称为复制组,在添加或删除索引时必须同步副本.如果不这样,从不同的副本中读取的索引可能截然不同.保持分片副本同步并从中提供读取的过程被 ...

  6. ningx配置本地https环境

    由于项目改成了https访问,所以本地开发的时候也要通过https验证,避免页面发送http请求. 例如原来是这样访问:http://192.168.88.88:8080/ 或 http://loca ...

  7. es截取指定的字段返回

    SearchResponse response = client.prepareSearch(index_name).setTypes("lw_devices") .setFrom ...

  8. unittest使用

    unittest:单元测试框架主要包含四部分: 1.测试固件(test fixture): 定义:包含执行测试前的准备setUP().测试执行完后的清扫工作tearDown() 注意: setUp() ...

  9. 关于如何往Jupyter notebook添加可选的kernel

    关于如何往Jupyter notebook添加可选的kernel 1. Anaconda知识预热 管理虚拟环境 关于如何安装Anaconda,这里就不再一一赘述,安装完Anaconda,接下来我们就可 ...

  10. 进程中join方法的使用

    在进程中:join方法 是让主进程等待子进程运行完毕后再执行主进程的.(即主进程阻塞) 示例 # -*- coding: utf-8 -*- from multiprocessing import P ...