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的终端请求,如果等于或高于这个中断请求级,将会产生这个断言
简单实现代码
#include "IRQL.h" //bp IRQL!DriverEntry
void Sub_1(); NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL; //KIRQL Irql;
KIRQL NewIrql;
KIRQL OldIrql; int* v1 = NULL;
int* v2 = NULL; DriverObject->DriverUnload = DriverUnload; Sub_1(); NewIrql = APC_LEVEL; KeRaiseIrql(NewIrql, &OldIrql); Sub_1(); v1 = ExAllocatePool(NonPagedPool, sizeof(int));
v2 = ExAllocatePool(PagedPool, sizeof(int));//DispatchLevel不能用分页内存 //APC_LEVEL下的申请内存可以是分页也可以是不分页, /*
页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或更高的 IRQL的程序中会带来系统崩溃。
*/ ExFreePool(v1);
ExFreePool(v2); /*
KeGetCurrentIrql
KeRaiseIrql
KeLowerIrql
*/
KeLowerIrql(OldIrql);
Sub_1(); /*
PASSIVE_LEVEL
APC_LEVEL
DISPATCH_LEVEL // Interrupt Request Level definitions
// #define PASSIVE_LEVEL 0 // Passive release level
#define LOW_LEVEL 0 // Lowest interrupt level
#define APC_LEVEL 1 // APC interrupt level
#define DISPATCH_LEVEL 2 // Dispatcher level
#define CMCI_LEVEL 5 // CMCI handler level #define PROFILE_LEVEL 27 // timer used for profiling.
#define CLOCK1_LEVEL 28 // Interval clock 1 level - Not used on x86
#define CLOCK2_LEVEL 28 // Interval clock 2 level
#define IPI_LEVEL 29 // Interprocessor interrupt level
#define POWER_LEVEL 30 // Power failure level
#define HIGH_LEVEL 31 // Highest interrupt level #define CLOCK_LEVEL (CLOCK2_LEVEL) */ return Status;
} void Sub_1()
{
KIRQL Irql;
Irql = KeGetCurrentIrql();//passive_level
switch (Irql)
{
case PASSIVE_LEVEL:
{
DbgPrint("PASSIVE_LEVEL\r\n");
break; }
case APC_LEVEL:
{
DbgPrint("APC_LEVEL\r\n"); break;
}
case DISPATCH_LEVEL:
{
DbgPrint("DISPATCH_LEVEL\r\n"); break;
} } } VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload()\r\n");
}
>=DISPATCH_LEVEL,程序只能使用非分页内存,这里用PAGED_CODE产生断言
#include "IRQL_ApcLevel_Dispatch_Level.h" //bp IRQL_ApcLevel_Dispatch_Level!DriverEntry KIRQL __NewIrql;
KIRQL __OldIrql; void ShowIrql();
void ApcLevel();
void DispatchLevel(); NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL; DriverObject->DriverUnload = DriverUnload; ApcLevel(); __NewIrql = DISPATCH_LEVEL; KeRaiseIrql(__NewIrql, &__OldIrql);
DispatchLevel(); /*
PASSIVE_LEVEL
APC_LEVEL
DISPATCH_LEVEL // Interrupt Request Level definitions
// #define PASSIVE_LEVEL 0 // Passive release level
#define LOW_LEVEL 0 // Lowest interrupt level
#define APC_LEVEL 1 // APC interrupt level
#define DISPATCH_LEVEL 2 // Dispatcher level
#define CMCI_LEVEL 5 // CMCI handler level #define PROFILE_LEVEL 27 // timer used for profiling.
#define CLOCK1_LEVEL 28 // Interval clock 1 level - Not used on x86
#define CLOCK2_LEVEL 28 // Interval clock 2 level
#define IPI_LEVEL 29 // Interprocessor interrupt level
#define POWER_LEVEL 30 // Power failure level
#define HIGH_LEVEL 31 // Highest interrupt level #define CLOCK_LEVEL (CLOCK2_LEVEL) */ return Status;
} void ApcLevel()
{
DbgPrint("In Apc\r\n");
int* v1 = NULL;
int* v2 = NULL; ShowIrql(); __NewIrql = APC_LEVEL; KeRaiseIrql(__NewIrql, &__OldIrql); ShowIrql(); v1 = ExAllocatePool(NonPagedPool, sizeof(int));
v2 = ExAllocatePool(PagedPool, sizeof(int));//Dispatch不能用分页内存 //APC_LEVEL下的申请内存可以是分页也可以是不分页 ExFreePool(v1);
ExFreePool(v2); KeLowerIrql(__OldIrql);
} #pragma PAGEDCODE //使函数加载到分页内存中
//#pragma LOCKEDCODE //使函数加载到未分页内存中
void DispatchLevel()
{
PAGED_CODE();
//#define PAGED_CODE() PAGED_ASSERT(KeGetCurrentIrql() <= APC_LEVEL); //PAGED_CODE() 是DDk提供的宏,在check版本中生效。
//他会检查这个函数是否低于DISPATCH_LEVEL的终端请求,
//如果等于或高于这个中断请求级,将会产生这个断言。 DbgPrint("In Dispatch\r\n");
int* v1 = NULL;
int* v2 = NULL; ShowIrql(); __NewIrql = DISPATCH_LEVEL; KeRaiseIrql(__NewIrql, &__OldIrql); ShowIrql(); v1 = ExAllocatePool(NonPagedPool, sizeof(int));
v2 = ExAllocatePool(PagedPool, sizeof(int));//Dispatch不能用分页内存 //APC_LEVEL下的申请内存可以是分页也可以是不分页 ExFreePool(v1);
ExFreePool(v2); KeLowerIrql(__OldIrql);
} void ShowIrql()
{
KIRQL Irql;
Irql = KeGetCurrentIrql();//passive_level
switch (Irql)
{
case PASSIVE_LEVEL:
{
DbgPrint("PASSIVE_LEVEL\r\n");
break; }
case APC_LEVEL:
{
DbgPrint("APC_LEVEL\r\n"); break;
}
case DISPATCH_LEVEL:
{
DbgPrint("DISPATCH_LEVEL\r\n"); break;
} } } VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload()\r\n");
}
IRQL Ring0实现的更多相关文章
- Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook
Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...
- 函数调用关于从Ring3转到Ring0 ESP堆栈变化
在ring0堆栈获取ring3堆栈方式 第一种方式 [esp+4] == [esp+参数个数*4+4] 如果这里不相等就需要用第二种方式 [[esp+参数个数*4+8]] 这里面的值就是Ring3的堆 ...
- ring0
Intel的x86处理器是通过Ring级别来进行访问控制的,级别共分4层,RING0,RING1,RING2,RING3.Windows只使用其中的两个级别RING0和RING3. RING0层拥有最 ...
- 对付ring0 inline hook
对付ring0 inline hook的基本思路是这样的,自己写一个替换的内核函数,以NtOpenProcess为例,就是MyNtOpenProcess.然后修改SSDT表,让系统服务进入自己的函数M ...
- ring0 与 ring3 层之间的交互
在进行Windows的ring0层开发时,必不可免的要与 ring3 层进行交互.进行数据间的相互传输.可用的方法有DeviceIoCntrol,ReadFile.我平常都是用的DeviceIoCon ...
- OD: Ring0 & Kernel
开发技术讲究封装与模块化,安全技术强调底层安全性.安全技术需要打开封装.追根溯源! <0day 安全:软件漏洞分析技术(第2版)> 第21章 探索 Ring0 笔记 Intel x86 系 ...
- Ring3 和Ring0 解释
这得从CPU指令系统(用于控制CPU完成各种功能的命令)的特权级别说起.在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃.比如:清内存.设置时钟等.如果所有的程序都能使用这些 ...
- [原创]浅谈NT下Ring3无驱进入Ring0的方法
原文链接:浅谈NT下Ring3无驱进入Ring0的方法 (测试环境:Windows 2000 SP4,Windows XP SP2.Windows 2003 未测试) 在NT下无驱进入Ring0是一个 ...
- ring0和ring3的区别
现在探讨内核程序和应用程序之间的本质区别.除了能用WDK编写内核程序和阅读一部分Windows的内核代码之外,我们还需要了解它们的本质是什么,它们和我们熟悉的应用程序有什么区别. Intel的x86处 ...
随机推荐
- python基础教程_学习笔记9:抽象
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/30745465 抽象 懒惰即美德. 抽象和结构 抽 ...
- VS版本号定义、规则和相关的Visual Studio插件
软件版本号主要标识了软件的版本,通过其可以了解软件.类库文件的当前版本,使得软件版本控制有所依据. 我们就Windows系统和.NET Framework的编号规则来看,软件版本号的定义结构一般是这样 ...
- Pycharm乱码解决
现象:输出栏出现乱码 解决方案: 结果:
- k8s-YAML配置文件
一.YAML基础 YAML是专门用来写配置文件的语言,非常简洁和强大,使用比json更方便.它实质上是一种通用的数据串行化格式. YAML语法规则: 大小写敏感 使用缩进表示层级关系 缩进时不允许使用 ...
- Java 8后的首个长期支持版本Java 11
Java 11是Java8后的首个长期支持版本.按照 Oracle 公布的支持路线图,Java 11 将会获得 Oracle 提供的长期支持服务,直至2026年9月. 按照官方的说法,新的发布周期会严 ...
- spring中afterPropertiesSet方法与init-method配置描述
1. InitializingBean.afterPropertiesSet()Spring中InitializingBean接口类为bean提供了定义初始化方法的方式,它仅仅包含一个方法:after ...
- centos 虚拟机中最小化安装,无法上网的解决方法
无法上网原因:因为最小化安装以后,centos 默认未开启网卡 解决方法进入 /etc/sysconfig/network-scripts/ifcfg-enp0s3 文件中 进入编辑模式,将 ONBO ...
- MAC上使用Enterprise Architecture,附带安装步骤及破解链接
绪论 网上找了半天这个主题也没有详细的步骤的昂,所以自己来造轮子了. 还有,百度搜EA破解版不靠谱,大搜狗更给力哦! 一.背景 穷逼只有一台存储空间不大MACAir,分给虚拟机Virtual Box的 ...
- 使用 Kafka 在生产环境构建大规模机器学习
智能实时应用为所有行业带来了革命性变化.机器学习及其分支深度学习正蓬勃发展,因为机器学习让计算机能够在无人指引的情况下挖掘深藏的洞见.这种能力正是多种领域所需要的,如非结构化数据分析.图像识别.语音识 ...
- Xilinx AXI总线学习(1)
Xilinx AXI总线学习 1. AXI GPIO 采用的是AXI4-Lite接口 AXI GPIO Block Diagram Block design: 端口描述: AXI GPIO核有哪些寄存 ...