IRQL Ring0实现

一,IRQL的定义
Interrupt ReQuest Level
     DDK对IRQL的定义是:中断请求级(IRQL)标示中断的优先级。处理器在一个IRQL上执行线程代码,IRQL是帮助决定线程如何被中断的。每个处理器都有自己的中断IRQL。 在同一处理器上,线程只能被更高级别IRQL的线程能中断。也就是说,较高IRQL的中断能够中断其它的任务或具有较低IRQL的中断,所有拥有与当前IRQL相同或更低的IRQL的中断将被屏蔽,直到它在较高IRQL中断服务程序结束后,得到再次执行的机会。

二,常见的IRQL
     Windows大部分时间都运行在软件中断级别中,即0-2级别。当有设备中断来临时,windows会将IRQL提升至硬件中断级别(DIRQL, DEVICE INTERRUPT REQUEST LEVEL),并且运行相应的硬件中断处理函数。当硬件中断结束后,恢复到原来的IRQL。
    
     我们经常遇见的有四种IRQL级别。“Passive”, “APC”, “Dispatch” and “DIRQL”。“DriverEntry”将会在PASSIVE_LEVEL被调用。
     #define PASSIVE_LEVEL 0
     #define APC_LEVEL 1
     #define DISPATCH_LEVEL 2
     #define PROFILE_LEVEL 27
     #define CLOCK1_LEVEL 28
     #define CLOCK2_LEVEL 28
     #define IPI_LEVEL 29
     #define POWER_LEVEL 30
     #define HIGH_LEVEL 31
     
     PASSIVE_LEVEL
     IRQL最低级别,没有被屏蔽的中断,在这个级别上,线程执行用户模式,可以访问分页内存。
     用户模式的代码是运行在最低级别的PASSIVE_LEVEL中,驱动程序的DriverEntry函数,派遣函数,AddDevice函数一般运行在PASSIVE_LEVEL中(驱动程序的StartIO和DPC函数运行在DISPATCH_LEVEL中),它们在必要的时候可以申请进入DISPATCH_LEVEL级别,使用内核函数KeGetCurrentIrql()可以知道系统的当前IRQL。

APC_LEVEL
     在这个级别上,只有APC级别的中断被屏蔽,可以访问分页内存。当有APC发生时,处理器提升到APC级别,这样,就屏蔽掉其它APC,为了和APC执行 一些同步,驱动程序可以手动提升到这个级别。APC级别仅仅比PASSIVE_LEVEL高,这也是在一个线程中插入一个APC可以打断该线程(如果该线程运行在PASSIVE_LEVEL上)运行的原因。

DISPATCH_LEVEL
     DISPATCH_LEVEL是一个重要的区分点,他代表了线程调度器正在运行。一个处理器运行在此IRQL上,代表他可能正在做两件事之一:正在进行线程调度;正在处理一个硬件中断的后半部(不那么重要的部分),这被称为DPC(Deferred Procedure Call:延迟调用)。
     这个级别,DPC(延迟过程) 和更低的中断被屏蔽,不能访问分页内存,所有的被访问的内存不能分页。因为只能处理分页内存,所以在这个级别,能够访问的Api大大减少。
     Windows负责线程调度的组件运行在DISPATCH_LEVEL级别,当前线程运行完时间片后,操作系统自动从PASSIVE_LEVEL提升至DISPATCH_LEVEL级别,从而可以使得线程调度组件可以调度其他的线程。当线程切换完成后,操作系统又从DISPATCH_LEVEL级别恢复到PASSIVE_LEVEL级别。

DIRQL (Device IRQL)
     通常处于高层次的驱动程序不会使用这个IRQL等级,在这个等级上所有的中断都会被忽略。这是IRQL的最高等级。通常使用这个来判断设备的优先级。
一般的,更高级的驱动在这个级别上不处理IRQL,但是几乎所有的中断被屏蔽,这实际上是IRQL的一个范围,这是一个决定某个驱动有更高的优先级的方法。

