10 DPC

DPC是什么?它的英文全称为Deferred Procedure Call,即延迟过程调用。它最初作用是设计为中断服务程序的一部分,用来解决中断服务处理时间过长的问题。因为每次触发中断,都会关中断,然后执行中断服务例程。由于关中断了,所以中断服务例程必须短小精悍,不能消耗过多时间,否则会导致系统丢失大量其他中断。但是有的中断,其中断服务例程要做的事情本来就很多,那怎么办?于是,可以在中断服务例程中先执行最紧迫的那部分工作,然后把剩余的相对来说不那么重要的工作移入到DPC函数中去执行。
  每当触发一个中断时,中断服务例程可以在当前CPU中插入一个DPC,当执行完ISR,退出ISR后, CPU就会扫描它的DPC队列,依次执行里面的每个DPC,当执行完DPC后,才又回到当前线程的中断处继续执行。
  既然提到ISR,那么它是什么?它的英文全称为Interrupt Service Routines,即中断服务处理。在Windows中如果有认为不太重要的操作会被打包成一个KDPC结构体,如下所示:

kd> dt _KDPC
ntdll!_KDPC
   +0x000 Type             : Int2B ;指明该结构体的类型,值为0x13
   +0x002 Number           : UChar ;指明属于哪个KPCR
   +0x003 Importance       : UChar ;优先级,取值0-20最低,2最高,优先级越高越优先执行,初始化默认值为1
   +0x004 DpcListEntry     : _LIST_ENTRY ;DPC链表,和进程线程链表一样,挂到腰上
   +0x00c DeferredRoutine  : Ptr32     void  ;DPC的回调函数地址
   +0x010 DeferredContext  : Ptr32 Void ;回调函数上下文,非必须
   +0x014 SystemArgument1  : Ptr32 Void ;回调函数的参数,非必须
   +0x018 SystemArgument2  : Ptr32 Void ;回调函数的参数,非必须
   +0x01c Lock             : Ptr32 Uint4B DPC结构体的锁

打包完毕后,会插入到KPCRB的DpcListHead成员中,等待触发调用时机

kd> dt _KPRCB
ntdll!_KPRCB
   ……
   +0x4b0 DpcTime          : Uint4B
   +0x4b4 DebugDpcTime     : Uint4B
   ……
   +0x860 DpcListHead      : _LIST_ENTRY
   +0x868 DpcStack         : Ptr32 Void
   +0x86c DpcCount         : Uint4B
   +0x870 DpcQueueDepth    : Uint4B
   +0x874 DpcRoutineActive : Uint4B
   +0x878 DpcInterruptRequested : Uint4B
   +0x87c DpcLastCount     : Uint4B
   +0x880 DpcRequestRate   : Uint4B
   ……
   +0x8a0 DpcLock          : Uint4B
   ……
   +0x8c0 CallDpc          : _KDPC
   ……

用户或者驱动创建的DPC,还可以加定时器,到指定时间进行触发,但不会挂到KPCR当中,会挂到时钟任务当中

DPC初始化

; void __stdcall KeInitializeDpc(PRKDPC Dpc, PKDEFERRED_ROUTINE DeferredRoutine, PVOID DeferredContext)
                public _KeInitializeDpc@12
_KeInitializeDpc@12 proc near           ; CODE XREF: IopInitializeIrpStackProfiler()+29↑p
                                        ; VdmpDelayInterrupt(x)+26B↓p ...

Dpc             = dword ptr  8
DeferredRoutine = dword ptr  0Ch
DeferredContext = dword ptr  10h

                mov     edi, edi
                push    ebp
                mov     ebp, esp
                mov     eax, [ebp+Dpc]
                mov     ecx, [ebp+DeferredRoutine]
                and     dword ptr [eax+1Ch], 0
                mov     [eax+0Ch], ecx
                mov     ecx, [ebp+DeferredContext]
                mov     word ptr [eax], 13h
                mov     byte ptr [eax+2], 0
                mov     byte ptr [eax+3], 1
                mov     [eax+10h], ecx
                pop     ebp
                retn    0Ch
_KeInitializeDpc@12 endp

DPC插入

DPC的优先级高,就会插到DPC链表的前面,如果低就会插到末尾

BOOLEAN __stdcall KeInsertQueueDpc(PRKDPC Dpc, PVOID SystemArgument1, PVOID SystemArgument2)
{
  _KPRCB *kprcb; // esi
  bool Importance; // zf
  _LIST_ENTRY *DpcListHead; // ecx
  _LIST_ENTRY *DpcListEntry; // eax
  _LIST_ENTRY *v9; // edx
  _LIST_ENTRY *v10; // edx
  KIRQL NewIrql; // [esp+Fh] [ebp-1h]

  NewIrql = KfRaiseIrql(0x1Fu);
  kprcb = MEMORY[0xFFDFF020];
  _ECX = &Dpc->Lock;
  _EDX = MEMORY[0xFFDFF020] + 0x8A0;            // DpcLock
  __asm { cmpxchg [ecx], edx }
  ++kprcb->DpcCount;
  ++kprcb->DpcQueueDepth;
  Importance = Dpc->Importance == 2;
  Dpc->SystemArgument1 = SystemArgument1;
  Dpc->SystemArgument2 = SystemArgument2;
  DpcListHead = &kprcb->DpcListHead;
  DpcListEntry = &Dpc->DpcListEntry;
  if ( Importance )
  {
    v9 = DpcListHead->Flink;
    DpcListEntry->Flink = DpcListHead->Flink;
    Dpc->DpcListEntry.Blink = DpcListHead;
    v9->Blink = DpcListEntry;
    DpcListHead->Flink = DpcListEntry;
  }
  else
  {
    v10 = kprcb->DpcListHead.Blink;
    DpcListEntry->Flink = DpcListHead;
    Dpc->DpcListEntry.Blink = v10;
    v10->Flink = DpcListEntry;
    kprcb->DpcListHead.Blink = DpcListEntry;
  }
  if ( !kprcb->DpcRoutineActive
    && !kprcb->DpcInterruptRequested
    && (Dpc->Importance
     || kprcb->DpcQueueDepth >= kprcb->MaximumDpcQueueDepth
     || kprcb->DpcRequestRate < kprcb->MinimumDpcRate) )
  {
    LOBYTE(DpcListHead) = 2;
    kprcb->DpcInterruptRequested = 1;
    HalRequestSoftwareInterrupt(DpcListHead);
  }
  KfLowerIrql(NewIrql);
  return 1;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值