无论是正常状态还是挂靠状态,都有两个APC队列,一个内核队列,一个用户队列。

每当要挂入一个APC函数时,不管是内核APC还是用户APC,内核都要准备一个KAPC的数据结构,并且将这个KAPC结构挂到相应的APC队列中。

kd> dt _kapc
nt!_KAPC+0x000 Type                //类型APC类型为0x12+0x002 Size              //本结构体的大小0x30+0x004 Spare0         //未使用+0x008 Thread         //目标线程+0x00c ApcListEntry      //APC队列挂的位置+0x014 KernelRoutine    //指向一个函数(调用ExFreePoolWithTag释放APC)+0x018 RundownRoutine    //未使用+0x01c NormalRoutine      //用户APC总入口或者真正的内核apc函数+0x020 NormalContext     //内核APC: NULL用户APC:真正的APC函数 +0x024 SystemArgument1 //APC函数的参数+0x028 SystemArgument2   //APC函数的参数+0x02c ApcStateIndex     //挂哪个队列,有四个值: 0 1 2 3+0x02d ApcMode            //内核APC用户APC+0x02e Inserted        //表示本apc是否已挂入队列挂入前: 0挂入后1

+0x000 Type
APC的类型为0x12,windows下任何一种内核对象都有一个类型编号。

+0x014 KernelRoutine
APC执行完毕后,释放本结构内存

+0x01c NormalRoutine
如果你当前的APC是内核APC,通过它就能找到内核APC函数。
如果你当前的APC是用户APC,通过它找到的只是用户APC的总入口并不是用户APC函数。

+0x020 NormalContext
如果是内核APC这个值为空,如果是用户APC这个值执行的就是用户APC函数

+0x02c ApcStateIndex

  • =0原始环境
  • =1挂靠环境
  • =2当前环境
  • =3插入APC时的当前环境

正常情况下:

KTHREAD.ApcStatePointer[0] 指向 KTHREAD.ApcState
KTHREAD.ApcStatePointer[1] 指向 KTHREAD.SavedApcState

挂靠情况下:

KTHREAD.ApcStatePointer[0] 指向 KTHREAD.SavedApcState
KTHREAD.ApcStatePointer[1] 指向 KTHREAD.ApcState

·

0时无论是在正常还是挂靠的情况下都能正常写到原来的那个列表中[0]

1时正常情况下写的就是SavedApcState,挂靠就是ApcState [1]

2 初始化的时候,当前进程的ApcState

3 插入的时候,当前进程的ApcState

在你初始化APC时可能时正常情况也可能是挂靠情况时用3,在你真正插入是它会再做一次判断。



APC挂入流程

我在3环插入APC调用QueueUserAPC,但是在0环有很多内核函数有很多函数也是可以插入APC的,它可能直接调用KelnitializeApc或者KilsertQueueApc来分配APC并且挂入APC。

KeInitializeApc函数说明

void KeInitializeApc
(IN PKAPC Apc,//KAPC指针 (分配好内存的还没初始化)IN PKTHREAD Thread,//目标线程IN KAPC_ENVIRONMENT TargetEnvironment,//0 1 2 3四种状态IN PKKERNEL_ROUTINE KernelRoutine//销毁KAPC的函数地址IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL//未使用IN PKNORMAL_ROUTINE NormalRoutine,//用户APC总入口或者内核apc函数IN KPROCESSOR_MODE Mode,//要插入用户apc队列还是内核apc队列IN PVOID Context//内核APC: NULL 用户APC:真正的APC函数
)
1.
2.Thread传进来会挂到 _KAPC.0x8 Thread
3.TargetEnvironment 传进来会挂到_KAPC.0x2c ApcStateIndex
4.KernelRoutine 传进来会挂到_KAPC.0x14 KernelPoutine
5.
6.NormalRoutine 传进来会挂到_KAPC.0x1c NormalRoutine
7.Mode 传进来会挂到_KAPC.0x2d ApcMode
8.Context 传进来会挂到_KAPC.0x20 NormalRoutine

KeInsertQueueApc函数说明

BOOLEAN
NTAPI
KeInsertQueueApc(IN PKAPC Apc,IN PVOID SystemArgument1,IN PVOID SystemArgument2,IN KPRIORITY PriorityBoost);
  1. 根据KAPC结构中的ApcStateIndex找到对应的APC队列
  2. 再根据KAPC结构中的ApcMode确定是用户队列还是内核队列
  3. 将KAPC挂到对应的队列中(挂到KAPC的ApcListEntry处)
  4. 再根据KAPC结构中的Inserted置1,标识当前的KAPC为已插入状态
  5. 修改KAPC_STATE结构中的KernelApcPending/UserApcPending
typedef struct _KAPC_STATE {LIST_ENTRY ApcListHead[MaximumMode];//0:内核apc链表。1:用户apc链表struct _KPROCESS *Process;//APC所关联的进程BOOLEAN KernelApcInProgress;//该线程正在处理一个普通的内核apc对象BOOLEAN KernelApcPending;//有内核apc对象正在等待交付BOOLEAN UserApcPending;//有用户apc对象正在等待交付
} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;

UserApcPending = 1时,用户apc才能被执行。

Alertable属性说明(是否运行被APC吵醒):