三,IRQL与线程优先级
     线程优先级的概念不同于IRQL,只有应用程序在PASSIVE_LEVEL运行的时候才有意义。程序员可以设定线程优先级(可以使用API SetThreadPriority)。优先级高代表可以有更多机会在CPU上运行。当线程调度内核组件运行于DISPATCH_LEVEL的时候,所有应用程序的线程都停止,等着被调度。
     一个运行中的线程,它的优先级可能有以下两种类型,每种类型有16个层次:
     1,可变的优先级
     可变的优先级类的数值范围是0到15,大多数的线程都属于这种类型。属于可变优先级的线程总是可抢先的,也就是说,他们共同在相同的IRQL层和其它的线程一起被系统调度,并构成一个循环。
     通常情况下,内核是这样处理一个可变优先级线程的,当线程是一个与用户交互的线程时,它的优先级最高,其它线程
的优先级随着运行时间片的增长而下降,直到到达最初程序设计者定义的基本优先级层次。
     2,实时优先级
     实时优先级类别的范围数值是16到31。这种类型的线程通常用于临界区线程,只能由一个拥有较高优先级的线程产生可抢先的线程。
     
     要注意的是,无论线程的优先级属性是多少,都会被一个软件或硬件中断所抢先。线程的优先级只影响系统线程调度程序的决策。调度程序运行于DISPATCH_LEVEL级,它将基于线程的优先级来决定一个线程何时该运行及这个线程将会获得多少时间片,同时确定其它所有线程的状态。

四,IRQL与内存分页
     在使用内存分页时,可能会导致页故障。因为分页内存随时可能从物理内存交换到磁盘文件,读取不在物理内存中的分页内存时,会引发一个页故障,从而执行这个异常的处理函数。异常处理函数会将磁盘文件的内容重新交换到物理内存中。     
     页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或更高的IRQL的程序中会带来系统崩溃。     
     因此,对于等于或高于DISPATCH_LEVEL级别的程序不能使用分页内存。
当程序的中断请求在DISPATCH_LEVEL以上,包括DISPATCH_LEVEL,程序只能使用非分页内存,否则将导致蓝屏死机

#define PAGED_CODE() PAGED_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);

PAGED_CODE() 是DDk提供的宏,在check版本中生效。他会检查这个函数是否低于DISPATCH_LEVEL的终端请求,如果等于或高于这个中断请求级,将会产生这个断言

