Tesla.Angela 发表于 2014-6-7 02:04:47

《WIN64驱动教程》补充[10]:在高IRQL下执行需要低IRQL的代码

作者:Tesla.Angela

这篇文章,来源于一个一年多前的噩梦(具体原因参见主教程的WFP章节)。
选择在这个时候发这篇文章,目的是终结这个噩梦,顺带问候一下YaoHui这个SB。
题外话:如果对我的这个故事感兴趣,还可以看一下我在2013-8-5至2013-8-9之间发的微博。

言归正传,当你在一个高IRQL的线程A里,需要执行一个只能在低IRQL才能执行的操作,怎么办?
比如说,在IRQL=2的时候,需要用ZwReadFile。我曾经想过两个办法:
1.在调用ZwReadFile之前,调用KeLowerIrql降低IRQL,然后再调用ZwReadFile,最后使用KeRaiseIrql来恢复原来的IRQL。
2.发消息给另外一个线程B,让线程B执行,等线程B执行完,再让线程A继续执行。
结果如下:
1.蓝屏。
2.偶尔会正常,但没过多久就会死锁。如果在单CPU的系统里,一定死锁。
原因如下:
1.彻底破坏了系统环境。
2.在高IRQL的情况下,线程是不能切换的。当线程A、B都被同一个CPU执行时,会陷入“你等我我又等你”的状态。
这两个办法都行不通之后,我郁闷了很久。当时我直骂NT系统的设计人员,说他们是“用嘴来拉屎,用屁眼来吃饭”。

后来,我终于找到了这个问题的解决方案:使用“作业队列”。
我个人感觉“作业队列”其实是代码片段。等于发通知给系统,让系统的线程(IRQL=0)来执行你的代码片段。
“作业队列”,有人翻译为“劳务线程”、“作业线程”甚至“工人线程”。
不管怎么说,这玩意其实非常简单,只有两个相关函数:ExInitializeWorkItem、ExQueueWorkItem。
ExInitializeWorkItem用来初始化一个“作业队列”,而ExQueueWorkItem则用于执行。
这两个函数的原型如下:
VOID ExInitializeWorkItem
(
_In_PWORK_QUEUE_ITEM Item,         //一片NonPagedPool,大小为sizeof(WORK_QUEUE_ITEM)
_In_PWORKER_THREAD_ROUTINE Routine,//“代码片段”函数
_In_PVOID Context                  //传递给“代码片段”函数的参数
);
VOID ExQueueWorkItem
(
_Inout_PWORK_QUEUE_ITEM WorkItem,//你之前申请的那片NonPagedPool
_In_   WORK_QUEUE_TYPE QueueType   //作业队列的类型,个人感觉没啥区别,详情见MSDN
);

下面的例子是在WFP回调里调用ZwWriteFile。
但有一点我必须要说明:使用“作业队列”来执行代码是滞后的。时机是IRQL下降到0的时候。
换句话说,系统会“尽快”执行你的代码,“尽快”的意思是,一旦IRQL下降到0,你的代码就能马上被执行。
**** Hidden Message *****

XSS 发表于 2014-7-5 23:45:06

5ak 发表于 2024-1-1 17:01:42

学习了

ruin1990 发表于 2024-1-17 14:18:58

这个真的很有帮助,最早写的一个防火墙过滤数据包,想写日志到文件,一写就死机,就是这个害的。

376408384 发表于 2024-1-26 09:52:25

我来学习

baggiowangyu 发表于 2024-1-26 14:21:05

2024补充学习

Cloutain 发表于 2024-1-29 10:25:58

做好软件设计,尽量避免在高IRQL下执行低的代码,毕竟有WorkItem的滞后性

HelloYoungBoy 发表于 2024-2-6 14:16:12

看看 学习

376408384 发表于 2024-2-7 11:16:24

PWORK_QUEUE_ITEM Item=kmalloc(sizeof(WORK_QUEUE_ITEM)); item 不用销毁吗?

Tesla.Angela 发表于 2024-2-7 16:08:06

376408384 发表于 2024-2-7 11:16
PWORK_QUEUE_ITEM Item=kmalloc(sizeof(WORK_QUEUE_ITEM)); item 不用销毁吗?

The callback routine that was specified in the Routine parameter to ExInitializeWorkItem is called in a system context at IRQL PASSIVE_LEVEL. This caller-supplied routine is responsible for freeing the work item when it is no longer needed by calling ExFreePool or ExFreePoolWithTag.
来源:https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exqueueworkitem

结论:需要自己释放,当年写代码时忘了,现在已经把你的提醒添加到主贴最末处。

lpmjknj 发表于 2024-2-15 18:00:44

学习一下

nj001 发表于 2024-3-15 09:25:46

学习一下

yimingqpa 发表于 2024-3-29 10:23:18

感谢楼主,看看隐藏内容

lzhlzhvip 发表于 2024-7-24 00:48:42

谢谢楼主

wst5898 发表于 2025-1-25 20:38:31

好好学习一下
页: [1]
查看完整版本: 《WIN64驱动教程》补充[10]:在高IRQL下执行需要低IRQL的代码