欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]DPC机制分析记录

[原创]DPC机制分析记录

APC机制分析中是主要分析了APC的执行流程,初始化、插入和派发,这里主要分析一下DPC的相关机制。
在此之前总结一下APC主要的应用点,由于初学不久,很多不全的请补充分享一下,毕竟对大神可能很简单的,对我们小白其实根本看不到路,甚至不知道有这条路,谢谢。

APC主要的使用场景

  1. windows内部异步IO
  2. APC注入,但是限制条件太多,感觉不实用
  3. 通过在APC的KernelRouting中回调PspExitThread,达到结束当前APC线程的目的,由于结束进程其实就是把进程的所有线程都结束掉,故可用来结束进程。
    源码如下:
    PspTerminateThreadByPointer;
    
    KeInitializeApc (ExitApc,
    
                    PsGetKernelThread (Thread),
    
                    OriginalApcEnvironment,
    
                    PsExitSpecialApc,//里面调用了PspExitThread用于结束线程
    
                    PspExitApcRundown,
    
                    PspExitNormalApc,
    
                    KernelMode,
    
                    ULongToPtr (ExitStatus));
    
    

DPC(Delayed Procedure Call)的创建

在用户层没有可以对DPC进行相关操作的函数,直接从0环开始分析。
KiInitializeDpc用于初始化DPC对象,
该函数只被KeInitializeDpcKeInitializeThreadedDpc所调用,这个和DPC的类型有关,下面会分析到。

首先看一下DPC相关的数据结构把,实际在内核系统中,各种3环的抽象概念基本都是有对应的数据结构可以追溯的。
typedef struct _KDPC_DATA {

    LIST_ENTRY DpcListHead;

    KSPIN_LOCK DpcLock;

    volatile ULONG DpcQueueDepth; //深度

    ULONG DpcCount;

} KDPC_DATA, *PKDPC_DATA;

typedef struct _KDPC {

    UCHAR Type; //DPC类型(分为普通DPC和线程化DPC)

    UCHAR Importance; //该DPC的重要性,将决定挂在队列头还是尾

    UCHAR Number; //第5位为0就表示当前cpu,否则,最低4位表示目标cpu号

    UCHAR Expedite; 

    LIST_ENTRY DpcListEntry; //用来挂入dpc链表,和_KDPC_DATA中的DpcListHead对应,

                             //内核中很多这样的结构安排

    PKDEFERRED_ROUTINE DeferredRoutine; //dpc函数

    PVOID DeferredContext; //dpc函数的参数

    PVOID SystemArgument1;

    PVOID SystemArgument2;

    PVOID DpcData;

} KDPC, *PKDPC, *PRKDPC;

KiInitializeDpc分析:

     Dpc->Type = (UCHAR)DpcType;//和ApcObject一样,属于_KOBJECTS枚举,分为DpcObject和ThreadedDpcObject(线程化的DPC对象)

    Dpc->Importance = MediumImportance; //重要性决定了DPC挂在队列的顺序

    Dpc->Number = 0; //初始的目标cpu为当前cpu

    Dpc->Expedite = 0;

    Dpc->DeferredRoutine = DeferredRoutine; //函数地址

    Dpc->DeferredContext = DeferredContext; //函数参数

    Dpc->DpcData = NULL; //表示该DPC尚未挂入任何DPC队列

以上就是初始的全部内容,十分简单。
插入DPC在KeInsertQueueDpc中实现。

KeInsertQueueDpc分析

首先明确一点,如果当前DPC已经在DPC queue中,那么实际上什么都不做。
//首先进行参数检查

 if (Dpc->Number >= MAXIMUM_PROCESSORS/*32*/) {

         //修正Number

        Number = Dpc->Number - MAXIMUM_PROCESSORS;

        //KiProcessorBlock是PKPRCB的数组,

        //这里取出DPC->Number对应的_KPRCB是因为DPC是CPU核心相关

        TargetPrcb = KiProcessorBlock[Number];

    } else {

        //参数不需要修正的分支,就是当前CPU的PRCB

        Number = CurrentPrcb->Number;

        TargetPrcb = CurrentPrcb;

    }

紧接着获取_KDPC_DATA的指针

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功