首页
社区
课程
招聘
[原创]内核APC源码剖析以及Vista之后调试机制的变化分析
发表于: 2021-4-14 19:36 8174

[原创]内核APC源码剖析以及Vista之后调试机制的变化分析

2021-4-14 19:36
8174

1.APC属于内核对象,所有的内核对象都有一个结构体 -- 1:1(数据模型)

APC内核对象

1.APC用于特定的线程,一个线程具有多个APC  -- 1:N

线程中相关内核重要结构

先解释一下:什么是激活的APC?

    激活的APC是指当前可以被交付的APC。首先APC是属于线程的,线程又属于进程,但是线程所属的这个进程不一定亲生的,比如挂靠到另一个进程中去。

    如果当一个线程挂靠到另一个进程中去,那么此时线程一般都不会交付原来进程环境中的APC,那么就要让这个APC进行备份一下。所以,在线程挂靠到另一个进程中时,它首先会将当前+0x050 ApcState保存到+0x240 SavedApcState字段中,同时ApcStatePointer[_KAPC.ApcStateIndex]指向的就SavedApcState

   KTHREAD.ApcStateIndex指向的ApcState。

   谨记:ApcState总是被激活的那一个,也就是被执行的那一个。

   可能比较绕,简而言之KAPC中的ApcStateIndex代表的是它所处的环境(或者它想要的环境),而KTHREAD中的ApcStateIndex指向的当前线程的环境。

由于这篇不设计用户APC,所以不概述用户APC的特征!

普通内核APC:

             NormalRoutine !=0 && ApcMode ==0

特殊内核APC:

             NormalRoutine ==0 && ApcMode ==0 && NormalContext==0 (三无)

KeInitializeApc:初始化内核APC

VOID

KeInitializeApc (

    IN PRKAPC Apc,  //得自己分配拟空间

    IN PRKTHREAD Thread, //指明线程

    IN KAPC_ENVIRONMENT Environment, //指明KAPC.ApcStateIndex    

    IN PKKERNEL_ROUTINE KernelRoutine,

    IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,

    IN PKNORMAL_ROUTINE NormalRoutine OPTIONAL,

    IN KPROCESSOR_MODE ApcMode OPTIONAL,

    IN PVOID NormalContext OPTIONAL

    )

这里剖析一下Environment:

    typedef enum _KAPC_ENVIRONMENT {

         OriginalApcEnvironment,

         AttachedApcEnvironment,

         CurrentApcEnvironment,

         InsertApcEnvironment

     } KAPC_ENVIRONMENT;

其实OriginalApcEnvironment代表的是,你想往当前线程插入,什么意思呢?其实就是“嫁鸡随鸡,嫁狗随狗”,不管是当前线程是挂靠了还是没挂靠,我都只认现在。AttachedApcEnvironment代表的是往挂靠的线程插入,它的意思就是我不管你挂靠了还没挂靠,我都认为是你挂靠了!  -- 这种就承担了一种风险,如果它没有挂靠,那么再也执行不了!CurrentApcEnvironmentInsertApcEnvironment它们俩更像是代表了当前代码所处的阶段。比如CurrentApcEnvironment代表的就是正在执行KeInitializeApc函数。InsertApcEnvironment代表是正在执行KiInsertQueueApc(Ki不是Ke)

前两种像是天生的,后两种就是后生的(延迟)...

KeInsertQueueApc:插入APC

BOOLEAN

KeInsertQueueApc (

    IN PRKAPC Apc,

    IN PVOID SystemArgument1,

    IN PVOID SystemArgument2,

    IN KPRIORITY Increment

    )

以KiInsertQueueApc函数为分界线,上半部分其实就只做了两件事:

       一件是,提升IRQL,只让时钟中断和IPI(核间中断)打断它。

       另一件,判断所属的线程是否开启了APC队列。--- 这里引出一个问题,如果一个线程没有开启APC队列后,那么它怎么结束自己呢?或者说是没有办法通过APC结束掉自己。

众人都知KiDeliverApc派发APC,殊不知我在KiInsertQueueApc中已经开始偷偷筹划。

接下来就探一探KiInsertQueueApc。

 

KiInsertQueueApc:实际插入APC的函数

VOID

FASTCALL

KiInsertQueueApc (

    IN PKAPC InApc,

    IN KPRIORITY Increment

    )

此时我们要考虑两个问题:

第一个问题:

    SpecialApcDisable为什么会等于FALSE?其实纵观之前代码,我们发现没有一处修改这里,这说明这个变量有可能是别人禁用APC的标志。

 

我举一个例子:

    KeEnterGuardedRegionThread函数内部会对这个标志进行修改。

这就解释了MSDN上所描述APC关于互斥体的那段。可见SpecialApcDisable体现的也是临界区的用途。


第二个问题:

      KiUnwaitThread只会将线程从等待网上摘下来,并不能立马变为就绪线程,而是延迟就绪线程,所以并不能去派发APC,那么如何去派发呢?

这时就要说出KiExitDispatcher(LockHandle.OldIrql)的作用了,它第一个功能是降低IRQL到之前的等级,其次万一KiInsertQueueApc内核唤醒的是等待线程(术语:延迟就绪线程),还会为这个延迟就绪的线程选择合适的处理器,从而去派发。

谨记:此处的派发时通过SwapContext,切换线程时候的才会有执行KiDeliverApc的时机。

KiDeliverApc:派发APC

VOID

KiDeliverApc (

    IN KPROCESSOR_MODE PreviousMode,


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-8-22 09:51 被烟花易冷丶编辑 ,原因:
上传的附件:
收藏
免费 4
支持
分享
最新回复 (6)
雪    币: 1129
活跃值: (2731)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2021-4-15 16:16
0
雪    币: 47147
活跃值: (20415)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
能不能将文章整理一下,直接放到帖子里?
方便阅读,同时方便论坛搜索。
2021-4-16 14:07
0
雪    币: 1230
活跃值: (1765)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
kanxue 能不能将文章整理一下,直接放到帖子里? 方便阅读,同时方便论坛搜索。
好的,我整理一下
2021-4-18 10:15
0
雪    币: 239
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
楼主PDF内容是不是打算发篇小论文的,感觉写的很好,再附加点实例代码就好看的更明白了。
2021-6-24 18:02
0
雪    币: 1230
活跃值: (1765)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
abel346 楼主PDF内容是不是打算发篇小论文的,感觉写的很好,再附加点实例代码就好看的更明白了。
一点心得而已...论文不至于 hhh,我一直想写一篇关于内存的设计的
2021-6-24 18:40
0
雪    币: 183
活跃值: (2427)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2021-8-24 18:51
0
游客
登录 | 注册 方可回帖
返回
//