Critical Regions和Guarded Regions区别
KeEnterCriticalRegion和KeLeaveCriticalRegion配合使用,能禁止用户模式APC和普通内核模式APC的调用,但是不能禁止特殊内核模式的调用(NormalRoutine为空的内核模式APC)
KeEnterGuardedRegion和KeLeaveGuardedRegion能禁止所有APC调用
KeEnterCriticalRegion会调用KeEnterCriticalRegionThread()函数,再看看KeEnterCriticalRegionThread()的内部实现
- FORCEINLINE
- VOID
- KeEnterCriticalRegionThread (
- PKTHREAD Thread
- )
- /*++
- Routine Description:
- This function disables kernel APC's for the current thread.
- N.B. The following code does not require any interlocks. There are
- two cases of interest: 1) On an MP system, the thread cannot
- be running on two processors as once, and 2) if the thread is
- is interrupted to deliver a kernel mode APC which also calls
- this routine, the values read and stored will stack and unstack
- properly.
- Arguments:
- Thread - Supplies a pointer to the current thread.
- N.B. This must be a pointer to the current thread.
- Return Value:
- None.
- --*/
- {
- ASSERT(Thread == KeGetCurrentThread());
- ASSERT((Thread->KernelApcDisable <= ) && (Thread->KernelApcDisable != -));
- Thread->KernelApcDisable -= ;
- KeMemoryBarrierWithoutFence();
- return;
- }
KeEnterGuardRegion会调用KeEnterGuardRegionThread()函数,再看看KeEnterGuardRegionThread()的内部实现
- FORCEINLINE
- VOID
- KeEnterGuardedRegionThread (
- IN PKTHREAD Thread
- )
- /*++
- Routine Description:
- This function disables special kernel APC's for the current thread.
- N.B. The following code does not require any interlocks. There are
- two cases of interest: 1) On an MP system, the thread cannot
- be running on two processors as once, and 2) if the thread is
- is interrupted to deliver a kernel mode APC which also calls
- this routine, the values read and stored will stack and unstack
- properly.
- Arguments:
- Thread - Supplies a pointer to the current thread.
- N.B. This must be a pointer to the current thread.
- Return Value:
- None.
- --*/
- {
- ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
- ASSERT(Thread == KeGetCurrentThread());
- ASSERT((Thread->SpecialApcDisable <= ) && (Thread->SpecialApcDisable != -));
- Thread->SpecialApcDisable -= ;
- KeMemoryBarrierWithoutFence();
- return;
- }
注意两者之间的区别
KeEnterCriticalRegionThread中为
- Thread->KernelApcDisable -= 1;
KeEnterGuardRegionThread中为
- Thread->SpecialApcDisable -= 1;
再看看这里的改变会对APC的派发有什么影响,查看KiDeliverApc函数代码
- VOID
- KiDeliverApc (
- IN KPROCESSOR_MODE PreviousMode,
- IN PKEXCEPTION_FRAME ExceptionFrame,
- IN PKTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This function is called from the APC interrupt code and when one or
- more of the APC pending flags are set at system exit and the previous
- IRQL is zero. All special kernel APC's are delivered first, followed
- by normal kernel APC's if one is not already in progress, and finally
- if the user APC queue is not empty, the user APC pending flag is set,
- and the previous mode is user, then a user APC is delivered. On entry
- to this routine IRQL is set to APC_LEVEL.
- N.B. The exception frame and trap frame addresses are only guaranteed
- to be valid if, and only if, the previous mode is user.
- Arguments:
- PreviousMode - Supplies the previous processor mode.
- ExceptionFrame - Supplies a pointer to an exception frame.
- TrapFrame - Supplies a pointer to a trap frame.
- Return Value:
- None.
- --*/
- {
- PKAPC Apc;
- PKKERNEL_ROUTINE KernelRoutine;
- KLOCK_QUEUE_HANDLE LockHandle;
- PLIST_ENTRY NextEntry;
- PVOID NormalContext;
- PKNORMAL_ROUTINE NormalRoutine;
- PKTRAP_FRAME OldTrapFrame;
- PKPROCESS Process;
- PVOID SystemArgument1;
- PVOID SystemArgument2;
- PKTHREAD Thread;
- //
- // If the thread was interrupted in the middle of the SLIST pop code,
- // then back up the PC to the start of the SLIST pop.
- //
- if (TrapFrame != NULL) {
- KiCheckForSListAddress(TrapFrame);
- }
- //
- // Save the current thread trap frame address and set the thread trap
- // frame address to the new trap frame. This will prevent a user mode
- // exception from being raised within an APC routine.
- //
- Thread = KeGetCurrentThread();
- OldTrapFrame = Thread->TrapFrame;
- Thread->TrapFrame = TrapFrame;
- //
- // If special APC are not disabled, then attempt to deliver one or more
- // APCs.
- //
- Process = Thread->ApcState.Process;
- Thread->ApcState.KernelApcPending = FALSE;
- if (Thread->SpecialApcDisable == ) {
- //
- // If the kernel APC queue is not empty, then attempt to deliver a
- // kernel APC.
- //
- // N.B. The following test is not synchronized with the APC insertion
- // code. However, when an APC is inserted in the kernel queue of
- // a running thread an APC interrupt is requested. Therefore, if
- // the following test were to falsely return that the kernel APC
- // queue was empty, an APC interrupt would immediately cause this
- // code to be executed a second time in which case the kernel APC
- // queue would found to contain an entry.
- //
- KeMemoryBarrier();
- while (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
- //
- // Raise IRQL to dispatcher level, lock the APC queue, and check
- // if any kernel mode APC's can be delivered.
- //
- // If the kernel APC queue is now empty because of the removal of
- // one or more entries, then release the APC lock, and attempt to
- // deliver a user APC.
- //
- KeAcquireInStackQueuedSpinLock(&Thread->ApcQueueLock, &LockHandle);
- NextEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
- if (NextEntry == &Thread->ApcState.ApcListHead[KernelMode]) {
- KeReleaseInStackQueuedSpinLock(&LockHandle);
- break;
- }
- //
- // Clear kernel APC pending, get the address of the APC object,
- // and determine the type of APC.
- //
- // N.B. Kernel APC pending must be cleared each time the kernel
- // APC queue is found to be non-empty.
- //
- Thread->ApcState.KernelApcPending = FALSE;
- Apc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
- ReadForWriteAccess(Apc);
- KernelRoutine = Apc->KernelRoutine;
- NormalRoutine = Apc->NormalRoutine;
- NormalContext = Apc->NormalContext;
- SystemArgument1 = Apc->SystemArgument1;
- SystemArgument2 = Apc->SystemArgument2;
- if (NormalRoutine == (PKNORMAL_ROUTINE)NULL) {
- //
- // First entry in the kernel APC queue is a special kernel APC.
- // Remove the entry from the APC queue, set its inserted state
- // to FALSE, release dispatcher database lock, and call the kernel
- // routine. On return raise IRQL to dispatcher level and lock
- // dispatcher database lock.
- //
- RemoveEntryList(NextEntry);
- Apc->Inserted = FALSE;
- KeReleaseInStackQueuedSpinLock(&LockHandle);
- (KernelRoutine)(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
- #if DBG
- if (KeGetCurrentIrql() != LockHandle.OldIrql) {
- KeBugCheckEx(IRQL_UNEXPECTED_VALUE,
- KeGetCurrentIrql() << | LockHandle.OldIrql << ,
- (ULONG_PTR)KernelRoutine,
- (ULONG_PTR)Apc,
- (ULONG_PTR)NormalRoutine);
- }
- #endif
- } else {
- //
- // First entry in the kernel APC queue is a normal kernel APC.
- // If there is not a normal kernel APC in progress and kernel
- // APC's are not disabled, then remove the entry from the APC
- // queue, set its inserted state to FALSE, release the APC queue
- // lock, call the specified kernel routine, set kernel APC in
- // progress, lower the IRQL to zero, and call the normal kernel
- // APC routine. On return raise IRQL to dispatcher level, lock
- // the APC queue, and clear kernel APC in progress.
- //
- if ((Thread->ApcState.KernelApcInProgress == FALSE) &&
- (Thread->KernelApcDisable == )) {
- RemoveEntryList(NextEntry);
- Apc->Inserted = FALSE;
- KeReleaseInStackQueuedSpinLock(&LockHandle);
- (KernelRoutine)(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
- #if DBG
- if (KeGetCurrentIrql() != LockHandle.OldIrql) {
- KeBugCheckEx(IRQL_UNEXPECTED_VALUE,
- KeGetCurrentIrql() << | LockHandle.OldIrql << | ,
- (ULONG_PTR)KernelRoutine,
- (ULONG_PTR)Apc,
- (ULONG_PTR)NormalRoutine);
- }
- #endif
- if (NormalRoutine != (PKNORMAL_ROUTINE)NULL) {
- Thread->ApcState.KernelApcInProgress = TRUE;
- KeLowerIrql();
- (NormalRoutine)(NormalContext,
- SystemArgument1,
- SystemArgument2);
- KeRaiseIrql(APC_LEVEL, &LockHandle.OldIrql);
- }
- Thread->ApcState.KernelApcInProgress = FALSE;
- } else {
- KeReleaseInStackQueuedSpinLock(&LockHandle);
- goto CheckProcess;
- }
- }
- }
- //
- // Kernel APC queue is empty. If the previous mode is user, user APC
- // pending is set, and the user APC queue is not empty, then remove
- // the first entry from the user APC queue, set its inserted state to
- // FALSE, clear user APC pending, release the dispatcher database lock,
- // and call the specified kernel routine. If the normal routine address
- // is not NULL on return from the kernel routine, then initialize the
- // user mode APC context and return. Otherwise, check to determine if
- // another user mode APC can be processed.
- //
- // N.B. There is no race condition associated with checking the APC
- // queue outside the APC lock. User APCs are always delivered at
- // system exit and never interrupt the execution of the thread
- // in the kernel.
- //
- if ((PreviousMode == UserMode) &&
- (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE) &&
- (Thread->ApcState.UserApcPending != FALSE)) {
- //
- // Raise IRQL to dispatcher level, lock the APC queue, and deliver
- // a user mode APC.
- //
- KeAcquireInStackQueuedSpinLock(&Thread->ApcQueueLock, &LockHandle);
- //
- // If the user APC queue is now empty because of the removal of
- // one or more entries, then release the APC lock and exit.
- //
- Thread->ApcState.UserApcPending = FALSE;
- NextEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
- if (NextEntry == &Thread->ApcState.ApcListHead[UserMode]) {
- KeReleaseInStackQueuedSpinLock(&LockHandle);
- goto CheckProcess;
- }
- Apc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
- ReadForWriteAccess(Apc);
- KernelRoutine = Apc->KernelRoutine;
- NormalRoutine = Apc->NormalRoutine;
- NormalContext = Apc->NormalContext;
- SystemArgument1 = Apc->SystemArgument1;
- SystemArgument2 = Apc->SystemArgument2;
- RemoveEntryList(NextEntry);
- Apc->Inserted = FALSE;
- KeReleaseInStackQueuedSpinLock(&LockHandle);
- (KernelRoutine)(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
- if (NormalRoutine == (PKNORMAL_ROUTINE)NULL) {
- KeTestAlertThread(UserMode);
- } else {
- KiInitializeUserApc(ExceptionFrame,
- TrapFrame,
- NormalRoutine,
- NormalContext,
- SystemArgument1,
- SystemArgument2);
- }
- }
- }
- //
- // Check if process was attached during the APC routine.
- //
- CheckProcess:
- if (Thread->ApcState.Process != Process) {
- KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
- (ULONG_PTR)Process,
- (ULONG_PTR)Thread->ApcState.Process,
- (ULONG)Thread->ApcStateIndex,
- (ULONG)KeIsExecutingDpc());
- }
- //
- // Restore the previous thread trap frame address.
- //
- Thread->TrapFrame = OldTrapFrame;
- return;
- }
可以看到,这个函数会判断Thread->SpecialApcDisable 和 Thread->KernelApcSidable 的值,如果Thread->SpecialApcDisable 为0,会先派发特殊内核APC,然后判断Thread->KernelApcDisable是否为0,为0 就去进一步的派发普通内核 Apc和 用户Apc
后续再补充代码实现细节.
Critical Regions和Guarded Regions区别的更多相关文章
- Windows内核开发-6-内核机制 Kernel Mechanisms
Windows内核开发-6-内核机制 Kernel Mechanisms 一部分Windows的内核机制对于驱动开发很有帮助,还有一部分对于内核理解和调试也很有帮助. Interrupt Reques ...
- [REP]AWS Regions and Availability Zones: the simplest explanation you will ever find around
When it comes to Amazon Web Services, there are two concepts that are extremely important and spanni ...
- Windows Kernel Security Training Courses
http://www.codemachine.com/courses.html#kerdbg Windows Kernel Internals for Security Researchers Thi ...
- C puzzles详解【51-57题】
第五十一题 Write a C function which does the addition of two integers without using the '+' operator. You ...
- mser 最大稳定极值区域(文字区域定位)算法 附完整C代码
mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. ...
- Hbase学习02
第2章 Apache HBase配置 本章在“入门”一章中进行了扩展,以进一步解释Apache HBase的配置. 请仔细阅读本章,特别是基本先决条件,确保您的HBase测试和部署顺利进行,并防止数据 ...
- fasta/fastq格式解读
1)知识简介--------------------------------------------------------1.1)测序质量值 首先在了解fastq,fasta之前,了解一下什么是质量 ...
- [libgdx游戏开发教程]使用Libgdx进行游戏开发(4)-素材管理
游戏中总是有大量的图像资源,我们通常的做法是把要用的图片做成图片集,这样做的好处就不多说了.直接来看怎么用. 这里我们使用自己的类Assets来管理它们,让这个工具类作为我们的资源管家,从而可以在任何 ...
- 目标检测之线段检测---lsd line segment detector
(1)线段检测应用背景 (2)线段检测原理简介 (3)线段检测实例 a line segment detector (4)hough 变换和 lsd 的区别 --------------------- ...
随机推荐
- long polling
Regular http: client 发出请求到server server 计算 response server 响应 response 给 client Polling: A client re ...
- python 中为什么不需要重载
函数重载主要是为了解决两个问题. (1)可变参数类型. (2) 可变参数个数. 另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两 ...
- django 定制管理页面外观 模板文件不生效的解决方法
问题描述:大概过程跟下面描述的一样,简单来说就是照着例子学习的时候定制管理页面外观,按照文档要求拷贝了base_site.html文件到templates目录下,并且按照要求修改了settings.p ...
- androidstudio提示adb错误:cannot parse version string:kg01的解决方法
打开adb.exe的文件目录,同时按下shift和鼠标右键,打开cmd后运行一下这个命令adb kill-server
- 浅谈 温故知新——HTML5!
古人有云:温故而知新.活到老,学到老,作为一枚前端的程序猿,不停的学习能够让我们对我们的技术有一个更加丰富的认识.这几天,项目已经完成,但我发现自己的知识体系存在一些短板,特别是在H5方面,所以我又回 ...
- C#——Socket
最近公司让我搞个socket小程序(服务端). 主要的功能:客户端发字符串到服务端,服务端接收后在界面上显示. 参照了网上许多代码,自己从中修改整理代码. public Form4() { Initi ...
- WP8.1StoreApp(WP8.1RT)---添加推送功能和获取系统信息
添加推送通知 1:Package.appxmanifest中的声明添加后台任务的推送通知权限 2:var channel = await PushNotificationChannelManager. ...
- django系列3.3--view视图函数, render, reverse(未完待续)
1.view视图函数 urls分发之后所用到的处理函数 2.render 用于渲染页面 在views.py中常用 from django.shortcuts import render, HttpRe ...
- 十一、linux文件系统权限详解
对于文件系统权限,我们前面已经讲解了一部分,这里就不在重复了. 1.修改文件权限有两种,一种是数字.一种是字母 (chmod 的修改只能是属主或者root) 数字: 修改目录权限和目录内所有文件的权限 ...
- 九、基础正则表达式BRE
1.重要性:简单的说正则表达式就是处理一套字符串的规则和方法,以行为单位对字符串进行处理. 运维工作中,会有大量的访问日志,错误日志,大数据学习正则表达式是不可少的. 2.linux正则表达式,主要是 ...