Windows APC学习笔记(一)—— APC的本质&备用APC队列

基础知识

  1. 线程是不能被“杀掉”、“挂起”、“恢复”的,线程在执行的时候自己占据着CPU,别人不能控制它
  2. 举个极端的例子:如果不调用API屏蔽中断并保证代码不出现异常,线程将永久占用CPU
  3. 所以说线程如果想“死”,一定是自己执行代码把自己杀死,不存在“他杀”的情况

思考:那如果想改变一个线程的行为该怎么办
答案:可以给他提供一个函数,让它自己去调用:APC(Asyncroneus Procedure Call,异步过程调用)

APC的本质

APC队列

在Windbg中查看
在这里插入图片描述
在这里插入图片描述
ApcListHead

  1. 由两个双向链表组成,共占16个字节
  2. 提供的APC函数可能是用户函数,也可能是系统函数(简单的区分方法就是判断函数地址是否大于0x80000000

Process:指向线程所属或者挂靠进程
KernelApcInProgress:内核Apc是否正在执行
KernelApcPending:是否存在等待状态的内核APC,存在则置1
UserApcPending:是否存在等待状态的用户APC,存在则置1

APC结构

在WinDbg中查看
在这里插入图片描述
NormalRoutine:找到提供的APC函数,并不完全等于APC函数的地址,后续将重点学习

分析 KiServiceExit

在这里插入图片描述

总结

如果我们想要改变一个线程,可以先提供一个APC,然后通过 _KAPC.NormalRoutine 指向我们提供的APC在哪里,再将APC存到 _KTHREAD.ApcState.ApcListHead 的第一个成员中

思考:当前线程什么时候将会执行提供的APC
答案

  1. KiServiceExit 函数(系统调用异常中断返回用户控件的必经之路)
  2. KiDeliverApc 函数(负责执行APC函数)

备用APC队列

描述

  1. _KTHREAD+0x14c 位置处,同样也存在一个 _KAPC_STATE 结构体,叫做 SavedApcState
  2. 线程APC队列中的APC函数都是与进程相关联的,具体点说:A进程的T线程中的所有APC函数,要访问的内存地址都是A进程的
  3. 但线程是可以挂靠到其他的进程:比如A进程的线程T,通过修改Cr3(改为B进程的页目录基址),就可以访问B进程地址空间,即所谓“进程挂靠”
  4. 当T线程挂靠B进程后,APC队列中存储的却仍然是原来的APC。具体点说,比如某个APC函数要读取一个地址为0x12345678的数据,如果此时进行读取,读到的将是B进程的地址空间,这样逻辑就错误了
  5. 为了避免混乱,在T线程挂靠B进程时,会将ApcState中的值暂时存储到SavedApcState中,等回到原进程A时,再将APC队列恢复。
  6. 因此,SavedApcState又称为备用APC队列

挂靠环境下ApcState的意义

在挂靠的环境下,也是可以先线程APC队列插入APC的

A进程的T线程挂靠B进程  A是T的所属进程  B是T的挂靠进程
ApcState    	B进程相关的APC函数     
SavedApcState	A进程相关的APC函数

在正常情况下,当前进程就是所属进程A,如果是挂靠情况下,当前进程就是挂靠进程B

ApcStatePointer

描述:为了操作方便,_KTHREAD 结构体中定义了一个指针数组 ApcStatePointer ,长度为2,位于 _KTHREAD+0x138

正常情况下

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

挂靠情况下

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

ApcStateIndex

描述ApcStateIndex 用来标识当前线程处于什么状态,位于 _KTHREAD+0x165

0:正常状态
1:挂靠状态

组合寻址

正常情况下,向ApcState队列中插入APC时:

ApcStatePointer[0] 指向 ApcState,此时 ApcStateIndex 的值为 0
ApcStatePointer[ApcStateIndex] 指向 ApcState

挂靠情况下,向ApcState队列中插入APC时:

ApcStatePointer[1] 指向 ApcState,此时 ApcStateIndex 的值为 1
ApcStatePointer[ApcStateIndex] 指向 ApcState

总结

无论什么环境下,ApcStatePointer[ApcStateIndex] 指向的都是 ApcState
ApcState 总是表示线程当前使用的apc状态

ApcQueueable

描述

  1. 位于 _KTHREAD+0x166,表示是否可以向线程的APC队列中插入APC
  2. 当线程正在执行退出的代码时,会将这个值设置为0 ,如果此时执行插入APC的代码(KeInsertQueueApc),在插入函数中会判断这个值的状态,如果为0,则插入失败
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows APC(Asynchronous Procedure Call)是一种异步过程调用机制,它允许一个线程在另一个线程上异步执行指定的函数。APC 机制是 Windows 操作系统中非常重要的一部分,它被广泛用于实现各种系统功能,例如异步 I/O、线程池等。 在 Windows 中,每个线程都有一个 APC 队列,该队列中存储了需要在该线程上异步执行的函数。当一个线程进入 Alertable 状态时(例如调用 Sleep、WaitForSingleObject 等函数),它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 APC 机制的具体原理如下: 1. 创建 APC 对象 首先,创建一个 APC 对象,该对象包含要在目标线程上执行的函数和参数。 2. 将 APC 对象插入到目标线程的 APC 队列 使用 QueueUserAPC 函数将 APC 对象插入到目标线程的 APC 队列中。当目标线程进入 Alertable 状态时,它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 3. 触发目标线程进入 Alertable 状态 为了让目标线程进入 Alertable 状态,可以使用 Sleep、WaitForSingleObject 等函数来实现。当目标线程进入 Alertable 状态时,它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 总之,APC 机制是 Windows 操作系统中非常重要的一部分,它提供了一种有效的异步过程调用机制,可以在不阻塞目标线程的情况下异步执行指定的函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值