APC(二)

分析KeInsertQueueApc

BOOLEAN KeInsertQueueApc (
    __inout PRKAPC Apc, //APC的结构
    __in_opt PVOID SystemArgument1,
    __in_opt PVOID SystemArgument2,//参数
    __in KPRIORITY Increment//优先级
    )

然后把ntkrnlpa.exe放进IDA里面进行反编译,然后再找到这个函数。

char __stdcall KeInsertQueueApc(int apc, int SystemArgument1, int SystemArgument2, int Increment)
{
  int v4; // edi
  volatile signed __int32 *v5; // ebx
  char bRet; // [esp+13h] [ebp-Dh]
  int spinCount; // [esp+14h] [ebp-Ch]
  unsigned __int8 NewIrql; // [esp+18h] [ebp-8h]
  _KPRCB *kpcr; // [esp+1Ch] [ebp-4h]

  v4 = *(_DWORD *)(apc + 8);
  spinCount = 0;
  NewIrql = KeRaiseIrqlToDpcLevel();//提高当前IQL等级为DPC_LEVEL
  kpcr = KeGetPcr()->Prcb;
  v5 = (volatile signed __int32 *)(v4 + 96);
  while ( _InterlockedExchange(v5, 1) )//加锁 确保中途的过程不会被打断
  {
    do
    {
      if ( ++spinCount & HvlLongSpinCountMask || !(HvlEnlightenments & 0x40) )//验证加的锁
        _mm_pause();
      else
        HvlNotifyLongSpinWait(spinCount);
    }
    while ( *v5 );
  }
  if ( *(_DWORD *)(v4 + 184) & 0x20 && *(_BYTE *)(apc + 46) != 1 )
  {
    *(_DWORD *)(apc + 36) = SystemArgument1;
    *(_BYTE *)(apc + 46) = 1;
    *(_DWORD *)(apc + 40) = SystemArgument2;
    KiInsertQueueApc((signed __int32)kpcr, apc, NewIrql);//这个函数才起到了插入APC的作用
    bRet = 1;
  }
  else
  {
    bRet = 0;
  }
  _InterlockedAnd(v5, 0);//解锁
  KiExitDispatcher((int)kpcr, 0, 1, Increment, NewIrql);
  return bRet;
}

然后跟进KiInsertQueueApc函数中,继续去查看

