Windows异常分发函数---KiUserExceptionDispatcher
简介
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的更多相关文章
- Windows内核读书笔记——Windows异常分发处理机制
本篇读书笔记主要参考自<深入解析Windows操作系统>和<软件调试>这两本书. IDT是处理异常,实现操作系统与CPU的交互的关口. 系统在初始化阶段会去填写这个结构. ID ...
- Windows异常分发
当有异常发生时,CPU会通过IDT表找到异常处理函数,即内核中的KiTrapXX系列函数,然后转去执行.但是,KiTrapXX函数通常只是对异常做简单的表征和描述,为了支持调试和软件自己定义的异常处理 ...
- Windows异常的分发处理流程
根据异常来源,一般分硬件异常和软件异常,它们处理的流程大致一样,下面简单讲一下. 如果是硬件异常,CPU会根据中断类型号转而执行对应的中断处理程序.CPU会在IDT中查找对应的函数来处理,各个异常处理 ...
- 4.5 HOOK分发函数
4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...
- hook键盘驱动中的分发函数实现键盘输入数据的拦截
我自己在看<寒江独钓>这本书的时候,书中除了给出了利用过滤的方式来拦截键盘数据之外,也提到了另外一种方法,就是hook键盘分发函数,将它替换成我们自己的,然后再自己的分发函数中获取这个数据 ...
- [内核编程] 4.5 HOOK分发函数
4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...
- 反调试——Windows异常-SEH
反调试--Windows异常-SEH 概念: SEH:Structured Exception Handling SEH是Windows默认的异常处理机制 如何使用 在代码中使用 __try__e ...
- 《寒江独钓_Windows内核安全编程》中修改类驱动分发函数
最近在阅读<寒江独钓_Windows内核安全编程>一书的过程中,发现修改类驱动分发函数这一技术点,书中只给出了具体思路和部分代码,没有完整的例子. 按照作者的思路和代码,将例子补充完整,发 ...
- mfc 调用Windows的API函数实现同步异步串口通信(源码)
在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...
随机推荐
- Mybatis自动生成代码工具
项目结构如下 一:在POM中添加mybatis-generator-maven-plugin 插件 <plugins> <plugin> <groupId>org. ...
- ubuntu 安装harbor仓库
一.介绍 Harbor,是一个英文单词,意思是港湾,港湾是干什么的呢,就是停放货物的,而货物呢,是装在集装箱中的,说到集装箱,就不得不提到Docker容器,因为docker容器的技术正是借鉴了集装箱的 ...
- 【题解】Luogu P5290 [十二省联考2019]春节十二响
原题传送门 每个点维护一个堆,表示这个点及其子树所需的每段内存的空间 搜索时从下向上做启发式合并堆中信息,最后根节点堆中所有内存空间之和就是答案 #include <bits/stdc++.h& ...
- ZooKeeper学习笔记(一)——概述
zookeeper学习笔记(一)--概述 1. 概述 Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目.zookeeper从设计模式的角度来理解:是一个基于观察者设计 ...
- Ambari调整日志级别:How to enable debug logging in Ambari Server and Ambari Agent ?
PURPOSE When troubleshooting Ambari issues, it may be necessary to enable debug logging in the Ambar ...
- HUAWEI,H3C 三层交换机 常用命令
<HUAWEI> display ip interface brief,命令全局模式下可以查看所有端口下的ip地址及物理状态display this interface,命令用来显示当前接 ...
- Mars Android 接入指南
Mars Android 接入指南 https://github.com/Tencent/mars/wiki/Mars-Android-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8 ...
- 如何在linux中重置Mysql访问密码
目录 跳过密码认证 重启MySQL: 用sql来修改root的密码 去掉'跳过密码'代码 假设我们使用的是root账户. 跳过密码认证 重置密码的第一步就是跳过MySQL的密码认证过程,方法如下: # ...
- 浏览器提示:源映射错误:request failed with status 404 源 URL:http://xxx.js 源映射 URL:jquery.min.map
浏览器 jquery1.9.1min.js 报脚本错误 无jquery.min.map 文件 最近在浏览个人网站的时候就遇到了这个问题 我先说一下什么是source map文件. source map ...
- nodeJS实现简易爬虫
nodeJS实现简易爬虫 需求:使用nodeJS爬取昵图网某个分类下的图片并存入本地 运用nodeJS自带系统模块http.fs 示例代码: var http =require('http'); va ...