简单实现代码

  1 #include "IRQL.h"
  2
  3 //bp IRQL!DriverEntry
  4 void Sub_1();
  5
  6 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
  7 {
  8     NTSTATUS Status = STATUS_SUCCESS;
  9     PDEVICE_OBJECT  DeviceObject = NULL;
 10
 11     //KIRQL Irql;
 12     KIRQL NewIrql;
 13     KIRQL OldIrql;
 14
 15     int* v1 = NULL;
 16     int* v2 = NULL;
 17
 18     DriverObject->DriverUnload = DriverUnload;
 19
 20
 21     Sub_1();
 22
 23     NewIrql = APC_LEVEL;
 24
 25     KeRaiseIrql(NewIrql, &OldIrql);
 26
 27     Sub_1();
 28
 29     v1 = ExAllocatePool(NonPagedPool, sizeof(int));
 30     v2 = ExAllocatePool(PagedPool, sizeof(int));//DispatchLevel不能用分页内存
 31
 32     //APC_LEVEL下的申请内存可以是分页也可以是不分页,
 33
 34     /*
 35     页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或更高的        IRQL的程序中会带来系统崩溃。  
 36    */
 37
 38     ExFreePool(v1);
 39     ExFreePool(v2);
 40
 41     /*
 42     KeGetCurrentIrql
 43     KeRaiseIrql
 44     KeLowerIrql
 45     */
 46     KeLowerIrql(OldIrql);
 47     Sub_1();
 48
 49
 50
 51
 52     /*
 53     PASSIVE_LEVEL
 54     APC_LEVEL
 55     DISPATCH_LEVEL
 56
 57
 58
 59 // Interrupt Request Level definitions
 60 //
 61
 62 #define PASSIVE_LEVEL 0             // Passive release level
 63 #define LOW_LEVEL 0                 // Lowest interrupt level
 64 #define APC_LEVEL 1                 // APC interrupt level
 65 #define DISPATCH_LEVEL 2            // Dispatcher level
 66 #define CMCI_LEVEL 5                // CMCI handler level
 67
 68 #define PROFILE_LEVEL 27            // timer used for profiling.
 69 #define CLOCK1_LEVEL 28             // Interval clock 1 level - Not used on x86
 70 #define CLOCK2_LEVEL 28             // Interval clock 2 level
 71 #define IPI_LEVEL 29                // Interprocessor interrupt level
 72 #define POWER_LEVEL 30              // Power failure level
 73 #define HIGH_LEVEL 31               // Highest interrupt level
 74
 75 #define CLOCK_LEVEL                 (CLOCK2_LEVEL)
 76
 77
 78
 79     */
 80
 81
 82
 83     return Status;
 84 }
 85
 86 void Sub_1()
 87 {
 88     KIRQL Irql;
 89     Irql = KeGetCurrentIrql();//passive_level
 90     switch (Irql)
 91     {
 92     case PASSIVE_LEVEL:
 93     {
 94         DbgPrint("PASSIVE_LEVEL\r\n");
 95         break;
 96
 97     }
 98     case APC_LEVEL:
 99     {
100         DbgPrint("APC_LEVEL\r\n");
101
102         break;
103     }
104     case DISPATCH_LEVEL:
105     {
106         DbgPrint("DISPATCH_LEVEL\r\n");
107
108         break;
109     }
110
111     }
112
113
114 }
115
116
117 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
118 {
119     DbgPrint("DriverUnload()\r\n");
120 }

>=DISPATCH_LEVEL,程序只能使用非分页内存,这里用PAGED_CODE产生断言

  1 #include "IRQL_ApcLevel_Dispatch_Level.h"
  2
  3 //bp IRQL_ApcLevel_Dispatch_Level!DriverEntry
  4
  5
  6
  7 KIRQL __NewIrql;
  8 KIRQL __OldIrql;
  9
 10
 11 void ShowIrql();
 12 void ApcLevel();
 13 void DispatchLevel();
 14
 15 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
 16 {
 17     NTSTATUS Status = STATUS_SUCCESS;
 18     PDEVICE_OBJECT  DeviceObject = NULL;
 19
 20
 21     DriverObject->DriverUnload = DriverUnload;
 22
 23
 24     ApcLevel();
 25
 26
 27
 28
 29     __NewIrql = DISPATCH_LEVEL;
 30
 31     KeRaiseIrql(__NewIrql, &__OldIrql);
 32     DispatchLevel();
 33
 34
 35     /*
 36     PASSIVE_LEVEL
 37     APC_LEVEL
 38     DISPATCH_LEVEL
 39
 40
 41
 42 // Interrupt Request Level definitions
 43 //
 44
 45 #define PASSIVE_LEVEL 0             // Passive release level
 46 #define LOW_LEVEL 0                 // Lowest interrupt level
 47 #define APC_LEVEL 1                 // APC interrupt level
 48 #define DISPATCH_LEVEL 2            // Dispatcher level
 49 #define CMCI_LEVEL 5                // CMCI handler level
 50
 51 #define PROFILE_LEVEL 27            // timer used for profiling.
 52 #define CLOCK1_LEVEL 28             // Interval clock 1 level - Not used on x86
 53 #define CLOCK2_LEVEL 28             // Interval clock 2 level
 54 #define IPI_LEVEL 29                // Interprocessor interrupt level
 55 #define POWER_LEVEL 30              // Power failure level
 56 #define HIGH_LEVEL 31               // Highest interrupt level
 57
 58 #define CLOCK_LEVEL                 (CLOCK2_LEVEL)
 59
 60
 61
 62     */
 63
 64
 65
 66     return Status;
 67 }
 68
 69
 70 void ApcLevel()
 71 {
 72     DbgPrint("In Apc\r\n");
 73     int* v1 = NULL;
 74     int* v2 = NULL;
 75
 76     ShowIrql();
 77
 78     __NewIrql = APC_LEVEL;
 79
 80     KeRaiseIrql(__NewIrql, &__OldIrql);
 81
 82     ShowIrql();
 83
 84     v1 = ExAllocatePool(NonPagedPool, sizeof(int));
 85     v2 = ExAllocatePool(PagedPool, sizeof(int));//Dispatch不能用分页内存
 86
 87     //APC_LEVEL下的申请内存可以是分页也可以是不分页
 88
 89
 90     ExFreePool(v1);
 91     ExFreePool(v2);
 92
 93
 94     KeLowerIrql(__OldIrql);
 95 }
 96
 97 #pragma PAGEDCODE  //使函数加载到分页内存中
 98 //#pragma LOCKEDCODE //使函数加载到未分页内存中
 99 void DispatchLevel()