kd> dt KTHREAD
ntdil! KTHREAD
...
+0x164 Alertable: UChar
...DWORD SleepEx
(DWORD dwMilliseconds, //time-out interval BOOL bAlertable // early completion option
);DWORD WaitForSingleObjectEx
(HANDLE hHandle,//handle to objectDWORD dwMilliseconds, // time-out interval BOOL bAlertable //alertable option
);上面的两个api的最后一个还是就可以修改KTHREAD->Alertable
的值。
= 1 当前的线程是可以被APC唤醒的
= 0 不可被APC唤醒

如果为用户模式

3个跳转都没有实现的话

Alertable总结

  1. Alertable = 0当前插入的APC函数未必有机会执行: UserApcPending = 0
  2. Alertable-1UserApcPending =1将目标线程唤醒(从等待链表中摘出来,并挂到调度链表)

3.APC的挂入过程相关推荐

  1. Windows APC学习笔记(二)—— 挂入过程执行过程

    Windows APC学习笔记(二)-- 挂入过程&执行过程 基础知识 挂入过程 KeInitializeApc ApcStateIndex KiInsertQueueApc Alertabl ...

  2. 递归转化成非递归过程_8086微处理器中的递归和重入过程

    递归转化成非递归过程 As we all know that a procedure is a set of instruction written separately which can be u ...

  3. android打电话,接电话,挂电话过程

    android打电话过程: 1.TwelveKeyDialer.java,onKeyDown()->dialButtonPressed() 2.OutgoingCallBroadcaster.j ...

  4. javaweb应用网站实现第三方QQ登入过程

    腾讯开发文档入口 今天实现了web应用第三方QQ登入,由于我当时只看了开发文档中实现登入的流程,没有看SDK中的demo,所以SDK中的工具我没有用到.其实只要知道流程,完全可以不借助它的SDK也能实 ...

  5. Dockerfile springboot项目拿走即用,将yml配置文件从外部挂入容器

    Dockerfile 将springboot项目jar包打成镜像,并将yml配置文件外挂. # 以一个镜像为基础,在其上进行定制.就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜 ...

  6. Linux系统磁盘的挂入和装载

    步骤1:添加磁盘 点击添加,然后一路回车 注: scsi -> sd开头 sda --> 表示SCSI接口类型的第一块硬盘 sdb --> 表示SCSI接口类型的第二块硬盘 sda1 ...

  7. 4.内核APC执行过程

    APC函数的执行与插入并不是同一个线程: 在A线程中向B线程插入一个APC,插入的动作是在A线程中完成的,但什么时候执行则由B线程决定!,所以叫"异步过程调用" 内核APC函数与用 ...

  8. c语言程序设计 滴水视频,编程达人滴水中级班视频教程

    Java视频教程详情描述: <编程达人滴水中级班视频教程>编程达人来了,N部视频教程让你成为真正的编程达人,融会贯通将是本套视频最大的目的. Java视频教程目录: ├─APC机制 │  ...

  9. Windows的进程创建和映像装入

    关于Windows的进程创建和映像装入的过程,"Microsoft Windows Internals 4e"一书的第六章中有颇为详细的说明.本文就以此为依据,夹译.夹叙.夹议地作 ...

最新文章

  1. memset()函数用法及其作用
  2. Symfony3.0 实践教程 (三) 安装与配置Symfony
  3. 人工智能导论 王万良教授_学会动态丨辽宁省人工智能导论教学研讨活动在沈阳成功举办...
  4. 吐血整理 《计算机网络 五层协议之物理层(上)》
  5. [Swift]LeetCode793. 阶乘函数后K个零 | Preimage Size of Factorial Zeroes Function
  6. 配置oracle网络连接命令,配置oracle网络环境
  7. 清华美女学霸数学笔记曝光, 精美程度无与伦比
  8. 爬虫怎么处理python_python 爬虫怎么处理json内容
  9. apache的tomcat负载均衡和集群配置
  10. docker基础4--docker的命令
  11. android studio jdy08,JDY-08模块 蓝牙4.0 BLE CC2541 airsync iBeacon 兼容arduino
  12. JAVA实现文本翻译功能_java实现简单的英文文本单词翻译器功能示例
  13. 【愚公系列】2022年04月 微信小程序-Flex布局详解
  14. e-target与e-currentTarget的区别
  15. android 模拟器 pubg,雷电安卓模拟器怎么玩绝地求生刺激战场 PC端带你愉快吃鸡...
  16. 双系统linux开机黑屏,解决双系统中ubuntu开关机异常,黑屏,出现“nouveau , SCHED_ERROR”字样等的问题...
  17. 蓝桥杯单片机决赛(国赛)第十一届题目加代码
  18. DICOM标准中关于C-Find,运用StudyTime进行查找时无法查找到数据的问题
  19. ValueError: Unknown activation function: ReLU
  20. 数字电路基础知识——组合逻辑电路(奇偶校验电路、数据比较器的设计)

热门文章

  1. ML之API:国内外各大人工智能平台(百度云/华为云/阿里云/Face++等)及其API的简介、使用方法之详细攻略
  2. Py:数据挖掘之对微信朋友圈好友的性别、区域、昵称、签名信息进行情感分析
  3. flask中的CBV , flask-session在redis中存储session , WTForms数据验证 , 偏函数 , 对象里的一些小知识...
  4. 20190110-用笨办法找到二维矩阵的鞍点
  5. 【BZOJ】3456: 城市规划(多项式求ln)
  6. iOS开发 tabBarController选中状态
  7. 使用 matlab 产生GK101任意波数据文件的方法
  8. MySql 长时间读数据发生超时的异常 Mysql Reader Exception TimeOut expired
  9. poj 2240 Arbitrage (floyd 变形)
  10. 【原创】C++变量作用域(三)