0x01  APC中断请求级别

     在Intel x86体系结构中,外部硬件中断是通过处理器上的"中断管脚"或者一个称为"本地APIC(local APIC)"的内置模块来发生的。本地APIC可以接收的中断源包括:  

  

    1处理器管脚(LINT0和LINT1)

    2本地APIC定时器(timer)

    3性能监视计数器中断

    4热传感器中断

    5 APIC内部错误中断

  

  APIC这个硬件中断设备是有优先级的,它使用了一个可编程阵列硬件来实现,并且在系统初始化的时候就完成了,Intel x86定义了256个中断向量号(Interrupt Vector Number),也称为中断向量,从0~255。这就对应了IDT中断描述符表,IDT的表项数目就是256,也就是说,APIC定义的是IDT中的中断例程的优先级

  对于一个处理器,它一旦被中断(可能来自内部,可能来自外部,可能是硬中断,可能是软中断),则某个预设的"中断服务例程"便被执行。而系统软件(操作系统)要做的事情就是,提供这些例程,并将它们设定到处理器的硬件中断向量表(即IDT)中。

  然而尽管APIC中断控制器已经提供了中断优先级支持,windows还是自己定义了一套优先级方案,称为"中断请求级别(IRPL Interrupt Request Level)"。在Intel x86系统中,windows使用了0~31来表示优先级,数值越大,优先级越高。内核为软件中断定义了一组标准的IRQL,而HAL则将硬件中断号映射为IRQL。

  IRQL的宏定义:

#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 PROFILE_LEVEL 27 //Timer used for profiling
#define CLOCK1_LEVEL 28 //Interval clock 1 level
#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

  对于IRQL,PASSIVE_LEVEL(被动级别)代表了最低的IRQL,那既然你最低,运行在PASSIVE_LEVEL的线程可以被任何更高的IRQL(从LOW_LEVEL开始都可以)的事情打断,所有的的用户模式代码都运行在PASSIVE_LEVEL(被动模式)上。而APC_LEVEL(APC级别)比PASSIVE_LEVEL高,这也正是在一个线程中插入一个APC可以打断该线程(如果被插入的这个线程正在PASSIVE_LEVEL上运行)的原因(APC注入的原理)。

  

  

  APC_LEVEL位于PASSIVE_LEVEL和DISPATCH_LEVEL之间,这是"专门"为另一种称为APC(异步过程调用 Asynchronous Procedure Call)的"软件中断"而保留的IRQL。每个APC都是在特定的线程环境中执行的,从而也一定在特定的进程环境中执行。APC是针对线程的,每个线程都有自己特有的APC链表。同一个线程的APC也是被排队执行的(思考线程的IRP对清队列,我们的IO请求要被排队执行,APC作为IRP请求的一种也不例外)。

  由于APC的IRQL高于PASSIVE_LEVEL,所以,它优先于普通的"线程代码"。当一个线程获得控制时,它的APC进程会立刻被执行(即执行APC队列中的IRP请求)。这一特性使得APC非常适合于实现各种异步通知事件。例如,I/O完成通知可以用APC来实现。

  (详细内容见《windows内核原理与实现》第5章2.6节)

0x02  APC结构

  APC是与线程相关的,在描述线程的结构KTHREAD中,可以看到很多带APC字眼的成员。

win7   32:

kd> dt _kthread
dtx is unsupported for this scenario. It only recognizes dtx [<type>] [<address>] with -a, -h, and -r. Reverting to dt.
ntdll!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 CycleTime : Uint8B
+0x018 HighCycleTime : Uint4B
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr32 Void
+0x02c StackLimit : Ptr32 Void
+0x030 KernelStack : Ptr32 Void
+0x034 ThreadLock : Uint4B
+0x038 WaitRegister : _KWAIT_STATUS_REGISTER
+0x039 Running : UChar
+0x03a Alerted : [2] UChar
+0x03c KernelStackResident : Pos 0, 1 Bit
+0x03c ReadyTransition : Pos 1, 1 Bit
+0x03c ProcessReadyQueue : Pos 2, 1 Bit
+0x03c WaitNext : Pos 3, 1 Bit
+0x03c SystemAffinityActive : Pos 4, 1 Bit
+0x03c Alertable : Pos 5, 1 Bit
……
+0x040 ApcState : _KAPC_STATE
……
+0x168 ApcStatePointer : [2] Ptr32 _KAPC_STATE
+0x170 SavedApcState : _KAPC_STATE
……

  可以看到在win7的32位下,与kthread偏移为0x40和0x170处,有两个成员:ApcState和SavedApcState,这两个成员指向两个不同的_KAPC_STATE结构:

