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
    评论
### 回答1: SAS(统计分析系统)是一种广泛应用于数据分析和统计建模的软件工具。实现APC(age-period-cohort)年龄时期队列涉及对数据的整理、分析和建模。 APC年龄时期队列分析是一种研究人口或事件在不同年龄、不同时期和不同历史时期的影响的方法。在SAS中,可以使用多种函数和过程来实现这一方法。 首先,需要对所需的数据进行整理和准备。将数据按年龄、时期和队列进行分类,并保证每个分类中的数据是完整和准确的。这可以通过SAS的数据整理和处理函数来实现,例如DATA步骤和SQL查询。 接下来,使用SAS中的统计分析过程来计算和分析APC年龄时期队列。可以使用PROC REG和PROC GLM来进行回归分析,查看年龄、时期和队列对所研究事件的影响。也可以使用PROC GENMOD来进行广义线性模型分析,例如对二项式数据的分析。 在分析过程中,还可以使用SAS的可视化工具来展示结果和趋势。例如,可以使用PROC SGPLOT生成图表和图形,清晰地展示年龄、时期和队列的关系和变化趋势。 最后,根据对APC年龄时期队列的分析结果,可以对特定问题或现象作出解释和预测。这将有助于了解人口或事件在不同年龄、时期和队列中的变化和发展规律,从而提供决策和干预的依据。 总而言之,通过SAS软件工具的数据整理、分析和建模功能,可以实现对APC年龄时期队列的研究和分析。这将有助于深入了解和解释人口或事件在不同年龄、时期和队列中的变化和影响。 ### 回答2: SAS(统计分析系统)是一种功能强大的统计分析软件,可以用于实现多种统计分析方法和模型。要实现APC(年龄、时期、队列)模型,首先需要了解APC模型的基本概念和原理。 在APC模型中,年龄、时期和队列是指个体或群体的三个重要维度。年龄表示个体或群体的年龄水平,时期表示观察或研究的时间点或时间期间,队列则表示在特定时期出生的个体或群体。这三个维度综合起来,可以帮助我们分析和预测某种现象或变量在不同年龄、不同时期和不同队列中的变化。 为了使用SAS实现APC模型,可以遵循以下步骤: 1. 数据准备:将需要分析的数据导入SAS软件中,并确保数据格式正确,包括年龄、时期和队列等相关变量。 2. 数据探索和描述性分析:使用SAS的统计分析功能,对数据进行探索性分析,如描述统计、频率分析、数据可视化等,以了解数据的分布和特征。 3. APC模型建立:在SAS中,可以使用各种统计模型来建立APC模型,如线性回归模型、广义线性模型、混合效应模型等。根据具体研究目的和数据特点,选择适合的模型进行建模。 4. 模型拟合和评估:使用SAS的模型拟合功能,对建立的APC模型进行拟合,并评估模型的拟合效果和预测能力,如残差分析、拟合优度检验等。 5. 结果解释和报告:根据模型结果,解释模型中各个变量的影响,如年龄效应、时期效应、队列效应等,并根据需要生成相应的报告或图表。 总之,通过使用SAS统计分析软件,可以比较方便地实现APC年龄时期队列模型,从而深入分析和预测不同维度对某种现象的影响。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值