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. Map m = Collections.synchronizedMap(new HashMap())

    Collections.synchronizedMap(new HashMap())让你创建的new HashMap()支持多线程数据的同步.保证多线程访问数据的一致性 来源:http://www.b ...

  2. python之面向对象的关系

    一.从空间角度研究类 类外面可以给对象封装属性 class A: address = '美丽富饶的沙河' def __init__(self, name): self.name = name def ...

  3. coding++:Spring中的@Transactional(rollbackFor = Exception.class)属性详解

    异常: 如下图所示,我们都知道 Exception 分为 运行时异常 RuntimeException 和 非运行时异常. error 是一定会回滚的. 如果不对运行时异常进行处理,那么出现运行时异常 ...

  4. coding++:Java 中Model 与 实体的区别

    model的字段>entity的字段,并且model的字段属性可以与entity不一致,model是用于前端页面数据展示的,而entity则是与数据库进行交互做存储用途. 举个例子: 比如在存储 ...

  5. coding++ :javascript Date format (js日期格式化)

    方式一: // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1 ...

  6. eureka和zookeeper注册中心的区别

    ookeeper与Eureka区别 CPA理论:一个分布式系统不可能同时满足C(一致性).A(可用性)和P(分区容错性).由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡. ...

  7. 如何使用Java中的Enum类

    Java1.5 中出现了枚举类型.当一个值都在一个固定的范围内变化,那就可以使用 enum 类型来定义.比如说,一周有七天,一年有四季. 没有枚举类的时候,我们用常量来定义一组范围值的: public ...

  8. MFC之使用blat发送邮件

    blat的下载地址:http://www.blat.net 我用它进行了smtp服务的邮件发送.这里我使用的qq邮箱,qq邮箱使用的密码是授权码,可以再qq邮箱设置里面开启smtp服务.下载下来是文件 ...

  9. PTA数据结构与算法题目集(中文) 7-11

    PTA数据结构与算法题目集(中文)  7-11 7-11 关键活动 (30 分)   假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行.“任务调度 ...

  10. PTA数据结构与算法题目集(中文) 7-7

    PTA数据结构与算法题目集(中文)  7-7 7-7 六度空间 (30 分)   “六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论.这个理论可以通俗地阐述为 ...