首页
社区
课程
招聘
[原创] PatchGuard原理分析 (update 1/19)
发表于: 4天前 933

[原创] PatchGuard原理分析 (update 1/19)

4天前
933

虽然网上关于 PatchGuard 原理分析的资料已经较多,但缺乏完整性且部分地方的分析不够细致。因此,出于学习的目的,此贴仅记录本人在分析 pg 过程中的笔记,希望对他人有所裨益。
如果错误之处,还望指正!

触发检查的 DeferredRoutine 函数是从以下函数池中选择出来的。

ExpTimerDpcRoutine -> KiCustomAccessRoutine0

FsRtlTruncateSmallMcb -> KiCustomAccessRoutine0

IopTimerDispatch -> KiCustomAccessRoutine1

IopIrpStackProfilerDpcRoutine -> KiCustomAccessRoutine2

PopThermalZoneDpc -> KiCustomAccessRoutine3

CmpEnableLazyFlushDpcRoutine -> KiCustomAccessRoutine4

CmpLazyFlushDpcRoutine -> KiCustomAccessRoutine5

KiBalanceSetManagerDeferredRoutine -> KiCustomAccessRoutine6

ExpTimeRefreshDpcRoutine -> KiCustomAccessRoutine7

ExpTimeZoneDpcRoutine -> KiCustomAccessRoutine8

ExpCenturyDpcRoutine -> KiCustomAccessRoutine9

KiTimerDispatch

KiDpcDispatch

KiDispatchCallout 枚举线程插入APC调用?

函数组 KiCustomAccessRoutine_n 使用异常处理程序来激活检查,而 KiTimerDispatchKiDpcDispatch 则直接调用 DPC,而不使用此异常技巧。通过校验 _KPDC::DeferredContext 是否为规范地址来判断当前 DPC 是否与 PathGuard 相关。

图片描述

需要注意的是,参数 SystemArgument1 和 dpc->SystemArgument1 的值并不相同,SystemArgument2 也是类似的情况。需要进一步分析...

KiCustomAccessRoutine_n 函数内部调用 KiCustomRecurseRoutine_n,取 DeferredContext 的低2位再加1作为循环轮次(count)。调用顺序为 0~9 的循环,每次循环 count 减1;直到计数结束,返回 DeferredContext 指针的值。

图片描述
图片描述

由于 DeferredContext 是无效指针,因此会触发 #GP 异常进入异常处理块 KiBalanceSetManagerDeferredRoutine$fin$0。该函数接收两个参数:UnwindReason(是否因异常展开 "exception unwinding" 而退出) 和栈帧的 Rsp。
图片描述

函数 ExpTimerDpcRoutine 中被加密的变量,诸如 SystemArgument1、Dpc 等在异常处理块中被解密。
图片描述

__ROR8__ 刚好对应于函数 KiBalanceSetManagerDeferredRoutine 中的 "*(QWORD *)((char *)&pgContext[0x34] + 2) = _ROL8(DeferredContext, SystemArgument1);"。因此,dpc->DeferredContext 的解密算法为 dpc->DeferredContext ^ DeferredContextMask | 0xffff800000000000。后续,设置 DeferredContext 的前4字节硬编码,即函数 CmpAppendDllSection 的首条指令 xor [rcx], rdx 开始自解密。

图片描述

DeferredContext 所指向地址的首条指令恰好为函数 CmpAppendDllSection函数的首条指令。
图片描述

函数 CmpAppendDllSection 会逐行进行自解密,后完成对 context 的解密,因此在该函数中下软件断点将会出现异常。自解密完成后,将会调用context的入口函数 PatchGuardEntryPoint

图片描述

指令 "xor qword ptr [rcx], rdx", 导致前4字节被覆盖, 后4字节指令被解密。每次执行4B,解密8字节。

指令 "jmp r8" 插入工作项(ExQueueWorkItem),参数 pgContext[0x798] 指定工作项指针。_WORK_QUEUE_ITEM::Parameter 指向当前 pgContext,_WORK_QUEUE_ITEM::WorkerRoutine 为 FsRtlUninitializeSmallMcb。

key = 0xe499f116fbceb8f6,函数入口硬编码 opcodes = 0xecc8c05e1131482e,则 key ^ opcodes = 0x08513148eafff0d8。
图片描述

PatchGuardEntryPoint 函数为 context 的入口函数。

临时替换 idt 表和清空 Dr7 寄存器,从而依赖于 #DB 异常的硬件断点和单步调试失效。
图片描述

首先检验 context 自身是否被篡改?可有效避免诸如软中断(int3),先前已通过清空 dr7 导致硬件中断失效。第一部分的 context 自检长度为 0x620,每次校验128B,共计12轮。数据校验时,利用内存预取技术 _mm_prefetch 将 context 缓存至 cache 中。以第 2 轮自检为例,每轮可细分为8次运算,包括 ^/__ROL8__。接着,第二部分的 context 自检校验剩余的32B。

图片描述

图片描述

如果 context 自检失败,则会最终调用 SdbpCheckDll 函数触发 KeBugCheckEx 蓝屏。arg1: pgContext[0x900] 指向 pgContext 首地址;arg2: pgContext[0x908] 被置空;arg3: pgContext[0x918] 校验和;arg4: pgContext[0x910] 错误码。

图片描述

图片描述

只要在 context 自检时机前清除 int3 软中断即可。

pgContext[0x7e0] 被设置时(当前内核完整性校验次数>0),将进入内核完整性校验阶段。pgContext[0x808]+pgContext 指向内核完整性校验描述符表 KICDT (Kernel integrity check descriptor table),不同类型的内核完整性校验对象的表项长度不同。对于函数而言,每个表项长度为 0x30。第一部分以128B为单位进行校验,第二部分将剩余不足128B的数据以8B为单位进行校验。 若剩余字节不足8B,将进入第三部分,以单字节为单位进行校验。

图片描述

图片描述

如果校验失败,则判断当前是否开启了虚拟化相关的安全策略导致内核完整性校验失败? "pgContext[0x994] & 0x40"

图片描述

计算并设置新的 context 地址。

当校验失败时(pgContext[0x8f8]),清空调用栈并调用 SdbpCheckDll -> KeBugCheckEx 蓝屏。该函数内部会将 Rsp 调用栈清空,从而造成无法获取调用源。参数依次是:KeBugCheckEx(errorCode, pg+0x900, pg+0x908, pg+0x918, pg+0x910)

图片描述

在函数 KeBugCheckEx 之前调用栈被清空;可通过被加密的内核完整性校验描述符地址回溯原始地址,其所记录的检测目标地址与 arg3 一致;pgContext 指向 CmpAppendDllSection。
图片描述
图片描述

