APC的本质
阅读原文时间:2023年07月15日阅读:1

_**Windows内核分析索引目录https://www.cnblogs.com/onetrainee/p/11675224.html**___

APC的本质

一、对于线程关闭问题的启发

线程,本身占据CPU,对CPU有直接控制权。

这就存在一个问题,如果一个线程不想关闭自己,则外界是无法干涉它的。

因此,线程需要自己杀死自己。

但是线程本身是代码,其并不知道何时才需要杀死自己,这时需要我们另外提供代码,让其杀死自己。

因此,线程的操作机制就是:定时检查是否有另外执行的代码,然后去执行。该代码(函数),就是APC。

二、APC介绍

1. APC,即Asynchronous procedure call,异步程序调用。

我们理解“异步”这个词,线程本身的代码是“同步”的,在此之外可以认为是异步。

2. _KAPC_STATE 结构体(具体作用右侧已经标记出来)

其在 _KTHREAD + 0x34 的位置。

kd> dt _KAPC_STATE       ntdll!_KAPC_STATE        +0x000 ApcListHead      : [2] _LIST_ENTRY  // APC队列,两个双向链表,分别指向用户与内核结构的APC        +0x010 Process          : Ptr32 _KPROCESS // 线程所属的进程或者挂靠的进程        +0x014 KernelApcInProgress : UChar  //  表示当前内核中的APC程序是否正在执行        +0x015 KernelApcPending : UChar  // 表示APC队列中是否有内核APC函数,如果有为1,否则为0.        +0x016 UserApcPending   : UChar   // 表示APC队列中是否用用户APC函数,如果有为1,否则为0.__

3. _KAPC 结构体

kd> dt _KAPC        ntdll!_KAPC        +0x000 Type             : Int2B        +0x002 Size             : Int2B        +0x004 Spare0           : Uint4B        +0x008 Thread           : Ptr32 _KTHREAD        +0x00c ApcListEntry     : _LIST_ENTRY        +0x014 KernelRoutine    : Ptr32     void        +0x018 RundownRoutine   : Ptr32     void        +0x01c NormalRoutine    : Ptr32     void        +0x020 NormalContext    : Ptr32 Void        +0x024 SystemArgument1  : Ptr32 Void        +0x028 SystemArgument2  : Ptr32 Void        +0x02c ApcStateIndex    : Char        +0x02d ApcMode          : Char        +0x02e Inserted         : UChar     在 _KAPC_STATE中前两个双向链表指向的就是一个个 _KAPC函数成员, 通过+0x01c NormalRoutine,可以查看代码(注意并不是指向函数地址)

三、什么时候执行APC函数

1. 先介绍两个函数

a. KiServiceExit函数:这个函数是系统调用、异常或中断的必经之路。

b. KiDeliverApc函数: 负责执行APC函数。

2. 在执行 KiServiceExit函数时,其会从线程结构体中拿出 __KAPC_STATE.___KernelApcPending是否为零。

如果不为零,则会调用__KiDeliverApc去执行APC函数,当执行完一次后再跳转回来进行遍历。

四、KiServiceExit2部分源码解读:

在WindowsXp 专业版的 ntoskrnl.exe 中并未搜索到 KiServiceExit 函数;在有关快速调用的代码中查看到 KiServiceExit2 (ntkrnlpa.exe)

.text:004667F0 cli
.text:004667F1 test dword ptr [ebp+70h], 20000h
.text:004667F8 jnz short loc_466800 ; 获取Kthread
.text:004667FA test byte ptr [ebp+6Ch],
.text:004667FE jz short loc_466834
.text:
.text: loc_466800: ; CODE XREF: _KiServiceExit2+↑j
.text: ; _KiServiceExit2+↓j
.text: mov ebx, ds:0FFDFF124h ; 获取Kthread
.text: mov byte ptr [ebx+2Eh],
.text:0046680A cmp byte ptr [ebx+4Ah], ; 判断是否有用户APC请求
.text:0046680E jz short loc_466834 ; 如果有用户APC请求会走这里
.text: mov ebx, ebp
.text: mov ecx, ; NewIrql
.text: call ds:__imp_@KfRaiseIrql@ ; KfRaiseIrql(x)
.text:0046681D push eax
.text:0046681E sti
.text:0046681F push ebx
.text: push
.text: push
.text: call _KiDeliverApc@ ; 该函数实现对APC的处理
.text: pop ecx ; NewIrql
.text:0046682A call ds:__imp_@KfLowerIrql@ ; KfLowerIrql(x)
.text: cli
.text: jmp short loc_466800 ; 获取Kthread

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章