前言
前一篇在介绍APC的文章中提到过,如果想让线程做什么事情,就给它的APC队列里面挂一个APC。我们也了解了,在位于KTHREAD+0x34的位置处有一个ApcState,该字段是一个存着描述APC信息的_KAPC_STATE结构。但实际上,线程结构体KTHREAD中存着与APC有关的字段不止这一处。
由图可以知道,KTHREAD结构体中,除了+0x034偏移处的ApcState,还有4处与APC有关的字段。本篇将会从依次介绍这几个字段的含义,并会引入一个新的概念“备用APC队列”。
+0x14c SavedApcState
备用APC队列
由上图可以发现,SavedApcState字段与ApcState字段一样,都是_KAPC_STATE结构体。这里先回顾一下该结构体:
那么问题来了,弄两个一模一样的结构体有什么用呢?再讨论这个问题之前,我们必须了解一个知识,那就是挂靠。关于挂靠,可以参考我之前写的这篇进程挂靠。
这里再简单总结一下,线程APC队列中的APC函数都是与进程相关联的,具体点说:“A进程的T线程中的所有APC函数,要访问的内存地址都是A进程的“。但线程是可以挂靠到其它进程上的,比如A进程的线程T,通过修改Cr3(改为B进程的页目录基址),就可以访问B进程的地址空间,即所谓”进程挂靠“。
当T线程挂靠B进程后,APC队列中的存储的却仍然是原来的APC!具体点说,比如某个APC函数要读取一个地址为0x12345678的数据,如果此时进行读取,读到的将是B进程的地址空间,这样逻辑就错误了!
为了避免混乱,在T线程挂靠B进程时,会将ApcState中的值暂时存储到SavedApcState中,等回到原进程A时,再将APC队列恢复。所以SavedApcState又称为备用APC队列。
再看NtReadVirtualMemory
在进程挂靠这篇中,我们分析了NtReadVirtualMemory这个内核函数,这个函数是ReadProcessMemory这个API在0环中的实现。根据上次分析,我们可以得到这样一个调用步骤:
1 | NtReadVirtualMemory -> _MmCopyVirtualMemory -> _MiDoPoolCopy -> _KeStackAttachProcess -> _KiAttachProcess |
在上一次分析时,我们分析到了_KiAttachProcess,该函数内部会先修改养父母(KTHREAD.ApcState.Process),再调用KiSwapProcess进行Cr3的修改,从而完成线程的挂靠。接着就可以读取另一个进程的内存了。当然,上一次分析时并没有学习APC相关的知识,这次,我们需要重新审视这个KiAttachProcess函数到底做了哪些事。
再次观察KiAttachProcess函数,在完成挂靠过程之前,其上方有一个叫做KiMoveApcState,这个函数看上去和APC有关,所以我们进入该函数进行分析。
分析该函数,可以发现,这个函数主要做了一件事,就是将ApcState中的内容复制一份到SavedApcState中,而这个操作刚好就位于挂靠进程之前,这也再一次验证了SavedApcState的作用,就是作为备用APC队列暂存ApcState中的值。
挂靠环境下ApcState的意义
在挂靠的环境下,也是可以先线程APC队列插入APC的,那这种情况下,使用的是哪个APC队列呢?
根据前面的分析,可以总结成如下:
1 | - A进程的T线程挂靠B进程,A是T的所属进程,B是T的挂靠进程。 |
+0x138 ApcStatePointer
为了操作方便,_KTHREAD结构体中定义了一个指针数组ApcStatePointer,长度为2.
1 | 正常情况下: |
+0x165 ApcStateIndex
1 | ApcStateIndex用来标识当前线程处于什么状态: |
ApcStatePointer 与 ApcStateIndex组合寻址
1 | 正常情况下,向ApcState队列中插入APC时: |
总结:无论什么环境下,ApcStatePointer[ApcStateIndex] 指向的都是ApcState,ApcState则总是表示线程当前使用的apc状态。
+0x166 ApcQueueable
ApcQueueable用于表示是否可以向线程的APC队列中插入APC。
当线程正在执行退出的代码时,会将这个值设置为0 ,如果此时执行
插入APC的代码(KeInsertQueueApc后面会讲),在插入函数中会判断这个值的状态,如果为0,则插入失败。
参考链接
- https://www.bilibili.com/video/BV1NJ411M7aE?p=70 (滴水预习班-备用APC队列)
- https://cataloc.gitee.io/blog/2020/04/05/%E8%BF%9B%E7%A8%8B%E6%8C%82%E9%9D%A0/ (cataLoc的博客-进程挂靠)
- https://blog.csdn.net/weixin_42052102/article/details/83304995 (MyClassmates博客-备用APC队列)