100 {
101     PAGED_CODE();
102     //#define PAGED_CODE() PAGED_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
103
104     //PAGED_CODE() 是DDk提供的宏,在check版本中生效。
105     //他会检查这个函数是否低于DISPATCH_LEVEL的终端请求,
106     //如果等于或高于这个中断请求级,将会产生这个断言。
107
108
109
110
111     DbgPrint("In Dispatch\r\n");
112     int* v1 = NULL;
113     int* v2 = NULL;
114
115     ShowIrql();
116
117     __NewIrql = DISPATCH_LEVEL;
118
119     KeRaiseIrql(__NewIrql, &__OldIrql);
120
121
122
123
124     ShowIrql();
125
126     v1 = ExAllocatePool(NonPagedPool, sizeof(int));
127     v2 = ExAllocatePool(PagedPool, sizeof(int));//Dispatch不能用分页内存
128
129     //APC_LEVEL下的申请内存可以是分页也可以是不分页
130
131
132     ExFreePool(v1);
133     ExFreePool(v2);
134
135
136     KeLowerIrql(__OldIrql);
137 }
138
139 void ShowIrql()
140 {
141     KIRQL Irql;
142     Irql = KeGetCurrentIrql();//passive_level
143     switch (Irql)
144     {
145     case PASSIVE_LEVEL:
146     {
147         DbgPrint("PASSIVE_LEVEL\r\n");
148         break;
149
150     }
151     case APC_LEVEL:
152     {
153         DbgPrint("APC_LEVEL\r\n");
154
155         break;
156     }
157     case DISPATCH_LEVEL:
158     {
159         DbgPrint("DISPATCH_LEVEL\r\n");
160
161         break;
162     }
163
164     }
165
166
167 }
168
169
170 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
171 {
172     DbgPrint("DriverUnload()\r\n");
173 }
时间: 2024-08-04 22:13:50

IRQL Ring0实现的相关文章

Ring0级的探索

内核基础知识介绍: 内核概述:Interx86系列处理器使用"环"的概念实施访问控制,共4个权限级别.一般情况下,操作系统的内核程序.驱动程序等都在Ring0级别上运行.研究内核漏洞,需要首先掌握一些内核基础知识.例如内核驱动程序的开发.编译和运行,以及内核中重要的数据结构等. 驱动编写之Hello World 代码,保存为Helloworld.c 路径 D:\0day\HelloWorld\helloworld.c #include <ntddk.h> #define D

IRQL

IRQL是Interrupt ReQuest Level,中断请求级别. 一个由windows虚拟出来的概念,划分在windows下中断的优先级,这里中断包括了硬中断和软中断,硬中断是由硬件产生,而软中断则是完全虚拟出来的.处理器在一个IRQL上执行线程代码.IRQL用于帮助决定线程如何被中断的.在同一处理器上,线程只能被更高级别IRQL的线程能中断.每个处理器都有自己的中断IRQL.IRQL级别:PASSIVE_LEVELIRQL最低级别,没有被屏蔽的中断,在这个级别上,线程执行用户模式,可以

【code】ring0下的安全拷贝

