Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

两种异常(CPU异常、用户模拟异常)的收集

 文章的核心:异常收集的是什么?(TrapFrame与ExceptionRecord);如何收集异常?(看文章)。

1. 异常的分类

  ① CPU指令异常 (比如除零异常) CPU运行检测到;

  ② 用户模拟异常 (throw 1)

  其在收集是存在不同,但在派发时和处理时是完全相同的,下面我们就来分析一下其存在的不同。

2. CPU指令异常 - 除零异常(分析)

  1)Trap00函数分析

    除零异常会引发中断,其执行 Trap00 函数,该函数逆向分析如下,我们在三环进零环时,已经学习过一个_TrapFrame结构,其本质也是填写该结构。

    注意,我们应该清楚,TrapFrame结构不只是三环进零环使用,而是只要走IDT表都要使用该结构,其是通过TrapFrame怎么返回,至于从三环还是零环进来这不重要。

    其分析情况如下图,Trap00总结做已下事情:

    ① 保存TrapFrame基本的信息;

    ② 检查DebugActive是否存在调试器,若存在调试器,则保存Dr相关寄存器;

    ③ 判断来自内核或三环,来确定其错误号(0xc0000094/0xc0000095);

    ④ 其最后有三次机会走CommonDispatchException函数。

    

  2) CommonDispatchException 异常记录函数分析

    该函数就是生成ExceptionRecord这个结构体,填写完成,然后调用nt!KiDispatchException进行下一步分析(三环的模拟异常直接在三环形成,然后拷贝到零环)。

    我们要知道ExceptionRecord的作用:存储了异常码异常属性、异常记录(链表,多次出现异常时记录)异常发生地址异常有关参数

    其中该函数的重要一点:其ExceptionFlags置为0,我们之后关注KiDispatchException如何处理的。

    

3.用户模拟异常分析

  像thorw 1 这种引发的是用户模拟异常,我们下面就来分析一下如下代码:

