APC的本质

 Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.htmlhtml

APC的本质异步

1、对于线程关闭问题的启发函数

  线程,自己占据CPU,对CPU有直接控制权。spa

  这就存在一个问题,若是一个线程不想关闭本身,则外界是没法干涉它的。线程

  所以,线程须要本身杀死本身。code

  可是线程自己是代码,其并不知道什么时候才须要杀死本身,这时须要咱们另外提供代码,让其杀死本身。orm

  所以,线程的操做机制就是:定时检查是否有另外执行的代码,而后去执行。该代码(函数),就是APC。htm

 

2、APC介绍blog

  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,能够查看代码(注意并非指向函数地址)

3、何时执行APC函数

  1. 先介绍两个函数

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

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

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

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

    

 

 

 

4、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], 1
.text:004667FE                 jz      short loc_466834
.text:00466800
.text:00466800 loc_466800:                             ; CODE XREF: _KiServiceExit2+8↑j
.text:00466800                                         ; _KiServiceExit2+41↓j
.text:00466800                 mov     ebx, ds:0FFDFF124h ; 获取Kthread
.text:00466806                 mov     byte ptr [ebx+2Eh], 0
.text:0046680A                 cmp     byte ptr [ebx+4Ah], 0 ; 判断是否有用户APC请求
.text:0046680E                 jz      short loc_466834 ; 若是有用户APC请求会走这里
.text:00466810                 mov     ebx, ebp
.text:00466812                 mov     ecx, 1          ; NewIrql
.text:00466817                 call    ds:__imp_@KfRaiseIrql@4 ; KfRaiseIrql(x)
.text:0046681D                 push    eax
.text:0046681E                 sti
.text:0046681F                 push    ebx
.text:00466820                 push    0
.text:00466822                 push    1
.text:00466824                 call    _KiDeliverApc@12 ; 该函数实现对APC的处理
.text:00466829                 pop     ecx             ; NewIrql
.text:0046682A                 call    ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
.text:00466830                 cli
.text:00466831                 jmp     short loc_466800 ; 获取Kthread
相关文章
相关标签/搜索