在 PatchGuardEntryPoint 函数中会对部分重要的函数进行完整性检查,但是对 pgContext 内容的完整检查是由 FsRtlUninitializeSmallMcb 调用 FsRtlMdlReadCompleteDevEx 函数完成的。这些完整性检查包括核心驱动的 IAT、GDT、IDT(包括中断向量表)、SSDT、CRx、MSR寄存器、内核全局变量、内核全局指针、进程模块链表、内核堆栈、对象类型、Local APIC、第三方通知回调、某些配置和 Flags、KPP Self 等。内部可能存在反调试导致蓝屏。
Ref. e24K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2L8s2k6A6L8X3!0$3L8#2)9J5k6i4c8G2M7q4)9J5c8Y4m8G2M7%4c8Q4x3V1k6w2k6i4u0F1k6h3I4Q4x3X3c8b7j5i4c8U0K9q4)9J5k6q4m8J5L8%4c8W2j5%4c8A6L8$3^5K6

pgContext 关键偏移如下。

函数 PatchGuardEntryPoint 的完整伪代码如下:

【未涉及的地方】

typedef struct _KICD {
    ULONG   Type;
    ULONG   Unknow;
    PVOID   Base;
    ULONG   Limit;
    ULONG   Checksum;   // Checksum == pgContextChecksum & 0x7FFFFFFF ? 校验成功 : 失败
    ULONG   bUnknow;
    ...
     
} KICD, * PKICD;
typedef struct _KICD {
    ULONG   Type;
    ULONG   Unknow;
    PVOID   Base;
    ULONG   Limit;
    ULONG   Checksum;   // Checksum == pgContextChecksum & 0x7FFFFFFF ? 校验成功 : 失败
    ULONG   bUnknow;
    ...
     
} KICD, * PKICD;
pg+0x0c4    context长度(390d)
 
pg+0x110    工作项: ExQueueWorkItem
 
pg+0x158    SdbpCheckDll将要执行的崩溃函数,KeBugCheckEx
 
pg+0x264    反调试(临时idt+dr7清空)
 
pg+0x268    回调函数: KeAcquireSpinLockRaiseToDpc,使用pg+0x800的SpinLock
 
pg+0x270    回调函数: KeReleaseSpinLock
 
pg+0x468    安全策略内核完整性校验验证函数: VslVerifyPage
 
pg+0x00 ~ pg+0x620  context区域
 
pg+0x798    工作项指针
 
pg+0x7a8    newPgContext
 
pg+0x7b0    oldPgContext
 
pg+0x7e0    当前内核完整性校验次数
 
pg+0x7f0    newPgContext偏移
 
pg+0x800    SpinLock
 
pg+0x808    内核完整性校验描述符偏移
 
pg+0x818    context校验和
 
pg+0x8f8    内核完整性校验失败
 
pg+0x828    累计校验长度,每次递增0x620
 
pg+0x900    pgContext 指针
 
pg+0x908    内核完整性校验描述符地址
 
pg+0x910    校验对象的类型 (Type)
 
pg+0x918    检验目标地址
 
pg+0x994    flag & 0x40 != 0 ? 因虚拟化相关安全策略导致内核完整性校验失败,调用 VslVerifyPage 进行验证
pg+0x0c4    context长度(390d)
 
pg+0x110    工作项: ExQueueWorkItem
 
pg+0x158    SdbpCheckDll将要执行的崩溃函数,KeBugCheckEx
 
pg+0x264    反调试(临时idt+dr7清空)
 
pg+0x268    回调函数: KeAcquireSpinLockRaiseToDpc,使用pg+0x800的SpinLock
 
pg+0x270    回调函数: KeReleaseSpinLock
 
pg+0x468    安全策略内核完整性校验验证函数: VslVerifyPage
 
pg+0x00 ~ pg+0x620  context区域
 
pg+0x798    工作项指针
 
pg+0x7a8    newPgContext
 
pg+0x7b0    oldPgContext
 
pg+0x7e0    当前内核完整性校验次数
 
pg+0x7f0    newPgContext偏移
 
pg+0x800    SpinLock
 
pg+0x808    内核完整性校验描述符偏移
 
pg+0x818    context校验和
 
pg+0x8f8    内核完整性校验失败
 
pg+0x828    累计校验长度,每次递增0x620
 
pg+0x900    pgContext 指针
 
pg+0x908    内核完整性校验描述符地址
 
pg+0x910    校验对象的类型 (Type)
 
pg+0x918    检验目标地址
 