#include "stdafx.h"
#include <windows.h> int main(int argc, char* argv[])
{
throw ; return ;
}

  9:        throw 11;
  00401028   mov         dword ptr [ebp-4],0Bh
  0040102F   push        offset __TI1H (00423580)
  00401034   lea         eax,[ebp-4]
  00401037   push        eax
  00401038   call        __CxxThrowException@8 (004011e0)

  1)CxxThrowException反汇编分析

    如下是CxxThrowException函数的反汇编,该函数需要两个参数,一个是我们模拟的代码,另外一个是ExceptionList,我们下面详细分析该段代码的执行流程:

    004011E0   push        ebp
    004011E1   mov         ebp,esp
    004011E3   sub         esp,20h
    004011E6   push        esi
    004011E7   push        edi
    004011E8   mov         ecx,8
    004011ED   mov         esi,offset string "The value of ESP was not properl"...+0E0h (00422118)
    004011F2   lea         edi,[ebp-20h]
    004011F5   rep movs    dword ptr [edi],dword ptr [esi]
    // 复制一段结构体
    004011F7   mov         eax,dword ptr [ebp+8]
    004011FA   mov         dword ptr [ebp-8],eax
    004011FD   mov         ecx,dword ptr [ebp+0Ch]
    00401200   mov         dword ptr [ebp-4],ecx
    // 传入参数
    00401203   lea         edx,[ebp-0Ch]
    00401206   push        edx  // 参数指针
    00401207   mov         eax,dword ptr [ebp-10h]
    0040120A   push        eax // 参数个数
    0040120B   mov         ecx,dword ptr [ebp-1Ch]
    0040120E   push        ecx // 异常标志位
    0040120F   mov         edx,dword ptr [ebp-20h]
    00401212   push        edx  // 异常码
    00401213   call        dword ptr [__imp__RaiseException@16 (0042a154)]

    该代码所做的事情如下:

    ① 先从内存中拷贝一段0x20字节的固定结构体到堆栈中;

    ② 将ExceptionList也拷贝到堆栈中(该结构体内部);

    ③ 传入有关参数调用RaiseException函数。

    可能光看比较抽象,下面画出其详细的栈帧图就知道了,注意,ThrowCode虽然从用户代码传入进来,但分析其函数并没有用到,而是直接调用一段固定的异常码。

    而&ThrowCode以及异常链被作为其参数存储,这样通过分析就可以轻易找到其ThrowCode值,其作为参考之后来处理SEH。

      

  2)kernel32!RaiseException函数分析

    前面分析过,其CxxThrowException函数调用该函数,该函数的本质就是生成一个ExceptionRecord结构体,

    我们之前分析过,如果是CPU指令异常,其在CommonDispatchException函数中生成该结构体;

    函数分析如下,该过程比较好理解,注意其触发异常的地址标记为该地址,并不是ThrowCode的地址,这个是你要明确的,后续在将异常处理时这里用到SEH异常,我们再继续分析

    

  3)ntdll!RtlRaiseException函数分析

    该函数分析如下,其在三环进入零环前在堆栈中保存了一个_CONTEXT结构体,我们之前在用户APC分析过,返回三环时要在零环向三环堆栈中写入一个CONTEXT用于保存。

    来自用户层的异常我们确定其必须返回,,则就进零环之前就直接在三环中预先保存了一个_CONTEXT结构体,至于其如何使用,我们在异常的处理中会详细分析到。

    这里我们要关注CONTEXT几个比较重要的点:eip与esp,因为其是程序的重要落脚点,发现其是该函数的返回地址与上一个函数的堆栈图(本质就是kernel!RaiseException调用时的现场)。

    

  4)nt!RtlRaiseException函数分析分析

    上面我们经过分析ntdll!RtlRaiseException,发现其调用ZwRaiseException函数进内核,其对应nt!NtRaiseException函数,其分析如下图

    该函数如下所示,其中值得注意的一点是:KThread.TrapFrame保存着TrapFrame.ebx,进零环时,mov edx,esp,其esp保存着call的返回地址,即ebx保存着三环栈顶,也是三环的返回地址。

    这是这里一个比较重要的细节,你是一定要明确的。

    

  5)nt!KiRaiseException函数分析

    我们之前在三环生成了ExceptionRecord与Context,但是我们要在零环使用,其如何使用的呢?

    分析了这个函数你就会明白,其在nt!KiRaiseException函数中调用完成的两者的复制,之后将Context转换为TrapFrame其KiDispatchException要使用。

    之前我们存在一个疑问,为什么不能使用三环进零环的一个TrapFrame而非得从三环拿过来一个Context转换?

    猜想:因为该TrapFrame必须是异常现场的TrapFrame,而CPU中断直接调用IDT异常表很容易保存,但是用户模拟的必须是从三环到零环的,其TrapFrame是关于系统调用的。

      因此必须调用ntdll!RtlRaiseException三环保存的Context,这是直接记录异常现场的,这样你就能很好理解其中的逻辑。    

      备注:在调用KiDispatchException上方,其存在一句代码:ExceptionCode &=  EFu,其表示将用户模拟异常的位置0,因此用户模拟异常最高位不可能为0,CPU异常,比如c0000094,区分。            

      

   

4. 总结

  到此为止,我们分析过上面两种异常的收集流程,其最终都会流向nt!KiDispatchException函数,下面一张图简单汇总,如果看详情,直接回去看有关函数,都说的很详细。

  我们要知道异常收集的是什么-ExceptionRecord以及TrapFrame,怎么收集的?按上面来分析即可。

  

5.通过异常来进行三环与零环通信的思路

  对于异常,我们存在一种思路,即通过除零异常触发,然后hook除零异常,接收到消息,然后读取全局变量或者节区。

  我们将数据存储在全局变量或者存放在一个专门的PE节区中,我们在Hook的除零异常代码中读取,然后执行,这样就很好理解了。

  之后我们会通过这个猜想来实现我们的代码。