typedef struct _KAPC_STATE {
LIST_ENTRY ApcListHead[MaximumMode]; //线程的apc链表 只有两个 内核态和用户态
struct _KPROCESS *Process; //当前线程的进程体 PsGetCurrentProcess()
BOOLEAN KernelApcInProgress; //内核APC正在执行
BOOLEAN KernelApcPending; //内核APC正在等待执行
BOOLEAN UserApcPending; //用户APC正在等待执行
} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;

  在_KAPC_STATE结构中,第一个成员为ApcListHead[2],第一个成员指向一个用户模式APC链表,而第二个成员指向内核模式APC链表。如果注意观察,可以看出特殊内核模式APC都排在普通内核模式APC之前。

  (图片源自危险漫步:http://www.weixianmanbu.com/article/33.html)

  

  APC结构:

//win7 32
kd> dt _kapc
dtx is unsupported for this scenario. It only recognizes dtx [<type>] [<address>] with -a, -h, and -r. Reverting to dt.
ntdll!_KAPC
+0x000 Type : UChar
+0x001 SpareByte0 : UChar
+0x002 Size : UChar
+0x003 SpareByte1 : UChar
+0x004 SpareLong0 : Uint4B
+0x008 Thread : Ptr64 _KTHREAD
+0x010 ApcListEntry : _LIST_ENTRY
+0x020 KernelRoutine : Ptr64 void
+0x028 RundownRoutine : Ptr64 void
+0x030 NormalRoutine : Ptr64 void
+0x038 NormalContext : Ptr64 Void
+0x040 SystemArgument1 : Ptr64 Void
+0x048 SystemArgument2 : Ptr64 Void
+0x050 ApcStateIndex : Char
+0x051 ApcMode : Char
+0x052 Inserted : UChar

  

  在 KAPC 结 构 中 , Type 域 应 为 KOBJECTS 枚 举 类 型 的 ApcObJect; Size 域 等 于 KAPC结 构 的 大 小 ; Thread 域 指 向 此 APC 对 象 所 在 的 线 程 KTHREAD 对 象 ; ApcListEntry 域 是APC 对 象 被 加 人 到 线 程 APC 链 表 中 的 节 点 对 象 ; KernelRoutine 域 是 一 个函 数 指 针 , 该 函数 将 在 内 核 模 式 的 APC-LEVEL 上 被 执 行 ; RundownRoutine 域 也 是 一 个 函 数 指 针 , 当 一个 线 程 终 止 时 如 果 它 的 APC 链 表 中 还 有 APC 对 象 , 那 么 , 若 成 员 非 空 ,则 调 用 它 所 指 的 函 数 。 № rmalRoutine 域 指 向 一 个 在 PASSIVE-LEVEL 上 执 行 的 函 数 。 在

这 三 个 函 数 指 针 成 员 中 , 只 有 KernelRoutine 是 必 需 的 , RundownRoutine 和 NormalRoutine都 是 可 选 的 。 而 且 , 如 果 NormalRoutine 为 空 的 话 , 则 其 后 的 Norma ℃ ontext 和 ApcMode域 也 将 被 忽 略 , 本 节 稍 后 会 解 释 这 三 个 域 的 关 系 。 SystemArgumentl 和 SystemArgument2是 两 个 提 供 给 KernelRoutine 或 NormalRoutine 函 数 的 参 数 。 ApcStateIndex 域 说 明 了 APC对 象 的 环 境 状 态 , 它 是 KAPC ENVIRONMENT 枚 举 类 型 的 成 员 , 一 旦 APC 对 象 被 插 人到 线 程 的 APC 链 表 中 , 则 ApcStatelndex 域 指 示 了 它 位 于 线 程 KTHREAD 对 象 的 哪 个 APC链 表 中 。 最 后 , 布 尔 类 型 Inserted 域 指 示 该 APC 对 象 是 否 已 被 插 人 到 线 程 的 APC 链 表 中。

  提炼几点关键:

  1.如果mode为UserMode,但是NormalRoutine为NULL,那么实际的模式变为Kernelmode,因为没有用户空间的APC例程可以使用;

  2.每种APC都有内核模式的例程;

  3.特殊的内核模式APC与普通的内核模式APC区别在于Normalroutine是否为空;

  4.当普通的内核模式APC例程被执行时,先执行KernelRoutine例程,再执行NormalRoutine例程(除非执行过KernelRoutine例程后,NormalRoutine例程被清除为NULL)。

  APC可以分成三种:用户模式APC、普通的内核模式APC,特殊的内核模式APC

  (图片源自危险漫步:http://www.weixianmanbu.com/article/33.html)

  

浅议APC的更多相关文章

  1. 网络语音视频技术浅议(附多个demo源码下载)

    我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...

  2. 浅议Delphi中的Windows API调用(举的两个例子分别是String和API,都不错,挺具有代表性)

    浅议Delphi中的Windows API调用http://tech.163.com/school • 2005-08-15 10:57:41 • 来源: 天极网为了能在Windows下快速开发应用程 ...

  3. 浅议Grpc传输机制和WCF中的回调机制的代码迁移

    浅议Grpc传输机制和WCF中的回调机制的代码迁移 一.引子 如您所知,gRPC是目前比较常见的rpc框架,可以方便的作为服务与服务之间的通信基础设施,为构建微服务体系提供非常强有力的支持. 而基于. ...

  4. 浅议NetMQ常见模式和消息加密机制

    浅议NetMQ常见模式和消息加密机制 概述 在传统企业级开发中,消息队列机制已经成为一种非常常见的技术实现手段,而基于NetMQ则看起来有点像一朵"奇葩",看起来从名字似乎是一个消 ...

  5. 浅议.NET遗留应用改造

    浅议.NET遗留应用改造 TLDR:本文介绍了遗留应用改造中的一些常见问题,并对改造所能开展的目标.原则.策略进行了概述. 一.背景概述 1.概述 或许仅"遗留应用"这个标题就比较 ...

  6. 浅议SNMP安全、SNMP协议、网络管理学习

    相关学习资料 tcp-ip详解卷1:协议.pdf(重点看25章SNMP部分) http://www.rfc-editor.org/rfc/rfc1213.txt http://www.rfc-edit ...

  7. 网络语音视频技术浅议 Visual Studio 2010(转)

    我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...

  8. Oracle 数据库表同步方法浅议

    总结一下Oracle数据库表级别的复制同步 一.通过触发器进行表的复制 原理,是监听表上都某一字段进行的DML操作,然后得到DML操作的数据,重新在另一个表上执行DML操作. 优点: 简单,编写一个触 ...

  9. DNS安全浅议、域名A记录(ANAME),MX记录,CNAME记录

    相关学习资料 http://baike.baidu.com/link?url=77B3BYIuVsB3MpK1nOQXI-JbS-AP5MvREzSnnedU7F9_G8l_Kvbkt_O2gKqFw ...

随机推荐

  1. English trip V1 - 11.What's That? 那是什么?Teacher:Patrick Key:There's/There are

    In this lesson you will learn to describe the position of an object. 在本课中,您将学习如何描述对象的位置. 课上内容(Lesson ...

  2. a gcc 4.2.4 bug(被stos指令累加后%edi作为参数的)

    a gcc 4.2.4 bug(被stos指令累加后%edi作为参数的) * * Ok, now we can initialize the rest of the tty devices and c ...

  3. NYOJ - 整数划分(四)

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=746 要求对一个n的整数插入m个乘号,求最大结果. 构造dp:dp[i][j]表示枚举至j ...

  4. HTML页面加载完毕后运行的js

    Js方法:<script type=”text/javascript”> window.onload=function (){ var userName=”xiaoming”; alert ...

  5. Linux下查看相应端口的进程

    1)查找被占用的端口:netstat -tln | grep 7777 2)查看被占用端口的PID:lsof -i:7777 3)禁用使用kill -9 PID来禁用端口进程

  6. 【Java】【5】List随机取值

    //shuffle 打乱顺序 Collections.shuffle(list); //随机抽取1个值 System.out.println(list.get(0)); //随机抽取N个值 Syste ...

  7. mysql 8.0.12 修改root密码

    use mysql: ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码'; FLUSH PRIVI ...

  8. python-day81--Ajax

    一.准备知识:json 1.什么是json? JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式.任何的语言之间都可以用json进行数据的交 ...

  9. 深入理解php内核

    目录 第一部分 基本原理 第一章 准备工作和背景知识 第一节 环境搭建 第二节 源码布局及阅读方法 第三节 常用代码 第四节 小结 第二章 用户代码的执行 第一节 PHP生命周期 第二节 从SAPI开 ...

  10. Spring注解之BeanPostProcessor与InitializingBean

    /*** BeanPostProcessor 为每个bean实例化时提供个性化的修改,做些包装等*/ package org.springframework.beans.factory.config; ...