char __fastcall KiInsertQueueApc(signed __int32 KPCR, int KAPC, unsigned __int8 IRQL)
{
  int v3; // edi
  int v4; // esi
  int v5; // ecx
  char v6; // bl
  int *v7; // ecx
  int v8; // edx
  int *v9; // eax
  int v10; // ecx
  _DWORD *v11; // edx
  int *v12; // eax
  int v13; // ecx
  int *v14; // eax
  int v15; // edx
  int *v16; // ecx
  int v17; // eax
  int v18; // ecx
  volatile signed __int32 *v19; // ebx
  volatile signed __int32 *v20; // edi
  int v21; // ebx
  char v22; // al
  unsigned int v23; // eax
  int v24; // esi
  unsigned int v25; // ecx
  int v26; // eax
  _KPRCB *v27; // eax
  char v29; // [esp+Fh] [ebp-19h]
  char v30; // [esp+Fh] [ebp-19h]
  int v31; // [esp+10h] [ebp-18h]
  signed __int32 v32; // [esp+14h] [ebp-14h]
  int v33; // [esp+18h] [ebp-10h]
  __int16 v34; // [esp+1Ch] [ebp-Ch]
  __int16 v35; // [esp+1Eh] [ebp-Ah]
  int v36; // [esp+24h] [ebp-4h]

  v3 = KAPC;
  v4 = *(_DWORD *)(KAPC + 8);                   // 获取线程
  v32 = KPCR;
  if ( *(_BYTE *)(KAPC + 0x2C) == 3 )           // 0x2c KAPC.ApcStateIndex 判断APC的索引
    *(_BYTE *)(KAPC + 0x2C) = *(_BYTE *)(v4 + 0x134);// 0x134 Kthread.ApcStateIndex 如果为3则选择当前的索引
  v5 = *(_DWORD *)(v4 + 4 * *(char *)(KAPC + 0x2C) + 0x168);// 获取0x168 Kthread.ApcStatePointer
  v6 = *(_BYTE *)(KAPC + 0x2D);                 // 0x2D KAPC.ApcMode 获取是内核还是用户
  if ( *(_DWORD *)(KAPC + 0x1C) )               // 0x1c KAPC.NormalRoutine 判断有无正常函数表
  {
    v29 = 1;
    if ( v6 && *(void (__stdcall **)(int, int, int, int, int))(KAPC + 0x14) == PsExitSpecialApc )// 0x14 KAPC.KernelRoutine 判断是否是退出线程的APC
    {
      *(_BYTE *)(v4 + 0x56) = 1;
      v7 = (int *)(v5 + 8 * v6);                // _KAPC_STATE
      v8 = *v7;
      v9 = (int *)(v3 + 0xC);
      *v9 = *v7;
      v9[1] = (int)v7;
      *(_DWORD *)(v8 + 4) = v3 + 0xC;           // 插入到头节点
      *v7 = v3 + 0xC;
    }
    else
    {
      v10 = v5 + 8 * v6;
      v11 = *(_DWORD **)(v10 + 4);
      v12 = (int *)(v3 + 12);
      *v12 = v10;
      v12[1] = (int)v11;
      *v11 = v3 + 12;
      *(_DWORD *)(v10 + 4) = v3 + 12;           // 如果不是就插入到尾节点
    }
  }
  else
  {
    v13 = v5 + 8 * v6;                          // 指向下一个节点
    v14 = *(int **)(v13 + 4);
    v29 = 0;
    while ( v14 != (int *)v13 && v14[4] )
      v14 = (int *)v14[1];
    v15 = *v14;                                 // KAPC.NormalRoutine
    v16 = (int *)(v3 + 12);
    *v16 = *v14;
    v16[1] = (int)v14;
    *(_DWORD *)(v15 + 4) = v3 + 12;
    *v14 = v3 + 12;
  }
  v17 = *(unsigned __int8 *)(v4 + 0x134);       // 0x134 Kthread.ApcStateIndex
  v18 = *(char *)(v3 + 0x2C);                   // 0x2c KAPC.ApcStateIndex 判断APC的索引
  if ( v18 == v17 )                             // 判断是否是一个 如果不一样直接跳走
  {
    LOBYTE(v17) = v32;
    if ( v4 == *(_DWORD *)(v32 + 4) )
    {
      if ( !v6 && (!*(_DWORD *)(v4 + 0x84) || !v29 && !*(_WORD *)(v4 + 0x86)) )// +0x084 KernelApcDisable +0x086 SpecialApcDisable 判断是否是特殊
                                                // 
      {
        *(_BYTE *)(v4 + 0x55) = 1;
        if ( IRQL < 1u )                        // 中断 检测APC是否需要执行
        {
          *(_DWORD *)(v4 + 60) |= 0x100u;       // 0x60 Kthread.ApcQueueLock
          return v17;
        }
LABEL_55:
        LOBYTE(v18) = 1;
        LOBYTE(v17) = HalRequestSoftwareInterrupt(v18);// 中断 然后执行APC
        return v17;
      }
    }
    else if ( v6 )                              // 如果是用户APC
    {
      LOBYTE(v17) = *(_BYTE *)(v4 + 0x68);      // Kthread.State
      if ( (_BYTE)v17 == 5 )                    // 一般直接返回
      {
        v30 = 0;
        v20 = (volatile signed __int32 *)(v4 + 52);
        v21 = 0;
        while ( _InterlockedExchange(v20, 1) )
        {
          do
          {
            if ( ++v21 & HvlLongSpinCountMask || !(HvlEnlightenments & 0x40) )
              _mm_pause();
            else
              HvlNotifyLongSpinWait(v21);
          }
          while ( *v20 );
        }
        if ( *(_BYTE *)(v4 + 104) == 5
          && *(_BYTE *)(v4 + 107) == 1
          && (*(_BYTE *)(v4 + 60) & 0x20 || *(_BYTE *)(v4 + 86)) )
        {
          v22 = KiSignalThread(v32, 192);
          *(_BYTE *)(v4 + 56) |= 0x20u;
          v30 = v22;
        }
        LOBYTE(v17) = 0;
        _InterlockedAnd(v20, 0);
        if ( v30 )
          *(_BYTE *)(v4 + 86) = 1;
      }                                         // 到这
    }
    else
    {
      *(_BYTE *)(v4 + 0x55) = 1;
      _InterlockedExchange(&v33, v32);          // 初始化
      v17 = *(unsigned __int8 *)(v4 + 0x68);    // Kthread.State
      if ( v17 == 2 )
      {
        v23 = KeGetCurrentProcessorNumberEx(0); // 获取处理器编号
        v18 = *(_DWORD *)(v4 + 0x58);
        if ( v23 == v18 )
          goto LABEL_55;
        v24 = *(_DWORD *)(v4 + 0x58);
        v34 = 1;
        v35 = 1;
        v36 = 0;
        v25 = (unsigned int)KiProcessorIndexToNumberMappingTable[v24] >> 6;
        v26 = KiProcessorIndexToNumberMappingTable[v24] & 0x3F;
        if ( v25 >= 1 )
          v34 = v25 + 1;
        *(&v36 + v25) |= KiMask32Array[v26];    // 获取位图
        v27 = KeGetPcr()->Prcb;
        ++v27->IpiSendSoftwareInterruptCount;
        LOBYTE(v17) = KiIpiSend(&v34);
      }
      else if ( v17 == 5 )
      {
        v31 = 0;
        v19 = (volatile signed __int32 *)(v4 + 52);
        while ( _InterlockedExchange(v19, 1) )
        {
          do
          {
            if ( ++v31 & HvlLongSpinCountMask || !(HvlEnlightenments & 0x40) )
              _mm_pause();
            else
              HvlNotifyLongSpinWait(v31);
          }
          while ( *v19 );
        }
        if ( *(_BYTE *)(v4 + 0x68) == 5
          && !*(_BYTE *)(v4 + 0x6A)
          && !*(_WORD *)(v4 + 0x86)
          && (!*(_DWORD *)(v3 + 0x1C) || !*(_WORD *)(v4 + 0x84) && !*(_BYTE *)(v4 + 0x54)) )
        {
          KiSignalThread(v32, 256);
          *(_BYTE *)(v4 + 56) |= 0x10u;
        }
        LOBYTE(v17) = 0;
        _InterlockedAnd(v19, 0);
      }
    }
  }
  return v17;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows APC(Asynchronous Procedure Call)是一种异步过程调用机制,它允许一个线程在另一个线程上异步执行指定的函数。APC 机制是 Windows 操作系统中非常重要的一部分,它被广泛用于实现各种系统功能,例如异步 I/O、线程池等。 在 Windows 中,每个线程都有一个 APC 队列,该队列中存储了需要在该线程上异步执行的函数。当一个线程进入 Alertable 状态时(例如调用 Sleep、WaitForSingleObject 等函数),它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 APC 机制的具体原理如下: 1. 创建 APC 对象 首先,创建一个 APC 对象,该对象包含要在目标线程上执行的函数和参数。 2. 将 APC 对象插入到目标线程的 APC 队列 使用 QueueUserAPC 函数将 APC 对象插入到目标线程的 APC 队列中。当目标线程进入 Alertable 状态时,它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 3. 触发目标线程进入 Alertable 状态 为了让目标线程进入 Alertable 状态,可以使用 Sleep、WaitForSingleObject 等函数来实现。当目标线程进入 Alertable 状态时,它会检查自己的 APC 队列中是否有待处理的 APC,如果有,则会立即执行 APC 中指定的函数。 总之,APC 机制是 Windows 操作系统中非常重要的一部分,它提供了一种有效的异步过程调用机制,可以在不阻塞目标线程的情况下异步执行指定的函数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值