两种异常(CPU异常、用户模拟异常)的收集的更多相关文章

  1. [ACM_模拟] POJ1068 Parencodings (两种括号编码转化 规律 模拟)

    Description Let S = s1 s2...s2n be a well-formed string of parentheses. S can be encoded in two diff ...

  2. 创建线程的两种方式比较Thread VS Runnable

    1.首先来说说创建线程的两种方式 一种方式是继承Thread类,并重写run()方法 public class MyThread extends Thread{ @Override public vo ...

  3. SSH两种验证方式原理

    本帖转自 http://www.cnblogs.com/hukey/p/6248468.html SSH验证方式有两种,分别为用户密码认证以及密钥认证. 1.用户密码认证方式 说明: (1) 当客户端 ...

  4. java的两种异常runtimeException和checkedException

    java异常处理机制主要依赖于try,catch,finally,throw,throws五个关键字.   try 关键字后紧跟一个花括号括起来的代码块,简称try块.同理:下面的也被称为相应的块. ...

  5. java程序中抛出异常的两种方式,及异常抛出的顺序

    在java中,会经常遇到异常,java提供了两种抛出异常的方式. 方式一: throws ,抛出具体代码中的异常,这种方式编译器都会提示,举例: public static void main(Str ...

  6. Java语言中两种异常的差别

    Java提供了两类主要的异常:runtime exception和checked exception.所有的checked exception是从java.lang.Exception类衍生出来的,而 ...

  7. Java异常处理机制及两种异常的区别

    java异常处理机制主要依赖于try,catch,finally,throw,throws五个关键字.   try 关键字后紧跟一个花括号括起来的代码块,简称try块.同理:下面的也被称为相应的块. ...

  8. 浅析Java语言中两种异常的差别

    Java提供了两类主要的异常:runtime exception和checked exception.所有的checked exception是从java.lang.Exception类衍生出来的,而 ...

  9. Java中的两种异常类型是什么?他们有什么区别?

    一.Throwable是所有异常的根,java.lang.Throwable Error是错误,java.lang.Error Exception是异常,java.lang.Exception 二.E ...

随机推荐

  1. css 重排与重绘

    css 重绘与重排 我们要知道当浏览器下载完页面的所有资源后,就会开始解析源代码. HTML 会被解析成 DOM Tree,Css 则会被渲染成 CSSOM Tree,最后它们会附加到一起,形成渲染树 ...

  2. CF 997A

    You’ve got a string a1,a2,…,an, consisting of zeros and ones.Let’s call a sequence of consecutive el ...

  3. PyTorch专栏(八):微调基于torchvision 0.3的目标检测模型

    专栏目录: 第一章:PyTorch之简介与下载 PyTorch简介 PyTorch环境搭建 第二章:PyTorch之60分钟入门 PyTorch入门 PyTorch自动微分 PyTorch神经网络 P ...

  4. 150+行Python代码实现带界面的数独游戏

    150行代码实现图形化数独游戏 Github地址,欢迎各位大佬们fork.star啥的,感谢: 今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独 ...

  5. 自动化运维Ansible之常用模块

    目录 0.Ansible模块语法 1.Command模块 2.Shell模块 3.Scripts模块 4.Copy模块 5.File模块 6.Yum模块 7.Service模块 8.Cron模块 9. ...

  6. 瀑布流vue-waterfall的高度设置

    最近用vue做项目,用到了瀑布流vue-waterfall,其中遇到高度的设置问题,大概介绍下,希望可以帮到一些人 1.安装 npm install --save vue-waterfall 2.引入 ...

  7. SQL实战(三)

    一. 查找所有员工自入职以来的薪水涨幅情况,给出员工编号emp_noy以及其对应的薪水涨幅growth,并按照growth进行升序CREATE TABLE `employees` (`emp_no` ...

  8. Python math库和random库

    1.math库 >>> from math import * >>> 2*pi 6.283185307179586 >>> e 2.7182818 ...

  9. jQuery数组去重复

    例如: var yearArray = new Array("三二一", "三二一", "学历", "学历", &quo ...

  10. 【cs224w】Lecture 5 - 谱聚类

    Spectral Clustering 前面的课程说到了 community detection 并介绍了两种算法.这次来说说另外一类做社区聚类的算法,谱聚类.这种算法一般分为三个步骤 pre-pro ...