pg+0x994    flag & 0x40 != 0 ? 因虚拟化相关安全策略导致内核完整性校验失败,调用 VslVerifyPage 进行验证
__int64 __fastcall PatchGuardEntryPoint(__int64 a1, char *CmpAppendDllSection_ptr)
{
  __int64 pgContext; // rdi
  __int64 idtBase; // rdx
  __int64 index; // r8
  _QWORD *idt_ptr; // rax
  int idtSize; // ecx
  int pgContextLength; // esi
  _QWORD *v8; // r9
  int v9; // r10d
  const char *mem_offset; // rax
  __int64 v11; // r11
  __int64 pgContextChecksum; // r8
  int v13; // ebx
  __int64 v14; // rdx
  __int64 v15; // rax
  __int64 *v16; // r9
  __int64 v17; // r8
  unsigned __int64 v18; // rcx
  __int64 Checksum; // rdx
  int v20; // ebx
  __int64 v21; // r11
  int v22; // r13d
  __int64 v23; // rax
  bool v24; // zf
  __int64 v25; // rax
  int v26; // ecx
  unsigned int *p_verificationRound_2; // rax
  unsigned int verificationRound_1; // ecx
  __int64 v29; // r9
  unsigned int verificationRoundIndex; // r8d
  _KICD *kicd; // rbx
  __int64 v32; // r10
  int v33; // ecx
  int v34; // ecx
  int v35; // ecx
  int v36; // ecx
  __int64 v37; // rax
  int Unknow_low; // eax
  __int64 base_ptr; // r11
  int v40; // r14d
  unsigned int v41; // eax
  unsigned __int64 v42; // r15
  _QWORD *base_ptr_1; // r9
  __int64 limit; // r8
  const char *offset; // rax
  unsigned __int64 pgContextChecksum_1; // rsi
  unsigned int v47; // r10d
  __int64 v48; // rax
  __int64 v49; // rsi
  unsigned __int64 v50; // rcx
  __int64 v51; // r8
  unsigned __int64 v52; // rax
  __int64 v53; // rax
  unsigned __int64 i; // rax
  unsigned int pgContextChecksum_dd; // esi
  BOOL v56; // r12d
  __int64 Limit; // rcx
  __int64 Base; // rdx
  unsigned __int8 CurrentIrql; // r13
  unsigned __int64 basePageAlignment; // r14
  unsigned __int64 v61; // r15
  int v62; // eax
  __int64 v63; // r13
  __int64 v64; // rbx
  __int64 v65; // rsi
  __int64 v66; // r12
  struct _KPRCB *CurrentPrcb; // rdx
  __int64 *v68; // r14
  __int64 v69; // r15
  unsigned __int64 v70; // r12
  unsigned __int64 v71; // r8
  unsigned int v72; // r10d
  unsigned __int64 v73; // r9
  _QWORD *j; // rdx
  unsigned __int64 v75; // rcx
  int failed; // eax
  __int64 v77; // rcx
  __int64 Type; // rax
  unsigned __int64 v79; // rax
  __int64 v80; // rsi
  _QWORD *v81; // rcx
  char *v82; // r10
  int v83; // r11d
  unsigned __int64 v84; // rbx
  signed __int64 v85; // r10
  __int64 newPgContext; // r8
  unsigned __int64 v87; // rcx
  unsigned __int64 v88; // rcx
  _QWORD *v89; // r9
  unsigned __int64 v90; // rax
  unsigned __int128 v91; // rax
  __int64 v92; // rdx
  char *v93; // rdx
  _QWORD *v94; // rcx
  __int64 v95; // r8
  char v96; // al
  unsigned __int64 v97; // rdx
  int v99; // ecx
  int v100; // ecx
  int v101; // ecx
  int v102; // ecx
  int v103; // ecx
  volatile signed __int32 *v104; // rax
  signed __int32 v105[8]; // [rsp+0h] [rbp-79h] BYREF
  __int64 v106; // [rsp+40h] [rbp-39h]
  unsigned int verificationRound_2; // [rsp+48h] [rbp-31h] BYREF
  __int64 verificationRound; // [rsp+50h] [rbp-29h]
  unsigned __int64 ptr; // [rsp+58h] [rbp-21h]
  __int64 limitPageAlignment; // [rsp+60h] [rbp-19h]
  __int64 v111; // [rsp+68h] [rbp-11h] BYREF
  _WORD NewIdtr[8]; // [rsp+70h] [rbp-9h] BYREF
  _BYTE oldIDTR[16]; // [rsp+80h] [rbp+7h] BYREF
  __int64 v114; // [rsp+90h] [rbp+17h]
  __int64 v115; // [rsp+98h] [rbp+1Fh]
  __int64 v116; // [rsp+A0h] [rbp+27h]
  __int64 v117; // [rsp+A8h] [rbp+2Fh]
 
  pgContext = (__int64)CmpAppendDllSection_ptr;
  if ( (*((_DWORD *)CmpAppendDllSection_ptr + 0x264) & 0x110000) != 0x110000 )// 反调试
  {
    idtBase = *((_QWORD *)CmpAppendDllSection_ptr + 0x11C);// 临时idt表基址
    index = 0x26;
    idt_ptr = (_QWORD *)idtBase;
    idtSize = 0x130;
    do
    {
      *idt_ptr = 0;
      idtSize -= 8;
      ++idt_ptr;
      --index;
    }
    while ( index );                            // 初始化IDT表
    for ( ; idtSize; --idtSize )
    {
      *(_BYTE *)idt_ptr = 0;
      idt_ptr = (_QWORD *)((char *)idt_ptr + 1);
    }
    *(_OWORD *)(idtBase + 0x10) = *(_OWORD *)(pgContext + 0x848);// 设置idt关键表项
    *(_OWORD *)(idtBase + 0x20) = *(_OWORD *)(pgContext + 0x858);
    *(_OWORD *)(idtBase + 0x120) = *(_OWORD *)(pgContext + 0x868);
    NewIdtr[0] = 0x12F;
    *(_QWORD *)&NewIdtr[1] = idtBase;           // 构建IDTR值
    *(_WORD *)(idtBase + 0x10) = pgContext + 0x878;
    *(_DWORD *)(idtBase + 0x18) = (unsigned __int64)(pgContext + 0x878) >> 32;
    *(_WORD *)(idtBase + 0x16) = (unsigned int)(pgContext + 0x878) >> 16;// 构建IDT描述符
    _disable();
    if ( *(int *)(pgContext + 0x990) >= 0 )
    {
      __sidt(oldIDTR);
      __lidt(NewIdtr);                          // 加载新的IDT表(破坏单步跟踪,反调试)
      __writedr(7u, 0);                         // 清空dr7寄存器, 禁用硬件调试
      __lidt(oldIDTR);
    }
    else
    {
      __writedr(7u, 0);
    }
    _enable();
  }
  *(_DWORD *)(pgContext + 0x828) += 0x620;      // 每次的校验长度为0x620 (context区域)
  pgContextLength = *(_DWORD *)(pgContext + 0xC4);// pgContext的长度
  v8 = (_QWORD *)pgContext;
  v9 = *(_DWORD *)(pgContext + 0x814);
  mem_offset = (const char *)pgContext;
  v11 = *(_QWORD *)(pgContext + 0x818);
  *(_DWORD *)(pgContext + 196) = 0;
  if ( pgContext < (unsigned __int64)(pgContext + 0x620) )// 第一份部分校验: context自身完整性
  {
    do
    {
      _mm_prefetch(mem_offset, 0);              // 内存预取至cache(64B)
      mem_offset += 64;
    }
    while ( (unsigned __int64)mem_offset < pgContext + 0x620 );
  }
  pgContextChecksum = v11;
  v13 = 12;
  do
  {
    v14 = 8;
    do
    {
      v15 = pgContextChecksum ^ *v8;            // 当前哈希 ^ 数据
      v16 = v8 + 1;
      v17 = *v16;
      v8 = v16 + 1;
      pgContextChecksum = __ROL8__(__ROL8__(v15, v9) ^ v17, v9);
      --v14;
    }
    while ( v14 );                              // 已校验8*16=128B
    v18 = __ROL8__(v11 ^ ((unsigned __int64)v8 - pgContext), 17) ^ v11 ^ ((unsigned __int64)v8 - pgContext);
    v114 = (v18 * (unsigned __int128)0x7010008004002001uLL) >> 64;
    v9 = ((unsigned __int8)(v114 ^ v18) ^ (unsigned __int8)v9) & 0x3F;
    if ( !v9 )
      LOBYTE(v9) = 1;
    --v13;
  }
  while ( v13 );                                // context自检(一): 12轮,每轮取128字节,共计0x600字节
  LODWORD(Checksum) = 32;
  v20 = 4;
  v21 = 4;
  v22 = 64;
  do
  {
    pgContextChecksum = __ROL8__(*v8++ ^ pgContextChecksum, v9);
    Checksum = (unsigned int)(Checksum - 8);
    --v21;
  }
  while ( v21 );                                // context自检(二): 剩余32B
  if ( (_DWORD)Checksum )
  {
    do
    {
      v23 = *(unsigned __int8 *)v8;
      v8 = (_QWORD *)((char *)v8 + 1);
      pgContextChecksum = __ROL8__(v23 ^ pgContextChecksum, v9);
      v24 = (_DWORD)Checksum == 1;
      Checksum = (unsigned int)(Checksum - 1);
    }
    while ( !v24 );
  }
  *(_DWORD *)(pgContext + 0xC4) = pgContextLength;
  if ( *(_QWORD *)(pgContext + 0xA20) != pgContextChecksum )// context自检是否通过?
  {
    v25 = *(_QWORD *)(pgContext + 0x590);
    v26 = *(_DWORD *)(pgContext + 0x7E4);
    *(_QWORD *)v25 = pgContext;
    *(_DWORD *)(v25 + 16) = v26;
    Checksum = *(_QWORD *)(pgContext + 0xA20);
    if ( !*(_DWORD *)(pgContext + 0x8F8) )      // 确保尚未触发过(防重入)
    {
      *(_QWORD *)(*(_QWORD *)(pgContext + 0x590) + 24LL) = Checksum ^ pgContextChecksum;
      if ( !*(_DWORD *)(pgContext + 0x8F8) )
      {
        *(_QWORD *)(pgContext + 0x908) = 0;     // context完整性校验未通过, 还没有展开待校验部分到的检测, 置空
        *(_QWORD *)(pgContext + 0x900) = pgContext - 0x5C5FC0A76E374B18LL;
        *(_QWORD *)(pgContext + 0x910) = 0x109; // SECURITY_ASSERTION_FAILURE
        *(_QWORD *)(pgContext + 0x918) = pgContextChecksum;
        *(_DWORD *)(pgContext + 0x8F8) = 1;     // 标记“已触发”
        sub_14036C3BC(pgContext, 0);
      }
    }
  }
  v106 = 0;
  p_verificationRound_2 = &verificationRound_2;
  do
  {
    *(_BYTE *)p_verificationRound_2 = 0;
    p_verificationRound_2 = (unsigned int *)((char *)p_verificationRound_2 + 1);
    --v20;
  }
  while ( v20 );
  verificationRound_1 = 0;
  LODWORD(verificationRound) = 0;
  if ( *(_DWORD *)(pgContext + 0x7E0) )         // 阶段三: 是否进行内核完整性校验? 校验次数>0
  {
    while ( 1 )
    {
      v29 = pgContext;
      verificationRoundIndex = 0;
      if ( *(_QWORD *)(pgContext + 0xA78) )
        v29 = *(_QWORD *)(pgContext + 0xA78);
      kicd = (_KICD *)(v29 + *(unsigned int *)(v29 + 0x808));
      if ( (_DWORD)v106 && HIDWORD(v106) <= verificationRound_1 )// verificationRound≥1
      {
        verificationRoundIndex = HIDWORD(v106);
        kicd = (_KICD *)(v29 + verificationRound_2);
      }
      if ( verificationRoundIndex != verificationRound_1 )
        break;
LABEL_57:
      base_ptr = kicd->Base;                    // 内核完整性校验起始地址, v31是一个数据结构
      v40 = *(_DWORD *)(pgContext + 2068);
      v41 = (_DWORD)kicd - v29;
      v42 = *(_QWORD *)(pgContext + 2072);
      base_ptr_1 = (_QWORD *)base_ptr;
      HIDWORD(v106) = verificationRoundIndex;
      limit = (unsigned int)kicd->Limit;
      *(_DWORD *)(pgContext + 0x828) += limit;  // 更新累计校验长度
      verificationRound_2 = v41;
      offset = (const char *)base_ptr;
      LODWORD(v106) = 1;
      if ( base_ptr < (unsigned __int64)(base_ptr + limit) )
      {
        do
        {
          _mm_prefetch(offset, 0);
          offset += 64;
        }
        while ( (unsigned __int64)offset < base_ptr + limit );
      }
      pgContextChecksum_1 = v42;
      v47 = (unsigned int)limit >> 7;
      if ( (unsigned int)limit >> 7 )           // 每轮校验2^7=128B
      {
        do
        {
          v48 = 8;
          do
          {
            v49 = base_ptr_1[1] ^ __ROL8__(*base_ptr_1 ^ pgContextChecksum_1, v40);
            base_ptr_1 += 2;
            pgContextChecksum_1 = __ROL8__(v49, v40);
            --v48;
          }
          while ( v48 );                        // 校验16*8=128B
          v50 = __ROL8__(v42 ^ ((unsigned __int64)base_ptr_1 - base_ptr), 17)
              ^ v42
              ^ ((unsigned __int64)base_ptr_1 - base_ptr);
          Checksum = (v50 * (unsigned __int128)0x7010008004002001uLL) >> 64;
          v115 = Checksum;
          v40 = ((unsigned __int8)(Checksum ^ v50) ^ (unsigned __int8)v40) & 0x3F;
          if ( !v40 )
            LOBYTE(v40) = 1;
          --v47;
        }
        while ( v47 );                          // 第一部分校验结束
        pgContext = (__int64)CmpAppendDllSection_ptr;
      }
      v51 = limit & 0x7F;                       // 校验剩余长度(<128B)
      if ( (unsigned int)v51 >= 8 )
      {
        v52 = (unsigned __int64)(unsigned int)v51 >> 3;
        do
        {
          pgContextChecksum_1 = __ROL8__(*base_ptr_1++ ^ pgContextChecksum_1, v40);
          v51 = (unsigned int)(v51 - 8);
          --v52;
        }
        while ( v52 );
      }                                         // 第二部分校验结束
      if ( (_DWORD)v51 )                        // 第三部分: 长度不足8B, 以字节为单位进行校验
      {
        do
        {
          v53 = *(unsigned __int8 *)base_ptr_1;
          base_ptr_1 = (_QWORD *)((char *)base_ptr_1 + 1);
          pgContextChecksum_1 = __ROL8__(v53 ^ pgContextChecksum_1, v40);
          v24 = (_DWORD)v51 == 1;
          v51 = (unsigned int)(v51 - 1);
        }
        while ( !v24 );
      }
      for ( i = pgContextChecksum_1; ; LODWORD(pgContextChecksum_1) = i ^ pgContextChecksum_1 )// 结束校验
      {
        i >>= 31;
        if ( !i )
          break;
      }
      pgContextChecksum_dd = pgContextChecksum_1 & 0x7FFFFFFF;
      v56 = 0;
      if ( pgContextChecksum_dd != kicd->Checksum )// 内核完整性校验是否成功?
      {
        if ( !kicd->Type )
          v56 = kicd->bUnknow != 0;
        Limit = (unsigned int)kicd->Limit;
        Base = kicd->Base;
        if ( kicd->Limit && (*(_DWORD *)(pgContext + 0x994) & 0x40) != 0 )// 是否因安全策略导致数据被篡改?
        {
          CurrentIrql = KeGetCurrentIrql();
          __writecr8(2u);                       // 提升 IRQL 到 DISPATCH_LEVEL
          basePageAlignment = Base & 0xFFFFFFFFFFFFF000uLL;// 页内存对齐
          limitPageAlignment = (Base + Limit - 1) | 0xFFF;
          ptr = (Base & 0xFFFFFFFFFFFFF000uLL) - 1;
          while ( 2 )
          {
            v61 = CurrentIrql;
            while ( 1 )
            {
              v62 = (*(__int64 (__fastcall **)(unsigned __int64, _QWORD, __int64, _QWORD *))(pgContext + 0x468))(
                      basePageAlignment,
                      0,
                      v51,
                      base_ptr_1);              // VslVerifyPage, 向hypervisor进行验证?
              if ( v62 != 0xC000022D )          // STATUS_INVALID_PAGE_PROTECTION
                break;
              if ( v56 )
                goto LABEL_100;
              if ( CurrentIrql > 1u )
                goto LABEL_86;
              v61 = CurrentIrql;
              __writecr8(CurrentIrql);
              KeGetCurrentIrql();
              __writecr8(2u);
            }
            if ( v62 < 0 )
            {
LABEL_100:
              __writecr8(v61);
              goto LABEL_101;
            }
LABEL_86:
            Checksum = 0x1000;
            basePageAlignment += 0x1000LL;
            ptr += 0x1000LL;
            if ( ptr != limitPageAlignment )
              continue;
            break;
          }
          __writecr8(v61);
        }
        else
        {
LABEL_101:
          failed = *(_DWORD *)(pgContext + 0x8F8);
          Checksum = (unsigned int)kicd->Checksum;
          if ( !failed )                        // 防止重入(如pgContext自校验失败)
          {
            *(_QWORD *)(*(_QWORD *)(pgContext + 0x590) + 0x18LL) = Checksum ^ pgContextChecksum_dd;
            failed = *(_DWORD *)(pgContext + 0x8F8);
          }
          v77 = kicd->Base;
          if ( !failed )
          {
            *(_QWORD *)(pgContext + 0x900) = pgContext - 0x5C5FC0A76E374B18LL;// 混淆上下文地址
            *(_QWORD *)(pgContext + 0x908) = (char *)kicd - 0x4C48B4211BBACBEBLL;// 混淆描述符地址
            Type = kicd->Type;
            *(_QWORD *)(pgContext + 0x918) = v77;// 校验地址
            *(_QWORD *)(pgContext + 0x910) = Type;
            *(_DWORD *)(pgContext + 0x8F8) = 1;
            sub_14036C3BC(pgContext, 0);
          }
        }
      }
      v22 = 64;
      verificationRound_1 = verificationRound + 1;
      LODWORD(verificationRound) = verificationRound_1;
      if ( verificationRound_1 >= *(_DWORD *)(pgContext + 0x7E0) )
        goto LABEL_89;                          // 校验结束
    }                                           // while循环结束
    v32 = verificationRound_1 - verificationRoundIndex;
    verificationRoundIndex = verificationRound_1;
    while ( 1 )                                 // 设置内核校验完整性描述符偏移
    {
      v33 = kicd->Type;
      if ( kicd->Type > 12 )
        break;
      if ( v33 == 12 )
        goto LABEL_50;
      v34 = v33 - 1;
      if ( !v34 )
        goto LABEL_50;
      v35 = v34 - 6;
      if ( v35 )
      {
        v36 = v35 - 1;
        if ( !v36 )
        {
          Unknow_low = LOWORD(kicd[1].Unknow);
LABEL_55:
          v37 = (Unknow_low + 0x37) & 0xFFFFFFF8;
          goto LABEL_56;
        }
        if ( v36 != 2 )
          goto LABEL_52;
        v37 = (unsigned int)(16 * (kicd[1].Type + 3));
      }
      else
      {
        v37 = (unsigned int)(24 * (kicd->bUnknow + 2));
      }
LABEL_56:
      kicd = (_KICD *)((char *)kicd + v37);
      if ( !--v32 )
        goto LABEL_57;                          // 继续校验
    }
    if ( v33 == 28 )
    {
      Unknow_low = WORD2(kicd[1].Base);
      goto LABEL_55;
    }
    if ( v33 == 30 )
    {
      Checksum = ((LODWORD(kicd[1].Base) - 1) / 0xCu + 7) & 0xFFFFFFF8;
      v37 = (unsigned int)Checksum + 24 * (WORD2(kicd[1].Base) + 2);
      goto LABEL_56;
    }
    if ( v33 <= 32 )
    {
LABEL_52:
      v37 = 48;                                 // 内核完整性描述符长度偏移
      goto LABEL_56;
    }
    if ( v33 <= 34 )
    {
      Checksum = ((kicd[1].Unknow & 0xFFF) + (unsigned __int64)HIDWORD(kicd[1].Base) + 4095) >> 12;
      v37 = (unsigned int)(20 * Checksum + 48);
      goto LABEL_56;
    }
    if ( v33 != 43 )
      goto LABEL_52;
LABEL_50:
    Checksum = (unsigned int)kicd->Limit / 0xCuLL;
    v37 = (unsigned int)(4 * Checksum + 48);
    goto LABEL_56;
  }
LABEL_89:
  if ( *(_DWORD *)(pgContext + 0x8F8) )         // 内核数据被篡改
  {
    v63 = *(_QWORD *)(pgContext + 2320);
    v64 = *(_QWORD *)(pgContext + 2328);
    v65 = *(_QWORD *)(pgContext + 0x908);
    v66 = *(_QWORD *)(pgContext + 0x900);
    limitPageAlignment = v64;
    ptr = v65;
    verificationRound = v66;
    v111 = pgContext;
    if ( KeGetCurrentIrql() < 2u )
    {
      KeGetCurrentIrql();
      __writecr8(2u);                           // 提升 IRQL 到 DISPATCH_LEVEL
    }
    CurrentPrcb = KeGetCurrentPrcb();
    v68 = *(__int64 **)((char *)&CurrentPrcb->MxCsr + *(_QWORD *)(pgContext + 1592));
    v69 = *(_QWORD *)((char *)&CurrentPrcb->MxCsr + *(_QWORD *)(pgContext + 1608));
    if ( !*((_BYTE *)&CurrentPrcb->MxCsr + *(_QWORD *)(pgContext + 1600)) || &v111 > v68 || &v111 < v68 - 3072 )// 栈范围检查
      v68 = *(__int64 **)(v69 + *(_QWORD *)(pgContext + 0x678));
    if ( (*(_DWORD *)(pgContext + 2448) & 0x8000000) == 0 )
    {
      v70 = __readcr0();
      __writecr0(v70 & 0xFFFFFFFFFFFEFFFFuLL);
      v71 = pgContext + 2728;
      v72 = 0;
      v73 = pgContext + 2728 + 16LL * *(unsigned int *)(pgContext + 2720);
      for ( j = (_QWORD *)v73; v72 < *(_DWORD *)(pgContext + 2724); ++v72 )
      {
        *(_QWORD *)*j = j[1];
        v75 = __readcr4();
        if ( (v75 & 0x20080) != 0 )
        {
          __writecr4(v75 ^ 0x80);
          __writecr4(v75);
        }
        else
        {
          v79 = __readcr3();
          __writecr3(v79);
        }
        j += 2;
      }
      if ( v71 < v73 )
      {
        do
        {
          v80 = *(unsigned int *)(v71 + 8);
          v81 = j;
          v82 = *(char **)v71;
          v83 = v80;
          if ( (unsigned int)v80 >= 8 )
          {
            v84 = (unsigned __int64)(unsigned int)v80 >> 3;
            do
            {
              v83 -= 8;
              *(_QWORD *)v82 = *v81++;
              v82 += 8;
              --v84;
            }
            while ( v84 );
          }
          if ( v83 )
          {
            v85 = v82 - (char *)v81;
            do
            {
              *((_BYTE *)v81 + v85) = *(_BYTE *)v81;
              v81 = (_QWORD *)((char *)v81 + 1);
              --v83;
            }
            while ( v83 );
          }
          j = (_QWORD *)((char *)j + v80);
          v71 += 16LL;
        }
        while ( v71 < v73 );
        v64 = limitPageAlignment;
        v65 = ptr;
      }
      **(_BYTE **)(pgContext + 536) = -61;
      __writecr0(v70);
      v66 = verificationRound;
    }
    v99 = *(_DWORD *)(pgContext + 2344);
    if ( v99 )
    {
      if ( KeGetCurrentIrql() < 2u )
      {
        KeGetCurrentIrql();
        __writecr8(2u);
        v99 = *(_DWORD *)(pgContext + 2344);
      }
      if ( v99 )
      {
        v100 = v99 - 1;
        if ( v100 )
        {
          v101 = v100 - 1;
          if ( v101 )
          {
            v102 = v101 - 1;
            if ( v102 )
            {
              v103 = v102 - 1;
              if ( v103 )
              {
                if ( v103 == 1 )
                  _interlockedbittestandset(
                    *(volatile signed __int32 **)((char *)&KeGetCurrentPrcb()->MxCsr + *(_QWORD *)(pgContext + 1608)),
                    (*(_DWORD *)(pgContext + 2448) >> 10) & 0x1F);
                else
                  _InterlockedOr64((volatile signed __int64 *)(*(_QWORD *)(pgContext + 1464) + 832LL), 1u);
              }
              else
              {
                _interlockedbittestandset(
                  *(volatile signed __int32 **)(*(_QWORD *)(pgContext + 1704)
                                              + *(_QWORD *)((char *)&KeGetCurrentPrcb()->MxCsr
                                                          + *(_QWORD *)(pgContext + 1608))
                                              + *(_QWORD *)(pgContext + 1672)),
                  (*(_DWORD *)(pgContext + 2448) >> 10) & 0x1F);
              }
              goto LABEL_150;
            }
            v104 = *(volatile signed __int32 **)(pgContext + 1376);
          }
          else
          {
            v104 = *(volatile signed __int32 **)(pgContext + 1368);
          }
        }
        else
        {
          v104 = *(volatile signed __int32 **)(pgContext + 1352);
        }
        _interlockedbittestandset64(v104, 0);
      }
    }
LABEL_150:
    *(_QWORD *)(v69 + *(_QWORD *)(pgContext + 1680)) = 0;
    *(_QWORD *)(v69 + *(_QWORD *)(pgContext + 1696)) = 0;
    SdbpCheckDll(
      0x109,
      v66,                                      // arg1: pgContext - 0x5C5FC0A76E374B18 (混淆pg_context地址)
      v65,                                      // arg2: addr - 0x4C48B4211BBACBEB (混淆目标结构体数组地址)
      v64,                                      // arg3: 异常地址
      v63,                                      // arg4
      *(__int64 (__fastcall **)(__int64, __int64, __int64, __int64, __int64))(pgContext + 0x158),// KeBugCheckEx
      v68);                                     // 系统崩溃, 内部清空数调用栈
    JUMPOUT(0x14036D803LL);
  }                                             // 内核数据被篡改
  newPgContext = pgContext + *(unsigned int *)(pgContext + 0x7F0);// 内核完整性校验通过
  if ( (*(_DWORD *)(pgContext + 2448) & 0x10000000) != 0 )
  {
    v87 = __rdtsc();
    v88 = __ROR8__(v87, 3) ^ v87;
    Checksum = (v88 * (unsigned __int128)0x7010008004002001uLL) >> 64;
    v116 = Checksum;
    newPgContext = (__int64)KiMachineCheckControl + 16 * (((unsigned __int8)v88 ^ (unsigned __int8)Checksum) & 0xF);//
                                                // 新的context地址随机化,地址空间布局随机化(ASLR)
  }
  v89 = *(_QWORD **)(pgContext + 2568);
  if ( v89 )
  {
    v90 = __rdtsc();
    v91 = (__ROR8__(v90, 3) ^ v90) * (unsigned __int128)0x7010008004002001uLL;
    v117 = *((_QWORD *)&v91 + 1);
    *((_QWORD *)&v91 + 1) ^= v91;
    v89[2] = *((_QWORD *)&v91 + 1);
    *(_QWORD *)&v91 = newPgContext ^ *((_QWORD *)&v91 + 1);
    Checksum = pgContext ^ *((_QWORD *)&v91 + 1);
    v89[3] = v91;
    v89[1] = Checksum;
    _InterlockedOr(v105, 0);
    newPgContext = *(_QWORD *)(pgContext + 752);
  }
  else
  {
    v89 = (_QWORD *)pgContext;
  }
  *(_QWORD *)(pgContext + 1960) = newPgContext;
  *(_QWORD *)(pgContext + 1968) = v89;          // oldPgContext
  *(_QWORD *)(pgContext + 1944) = 0;
  _disable();
  _enable();
  LOBYTE(v92) = (*(__int64 (__fastcall **)(__int64, __int64))(pgContext + 0x268))(pgContext + 0x800, Checksum);// KeAcquireSpinLockRaiseToDpc
  (*(void (__fastcall **)(__int64, __int64))(pgContext + 0x270))(pgContext + 0x800, v92);// KeReleaseSpinLock
  switch ( *(_DWORD *)(pgContext + 2104) )
  {
    case 3:
      _disable();
      *(_QWORD *)(pgContext + 2456) = *(_QWORD *)((char *)&KeGetCurrentPrcb()->MxCsr + *(_QWORD *)(pgContext + 1608));
      _enable();
      break;
    case 4:
      v97 = *(_QWORD *)(pgContext + 2528);
      *(_QWORD *)(*(_QWORD *)(v97 + 56) ^ *(_QWORD *)(v97 + 64)) = v97 ^ *(_QWORD *)(v97 + 72) ^ *(_QWORD *)(v97 + 64);
      *(_QWORD *)(v97 + 72) = 0;
      *(_QWORD *)(v97 + 56) = 0;
      break;
    case 5:
      v93 = (char *)(pgContext + 2464);
      v94 = (_QWORD *)(*(_QWORD *)(pgContext + 2456) + 8LL);
      v95 = 8;
      do
      {
        v22 -= 8;
        *v94 = *(_QWORD *)v93;
        v93 += 8;
        ++v94;
        --v95;
      }
      while ( v95 );
      for ( ; v22; --v22 )
      {
        v96 = *v93++;
        *(_BYTE *)v94 = v96;
        v94 = (_QWORD *)((char *)v94 + 1);
      }
      break;
  }
  _InterlockedOr(v105, 0);
  return pgContext;
}
__int64 __fastcall PatchGuardEntryPoint(__int64 a1, char *CmpAppendDllSection_ptr)
{
  __int64 pgContext; // rdi
  __int64 idtBase; // rdx
  __int64 index; // r8
  _QWORD *idt_ptr; // rax
  int idtSize; // ecx
  int pgContextLength; // esi
  _QWORD *v8; // r9
  int v9; // r10d
  const char *mem_offset; // rax
  __int64 v11; // r11
  __int64 pgContextChecksum; // r8
  int v13; // ebx
  __int64 v14; // rdx
  __int64 v15; // rax
  __int64 *v16; // r9
  __int64 v17; // r8
  unsigned __int64 v18; // rcx
  __int64 Checksum; // rdx
  int v20; // ebx
  __int64 v21; // r11
  int v22; // r13d
  __int64 v23; // rax
  bool v24; // zf
  __int64 v25; // rax
  int v26; // ecx
  unsigned int *p_verificationRound_2; // rax
  unsigned int verificationRound_1; // ecx
  __int64 v29; // r9
  unsigned int verificationRoundIndex; // r8d
  _KICD *kicd; // rbx
  __int64 v32; // r10
  int v33; // ecx
  int v34; // ecx
  int v35; // ecx
  int v36; // ecx
  __int64 v37; // rax
  int Unknow_low; // eax
  __int64 base_ptr; // r11
  int v40; // r14d
  unsigned int v41; // eax
  unsigned __int64 v42; // r15
  _QWORD *base_ptr_1; // r9
  __int64 limit; // r8
  const char *offset; // rax
  unsigned __int64 pgContextChecksum_1; // rsi
  unsigned int v47; // r10d
  __int64 v48; // rax
  __int64 v49; // rsi
  unsigned __int64 v50; // rcx
  __int64 v51; // r8
  unsigned __int64 v52; // rax
  __int64 v53; // rax
  unsigned __int64 i; // rax
  unsigned int pgContextChecksum_dd; // esi
  BOOL v56; // r12d
  __int64 Limit; // rcx
  __int64 Base; // rdx
  unsigned __int8 CurrentIrql; // r13
  unsigned __int64 basePageAlignment; // r14
  unsigned __int64 v61; // r15
  int v62; // eax
  __int64 v63; // r13
  __int64 v64; // rbx
  __int64 v65; // rsi
  __int64 v66; // r12
  struct _KPRCB *CurrentPrcb; // rdx
  __int64 *v68; // r14
  __int64 v69; // r15
  unsigned __int64 v70; // r12
  unsigned __int64 v71; // r8
  unsigned int v72; // r10d
  unsigned __int64 v73; // r9
  _QWORD *j; // rdx
  unsigned __int64 v75; // rcx
  int failed; // eax
  __int64 v77; // rcx
  __int64 Type; // rax
  unsigned __int64 v79; // rax
  __int64 v80; // rsi
  _QWORD *v81; // rcx
  char *v82; // r10
  int v83; // r11d
  unsigned __int64 v84; // rbx
  signed __int64 v85; // r10
  __int64 newPgContext; // r8
  unsigned __int64 v87; // rcx
  unsigned __int64 v88; // rcx
  _QWORD *v89; // r9
  unsigned __int64 v90; // rax
  unsigned __int128 v91; // rax
  __int64 v92; // rdx
  char *v93; // rdx
  _QWORD *v94; // rcx
  __int64 v95; // r8
  char v96; // al
  unsigned __int64 v97; // rdx
  int v99; // ecx
  int v100; // ecx
  int v101; // ecx
  int v102; // ecx
  int v103; // ecx
  volatile signed __int32 *v104; // rax
  signed __int32 v105[8]; // [rsp+0h] [rbp-79h] BYREF
  __int64 v106; // [rsp+40h] [rbp-39h]
  unsigned int verificationRound_2; // [rsp+48h] [rbp-31h] BYREF
  __int64 verificationRound; // [rsp+50h] [rbp-29h]
  unsigned __int64 ptr; // [rsp+58h] [rbp-21h]
  __int64 limitPageAlignment; // [rsp+60h] [rbp-19h]
  __int64 v111; // [rsp+68h] [rbp-11h] BYREF
  _WORD NewIdtr[8]; // [rsp+70h] [rbp-9h] BYREF
  _BYTE oldIDTR[16]; // [rsp+80h] [rbp+7h] BYREF
  __int64 v114; // [rsp+90h] [rbp+17h]
  __int64 v115; // [rsp+98h] [rbp+1Fh]
  __int64 v116; // [rsp+A0h] [rbp+27h]
  __int64 v117; // [rsp+A8h] [rbp+2Fh]
 
  pgContext = (__int64)CmpAppendDllSection_ptr;
  if ( (*((_DWORD *)CmpAppendDllSection_ptr + 0x264) & 0x110000) != 0x110000 )// 反调试
  {
    idtBase = *((_QWORD *)CmpAppendDllSection_ptr + 0x11C);// 临时idt表基址
    index = 0x26;
    idt_ptr = (_QWORD *)idtBase;
    idtSize = 0x130;
    do
    {
      *idt_ptr = 0;
      idtSize -= 8;
      ++idt_ptr;
      --index;
    }
    while ( index );                            // 初始化IDT表
    for ( ; idtSize; --idtSize )
    {
      *(_BYTE *)idt_ptr = 0;
      idt_ptr = (_QWORD *)((char *)idt_ptr + 1);
    }
    *(_OWORD *)(idtBase + 0x10) = *(_OWORD *)(pgContext + 0x848);// 设置idt关键表项
    *(_OWORD *)(idtBase + 0x20) = *(_OWORD *)(pgContext + 0x858);
    *(_OWORD *)(idtBase + 0x120) = *(_OWORD *)(pgContext + 0x868);
    NewIdtr[0] = 0x12F;
    *(_QWORD *)&NewIdtr[1] = idtBase;           // 构建IDTR值
    *(_WORD *)(idtBase + 0x10) = pgContext + 0x878;
    *(_DWORD *)(idtBase + 0x18) = (unsigned __int64)(pgContext + 0x878) >> 32;
    *(_WORD *)(idtBase + 0x16) = (unsigned int)(pgContext + 0x878) >> 16;// 构建IDT描述符
    _disable();
    if ( *(int *)(pgContext + 0x990) >= 0 )
    {
      __sidt(oldIDTR);
      __lidt(NewIdtr);                          // 加载新的IDT表(破坏单步跟踪,反调试)
      __writedr(7u, 0);                         // 清空dr7寄存器, 禁用硬件调试
      __lidt(oldIDTR);
    }
    else
    {
      __writedr(7u, 0);
    }
    _enable();
  }
  *(_DWORD *)(pgContext + 0x828) += 0x620;      // 每次的校验长度为0x620 (context区域)
  pgContextLength = *(_DWORD *)(pgContext + 0xC4);// pgContext的长度
  v8 = (_QWORD *)pgContext;
  v9 = *(_DWORD *)(pgContext + 0x814);
  mem_offset = (const char *)pgContext;
  v11 = *(_QWORD *)(pgContext + 0x818);
  *(_DWORD *)(pgContext + 196) = 0;
  if ( pgContext < (unsigned __int64)(pgContext + 0x620) )// 第一份部分校验: context自身完整性
  {
    do
    {
      _mm_prefetch(mem_offset, 0);              // 内存预取至cache(64B)
      mem_offset += 64;
    }
    while ( (unsigned __int64)mem_offset < pgContext + 0x620 );
  }
  pgContextChecksum = v11;
  v13 = 12;
  do
  {
    v14 = 8;
    do
    {
      v15 = pgContextChecksum ^ *v8;            // 当前哈希 ^ 数据
      v16 = v8 + 1;
      v17 = *v16;
      v8 = v16 + 1;
      pgContextChecksum = __ROL8__(__ROL8__(v15, v9) ^ v17, v9);
      --v14;
    }
    while ( v14 );                              // 已校验8*16=128B
    v18 = __ROL8__(v11 ^ ((unsigned __int64)v8 - pgContext), 17) ^ v11 ^ ((unsigned __int64)v8 - pgContext);
    v114 = (v18 * (unsigned __int128)0x7010008004002001uLL) >> 64;
    v9 = ((unsigned __int8)(v114 ^ v18) ^ (unsigned __int8)v9) & 0x3F;
    if ( !v9 )
      LOBYTE(v9) = 1;
    --v13;
  }
  while ( v13 );                                // context自检(一): 12轮,每轮取128字节,共计0x600字节
  LODWORD(Checksum) = 32;
  v20 = 4;
  v21 = 4;
  v22 = 64;
  do
  {
    pgContextChecksum = __ROL8__(*v8++ ^ pgContextChecksum, v9);
    Checksum = (unsigned int)(Checksum - 8);
    --v21;
  }
  while ( v21 );                                // context自检(二): 剩余32B
  if ( (_DWORD)Checksum )
  {
    do
    {
      v23 = *(unsigned __int8 *)v8;
      v8 = (_QWORD *)((char *)v8 + 1);
      pgContextChecksum = __ROL8__(v23 ^ pgContextChecksum, v9);
      v24 = (_DWORD)Checksum == 1;
      Checksum = (unsigned int)(Checksum - 1);
    }
    while ( !v24 );
  }
  *(_DWORD *)(pgContext + 0xC4) = pgContextLength;
  if ( *(_QWORD *)(pgContext + 0xA20) != pgContextChecksum )// context自检是否通过?
  {
    v25 = *(_QWORD *)(pgContext + 0x590);
    v26 = *(_DWORD *)(pgContext + 0x7E4);
    *(_QWORD *)v25 = pgContext;
    *(_DWORD *)(v25 + 16) = v26;
    Checksum = *(_QWORD *)(pgContext + 0xA20);
    if ( !*(_DWORD *)(pgContext + 0x8F8) )      // 确保尚未触发过(防重入)
    {
      *(_QWORD *)(*(_QWORD *)(pgContext + 0x590) + 24LL) = Checksum ^ pgContextChecksum;
      if ( !*(_DWORD *)(pgContext + 0x8F8) )
      {
        *(_QWORD *)(pgContext + 0x908) = 0;     // context完整性校验未通过, 还没有展开待校验部分到的检测, 置空
        *(_QWORD *)(pgContext + 0x900) = pgContext - 0x5C5FC0A76E374B18LL;
        *(_QWORD *)(pgContext + 0x910) = 0x109; // SECURITY_ASSERTION_FAILURE
        *(_QWORD *)(pgContext + 0x918) = pgContextChecksum;
        *(_DWORD *)(pgContext + 0x8F8) = 1;     // 标记“已触发”
        sub_14036C3BC(pgContext, 0);
      }
    }
  }
  v106 = 0;
  p_verificationRound_2 = &verificationRound_2;
  do
  {
    *(_BYTE *)p_verificationRound_2 = 0;
    p_verificationRound_2 = (unsigned int *)((char *)p_verificationRound_2 + 1);
    --v20;
  }
  while ( v20 );
  verificationRound_1 = 0;
  LODWORD(verificationRound) = 0;
  if ( *(_DWORD *)(pgContext + 0x7E0) )         // 阶段三: 是否进行内核完整性校验? 校验次数>0
  {
    while ( 1 )
    {
      v29 = pgContext;
      verificationRoundIndex = 0;
      if ( *(_QWORD *)(pgContext + 0xA78) )
        v29 = *(_QWORD *)(pgContext + 0xA78);
      kicd = (_KICD *)(v29 + *(unsigned int *)(v29 + 0x808));
      if ( (_DWORD)v106 && HIDWORD(v106) <= verificationRound_1 )// verificationRound≥1
      {
        verificationRoundIndex = HIDWORD(v106);
        kicd = (_KICD *)(v29 + verificationRound_2);
      }
      if ( verificationRoundIndex != verificationRound_1 )
        break;
LABEL_57:
      base_ptr = kicd->Base;                    // 内核完整性校验起始地址, v31是一个数据结构
      v40 = *(_DWORD *)(pgContext + 2068);
      v41 = (_DWORD)kicd - v29;
      v42 = *(_QWORD *)(pgContext + 2072);
      base_ptr_1 = (_QWORD *)base_ptr;
      HIDWORD(v106) = verificationRoundIndex;
      limit = (unsigned int)kicd->Limit;
      *(_DWORD *)(pgContext + 0x828) += limit;  // 更新累计校验长度
      verificationRound_2 = v41;
      offset = (const char *)base_ptr;
      LODWORD(v106) = 1;
      if ( base_ptr < (unsigned __int64)(base_ptr + limit) )
      {
        do
        {
          _mm_prefetch(offset, 0);
          offset += 64;
        }
        while ( (unsigned __int64)offset < base_ptr + limit );
      }
      pgContextChecksum_1 = v42;
      v47 = (unsigned int)limit >> 7;
      if ( (unsigned int)limit >> 7 )           // 每轮校验2^7=128B
      {
        do
        {
          v48 = 8;
          do
          {
            v49 = base_ptr_1[1] ^ __ROL8__(*base_ptr_1 ^ pgContextChecksum_1, v40);
            base_ptr_1 += 2;
            pgContextChecksum_1 = __ROL8__(v49, v40);
            --v48;
          }
          while ( v48 );                        // 校验16*8=128B
          v50 = __ROL8__(v42 ^ ((unsigned __int64)base_ptr_1 - base_ptr), 17)
              ^ v42
              ^ ((unsigned __int64)base_ptr_1 - base_ptr);
          Checksum = (v50 * (unsigned __int128)0x7010008004002001uLL) >> 64;
          v115 = Checksum;

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 4天前 被ALwalker编辑 ,原因: 补充内容
收藏
免费 20
支持
分享
最新回复 (5)
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
4天前
0
雪    币: 2790
活跃值: (5664)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
学习一下
3天前
0
雪    币: 4600
活跃值: (5142)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
感谢分享。
15小时前
0
雪    币: 6241
活跃值: (6035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
66
15小时前
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
感谢分享
11小时前
0
游客
登录 | 注册 方可回帖
返回