ring0下的安全拷贝 BOOLEAN SafeCopyMemory(PVOID pDestination, PVOID pSourceAddress, SIZE_T SizeOfCopy) { PMDL pMdl = NULL; PVOID pSafeAddress = NULL; if(!MmIsAddressValid(pDestination) || !MmIsAddressValid(pSourceAddress)) return FALSE; pMdl = IoAllocateMdl

OD: Ring0 &amp; Kernel

开发技术讲究封装与模块化,安全技术强调底层安全性.安全技术需要打开封装.追根溯源! <0day 安全:软件漏洞分析技术(第2版)> 第21章 探索 Ring0 笔记 Intel x86 系列处理器使用"环"的概念来实施访问控制,共有 4 个权限级别,由高到低分别为 Ring0.Ring1.Ring2.Ring3,其中 Ring0 权限最高,Ring3 权限最低.Windows(从 NT 开始)和 Linux 等多数操作系统在 Intel x86 处理器上只使用了 Ring0

ring0和ring3的区别

现在探讨内核程序和应用程序之间的本质区别.除了能用WDK编写内核程序和阅读一部分Windows的内核代码之外,我们还需要了解它们的本质是什么,它们和我们熟悉的应用程序有什么区别. Intel的x86处理器是通过Ring级别来进行访问控制的,级别共分4层,从Ring0到Ring3(后面简称R0.R1.R2.R3).R0层拥有最高的权限,R3层拥有最低的权限.按照Intel原有的构想,应用程序工作在R3层,只能访问R3层的数据:操作系统工作在R0层,可以访问所有层的数据:而其他驱动程序位于R1.R2

【原创】浅说windows下的中断请求级IRQL

一 中断分类 根据中断源不同,可以将中断分为 硬件中断:硬件上产生的中断,可以来自处理器的内部和外部.处理器的外部中断可以来自各种PIN信号接口和Local APIC的LINT0和LINT1引脚,以及外部的I/O APIC发送过来的中断信息. 软件中断:软件上产生的中断,使用INT指令主动发起的中断,如INT 0X40,调用0X40号的中断服务例程. 硬件中断源又可以分为 可屏蔽中断:可屏蔽的中断如下 通过处理器的INTR pin接收的中断请求,典型地,INTR连接到8259A PIC上,在支持

IRQL和内核字符串处理函数

内核字符串处理函数和IRQL --by 张佩 系统中断级(IRQL) 借助于IRQL机制,系统实现了任务抢占功能.高中断级任务可以任意抢占低中断级任务的系统执行权,而低中断级任务必须等待所有高中断级任务都完成后,才能获取执行机会和相应系统资源.在单核系统中,系统中断级还被用做实现系统同步机制的手段,因为一颗核心的CPU在同一时刻,仅能运行一个线程,所以只要把当前正在使用Critical资源的线程IRQL提高到更高Level上,就可以避免其他线程和抢占自己的可能性. 系统功能被细分为许多系统模块,

Ring3 和Ring0 解释

这得从CPU指令系统(用于控制CPU完成各种功能的命令)的特权级别说起.在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃.比如:清内存.设置时钟等.如果所有的程序都能使用这些指令,那么你的系统一天死机n回就不足为奇了.所以,CPU将指令分为特权指令和非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通的应用程序只能使用那些不会造成灾难的指令.形象地说,特权指令就是那些儿童不宜的东东,而非特权指令则是老少皆宜. Intel的CPU将特权级别分为4个级别:R

RING0,RING1,RING2,RING3

Intel的CPU将特权级别分为4个级别:RING0,RING1,RING2,RING3.Windows只使用其中的两个级别RING0和RING3,RING0只给操作系统用,RING3谁都能用.如果普通应用程序企图执行RING0指令,则Windows会显示“非法指令”错误信息.  挑战: 大部分modern CPU 并不支持可虚拟化, 如x86 需直接访问内存和硬件的操作系统特权代码必须在Ring 0执行 CPU虚拟化必须在Guest OS下面添加VMM(Ring 0) 一些关键指令在非Ring