avatar

Catalog
内核APC执行过程

前言

前一篇介绍了APC会在何时被执行,内核APC会在线程切换时执行用户APC会在0环返回3环时执行。无论是内核APC还是用户APC最终都会被函数KiDeliverApc处理,区别在于传入的参数不同。本篇从内核APC执行的角度来分析一下KiDeliverApc函数。

KiDeliverApc

函数原型

在分析KiDeliverApc函数前,先来看函数原型

Code
1
2
3
4
VOID KiDeliverApc (
IN KPROCESSOR_MODE PreviousMode,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame)

函数参数:

  • PreviousMode:先前模式;值为0时,仅处理内核APC,值为1时,先处理内核APC再处理用户APC
  • ExceptionFrame:异常结构。
  • TrapFrame:陷阱帧,在API函数调用过程的分析中,了解到这是3环进0环时保存现场用到的结构

函数分析

part1

这里把KiDeliverApc分为3个方框来看。首先是准备工作,包括分配栈空间,保存现场,获取当前线程,获取TrapFrame等基本操作;接下来,上锁,进入原子操作。

再来看用红色方框框住的部分,这里有着比较关键的处理逻辑。先将KernelApcPending的值置为0,意味着要开始处理内核APC了,然后再去取位于ApcState结构内核APC队列上的内核Kapc块,这时会做一个判断,比较当前地址与内核APC队列上存着的值是否相同,之所以这样比较的原因是,微软在设计链表时,链表为空时不会存储空,而是存当前链表的地址。这样若相同,意味着内核APC队列为空,否则说明有待处理的内核APC。

然后进入到一个跳转,若判断出存在待处理的内核APC,则会进入跳转,否则将会继续执行,进入到用户APC的处理范畴。

part2

这部分代码核心逻辑主要有3个部分,先看橙色方框的部分,当取到KAPC结构体后,会先跳到这里来。这部分的一个操作是将KAPC-0xC处的地址,赋值给edi寄存器,为何要这么做呢?因为KAPC结构体不是以首地址的形式挂在ApcState的APC队列上的,而是挂在0xC偏移处,因此当取到KAPC结构体后,需要减去这段偏移,才能获取到KAPC的首地址

有了KAPC后,可以获得NormalRoutine这个字段的值,在APC挂入过程中提到过这个字段的含义若是内核APC,它就是真正的内核APC函数;若是用户APC,则是用户APC的总入口。搞清楚这个逻辑后,就可以看红框的这个判断和跳转了。如果NormalRoutine的值不为0,则跳转,继续看part3的分析。如果不为0,说明该内核APC没有内核APC函数,会向下继续执行到绿框,可以看到,这里会跳转回去,继续判断内核APC队列中是否有下一个APC

part3

先看橙色框住的部分,刚开始会先有两个判断,第一个判断当前线程KernelApcInProgress字段的值,看是否有别的内核APC处于进程中正在执行,若有,就跳转离开;否则将会进入到第二个判断,判断当前线程的KernelApcDisable字段的值,判断当前线程是否禁用了内核APC,若被禁用,同样跳转离开;否则继续执行。

当两个判断都通过的时候,下一步先从内核APC队列中摘除当前KAPC块。然后调用KernelRoutine函数释放KAPC结构体占用的空间。

再往下看,可以看到红色框住的部分,通过call指令调用了NormalRoutine函数并完成执行,这个函数就是真正的APC中的内核函数。至此,KiDeliverApc完成对内核APC的执行。也可以验证结论,在内核APC中,NormalRoutine就是真正的内核APC函数。执行完后,通过跳转指令,继续判断内核APC队列中是否有下一个APC。

执行流程

在KiDeliverApc函数中,具体的执行流程可以参考下图:

参考资料

  1. 滴水中级预习班
  2. https://blog.csdn.net/qq_41988448/article/details/104240902 (CSDN lzyddf笔记)
  3. https://blog.csdn.net/qq_38474570/article/details/104326170 (CSDN 鬼手笔记)
  4. https://blog.csdn.net/weixin_42052102/article/details/83339412 (CSDN My classmates笔记)
Author: cataLoc
Link: http://cataloc.gitee.io/blog/2020/08/08/%E5%86%85%E6%A0%B8APC%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