[原创]DPC机制分析记录
在 APC机制分析中是主要分析了APC的执行流程,初始化、插入和派发,这里主要分析一下DPC的相关机制。
在此之前总结一下APC主要的应用点,由于初学不久,很多不全的请补充分享一下,毕竟对大神可能很简单的,对我们小白其实根本看不到路,甚至不知道有这条路,谢谢。
APC主要的使用场景
- windows内部异步IO
- APC注入,但是限制条件太多,感觉不实用
- 通过在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对象,
该函数只被KeInitializeDpc和KeInitializeThreadedDpc所调用,这个和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。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
复制成功
