虽然网上关于 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 使用异常处理程序来激活检查,而 KiTimerDispatch 和 KiDpcDispatch 则直接调用 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;
ULONG bUnknow;
...
} KICD, * PKICD;
typedef struct _KICD {
ULONG Type;
ULONG Unknow;
PVOID Base;
ULONG Limit;
ULONG Checksum;
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;
__int64 idtBase;
__int64 index;
_QWORD *idt_ptr;
int idtSize;
int pgContextLength;
_QWORD *v8;
int v9;
const char *mem_offset;
__int64 v11;
__int64 pgContextChecksum;
int v13;
__int64 v14;
__int64 v15;
__int64 *v16;
__int64 v17;
unsigned __int64 v18;
__int64 Checksum;
int v20;
__int64 v21;
int v22;
__int64 v23;
bool v24;
__int64 v25;
int v26;
unsigned int *p_verificationRound_2;
unsigned int verificationRound_1;
__int64 v29;
unsigned int verificationRoundIndex;
_KICD *kicd;
__int64 v32;
int v33;
int v34;
int v35;
int v36;
__int64 v37;
int Unknow_low;
__int64 base_ptr;
int v40;
unsigned int v41;
unsigned __int64 v42;
_QWORD *base_ptr_1;
__int64 limit;
const char *offset;
unsigned __int64 pgContextChecksum_1;
unsigned int v47;
__int64 v48;
__int64 v49;
unsigned __int64 v50;
__int64 v51;
unsigned __int64 v52;
__int64 v53;
unsigned __int64 i;
unsigned int pgContextChecksum_dd;
BOOL v56;
__int64 Limit;
__int64 Base;
unsigned __int8 CurrentIrql;
unsigned __int64 basePageAlignment;
unsigned __int64 v61;
int v62;
__int64 v63;
__int64 v64;
__int64 v65;
__int64 v66;
struct _KPRCB *CurrentPrcb;
__int64 *v68;
__int64 v69;
unsigned __int64 v70;
unsigned __int64 v71;
unsigned int v72;
unsigned __int64 v73;
_QWORD *j;
unsigned __int64 v75;
int failed;
__int64 v77;
__int64 Type;
unsigned __int64 v79;
__int64 v80;
_QWORD *v81;
char *v82;
int v83;
unsigned __int64 v84;
signed __int64 v85;
__int64 newPgContext;
unsigned __int64 v87;
unsigned __int64 v88;
_QWORD *v89;
unsigned __int64 v90;
unsigned __int128 v91;
__int64 v92;
char *v93;
_QWORD *v94;
__int64 v95;
char v96;
unsigned __int64 v97;
int v99;
int v100;
int v101;
int v102;
int v103;
volatile signed __int32 *v104;
signed __int32 v105[8];
__int64 v106;
unsigned int verificationRound_2;
__int64 verificationRound;
unsigned __int64 ptr;
__int64 limitPageAlignment;
__int64 v111;
_WORD NewIdtr[8];
_BYTE oldIDTR[16];
__int64 v114;
__int64 v115;
__int64 v116;
__int64 v117;
pgContext = (__int64)CmpAppendDllSection_ptr;
if ( (*((_DWORD *)CmpAppendDllSection_ptr + 0x264) & 0x110000) != 0x110000 )
{
idtBase = *((_QWORD *)CmpAppendDllSection_ptr + 0x11C);
index = 0x26;
idt_ptr = (_QWORD *)idtBase;
idtSize = 0x130;
do
{
*idt_ptr = 0;
idtSize -= 8;
++idt_ptr;
--index;
}
while ( index );
for ( ; idtSize; --idtSize )
{
*(_BYTE *)idt_ptr = 0;
idt_ptr = (_QWORD *)((char *)idt_ptr + 1);
}
*(_OWORD *)(idtBase + 0x10) = *(_OWORD *)(pgContext + 0x848);
*(_OWORD *)(idtBase + 0x20) = *(_OWORD *)(pgContext + 0x858);
*(_OWORD *)(idtBase + 0x120) = *(_OWORD *)(pgContext + 0x868);
NewIdtr[0] = 0x12F;
*(_QWORD *)&NewIdtr[1] = idtBase;
*(_WORD *)(idtBase + 0x10) = pgContext + 0x878;
*(_DWORD *)(idtBase + 0x18) = (unsigned __int64)(pgContext + 0x878) >> 32;
*(_WORD *)(idtBase + 0x16) = (unsigned int)(pgContext + 0x878) >> 16;
_disable();
if ( *(int *)(pgContext + 0x990) >= 0 )
{
__sidt(oldIDTR);
__lidt(NewIdtr);
__writedr(7u, 0);
__lidt(oldIDTR);
}
else
{
__writedr(7u, 0);
}
_enable();
}
*(_DWORD *)(pgContext + 0x828) += 0x620;
pgContextLength = *(_DWORD *)(pgContext + 0xC4);
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) )
{
do
{
_mm_prefetch(mem_offset, 0);
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 );
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 );
LODWORD(Checksum) = 32;
v20 = 4;
v21 = 4;
v22 = 64;
do
{
pgContextChecksum = __ROL8__(*v8++ ^ pgContextChecksum, v9);
Checksum = (unsigned int)(Checksum - 8);
--v21;
}
while ( v21 );
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 )
{
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;
*(_QWORD *)(pgContext + 0x900) = pgContext - 0x5C5FC0A76E374B18LL;
*(_QWORD *)(pgContext + 0x910) = 0x109;
*(_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) )
{
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 )
{
verificationRoundIndex = HIDWORD(v106);
kicd = (_KICD *)(v29 + verificationRound_2);
}
if ( verificationRoundIndex != verificationRound_1 )
break;
LABEL_57:
base_ptr = kicd->Base;
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 )
{
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 );
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;
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 )
{
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);
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);
if ( v62 != 0xC000022D )
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 )
{
*(_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;
}
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);
}
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,
v65,
v64,
v63,
*(__int64 (__fastcall **)(__int64, __int64, __int64, __int64, __int64))(pgContext + 0x158),
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);
}
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;
*(_QWORD *)(pgContext + 1944) = 0;
_disable();
_enable();
LOBYTE(v92) = (*(__int64 (__fastcall **)(__int64, __int64))(pgContext + 0x268))(pgContext + 0x800, Checksum);
(*(void (__fastcall **)(__int64, __int64))(pgContext + 0x270))(pgContext + 0x800, v92);
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;
__int64 idtBase;
__int64 index;
_QWORD *idt_ptr;
int idtSize;
int pgContextLength;
_QWORD *v8;
int v9;
const char *mem_offset;
__int64 v11;
__int64 pgContextChecksum;
int v13;
__int64 v14;
__int64 v15;
__int64 *v16;
__int64 v17;
unsigned __int64 v18;
__int64 Checksum;
int v20;
__int64 v21;
int v22;
__int64 v23;
bool v24;
__int64 v25;
int v26;
unsigned int *p_verificationRound_2;
unsigned int verificationRound_1;
__int64 v29;
unsigned int verificationRoundIndex;
_KICD *kicd;
__int64 v32;
int v33;
int v34;
int v35;
int v36;
__int64 v37;
int Unknow_low;
__int64 base_ptr;
int v40;
unsigned int v41;
unsigned __int64 v42;
_QWORD *base_ptr_1;
__int64 limit;
const char *offset;
unsigned __int64 pgContextChecksum_1;
unsigned int v47;
__int64 v48;
__int64 v49;
unsigned __int64 v50;
__int64 v51;
unsigned __int64 v52;
__int64 v53;
unsigned __int64 i;
unsigned int pgContextChecksum_dd;
BOOL v56;
__int64 Limit;
__int64 Base;
unsigned __int8 CurrentIrql;
unsigned __int64 basePageAlignment;
unsigned __int64 v61;
int v62;
__int64 v63;
__int64 v64;
__int64 v65;
__int64 v66;
struct _KPRCB *CurrentPrcb;
__int64 *v68;
__int64 v69;
unsigned __int64 v70;
unsigned __int64 v71;
unsigned int v72;
unsigned __int64 v73;
_QWORD *j;
unsigned __int64 v75;
int failed;
__int64 v77;
__int64 Type;
unsigned __int64 v79;
__int64 v80;
_QWORD *v81;
char *v82;
int v83;
unsigned __int64 v84;
signed __int64 v85;
__int64 newPgContext;
unsigned __int64 v87;
unsigned __int64 v88;
_QWORD *v89;
unsigned __int64 v90;
unsigned __int128 v91;
__int64 v92;
char *v93;
_QWORD *v94;
__int64 v95;
char v96;
unsigned __int64 v97;
int v99;
int v100;
int v101;
int v102;
int v103;
volatile signed __int32 *v104;
signed __int32 v105[8];
__int64 v106;
unsigned int verificationRound_2;
__int64 verificationRound;
unsigned __int64 ptr;
__int64 limitPageAlignment;
__int64 v111;
_WORD NewIdtr[8];
_BYTE oldIDTR[16];
__int64 v114;
__int64 v115;
__int64 v116;
__int64 v117;
pgContext = (__int64)CmpAppendDllSection_ptr;
if ( (*((_DWORD *)CmpAppendDllSection_ptr + 0x264) & 0x110000) != 0x110000 )
{
idtBase = *((_QWORD *)CmpAppendDllSection_ptr + 0x11C);
index = 0x26;
idt_ptr = (_QWORD *)idtBase;
idtSize = 0x130;
do
{
*idt_ptr = 0;
idtSize -= 8;
++idt_ptr;
--index;
}
while ( index );
for ( ; idtSize; --idtSize )
{
*(_BYTE *)idt_ptr = 0;
idt_ptr = (_QWORD *)((char *)idt_ptr + 1);
}
*(_OWORD *)(idtBase + 0x10) = *(_OWORD *)(pgContext + 0x848);
*(_OWORD *)(idtBase + 0x20) = *(_OWORD *)(pgContext + 0x858);
*(_OWORD *)(idtBase + 0x120) = *(_OWORD *)(pgContext + 0x868);
NewIdtr[0] = 0x12F;
*(_QWORD *)&NewIdtr[1] = idtBase;
*(_WORD *)(idtBase + 0x10) = pgContext + 0x878;
*(_DWORD *)(idtBase + 0x18) = (unsigned __int64)(pgContext + 0x878) >> 32;
*(_WORD *)(idtBase + 0x16) = (unsigned int)(pgContext + 0x878) >> 16;
_disable();
if ( *(int *)(pgContext + 0x990) >= 0 )
{
__sidt(oldIDTR);
__lidt(NewIdtr);
__writedr(7u, 0);
__lidt(oldIDTR);
}
else
{
__writedr(7u, 0);
}
_enable();
}
*(_DWORD *)(pgContext + 0x828) += 0x620;
pgContextLength = *(_DWORD *)(pgContext + 0xC4);
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) )
{
do
{
_mm_prefetch(mem_offset, 0);
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 );
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 );
LODWORD(Checksum) = 32;
v20 = 4;
v21 = 4;
v22 = 64;
do
{
pgContextChecksum = __ROL8__(*v8++ ^ pgContextChecksum, v9);
Checksum = (unsigned int)(Checksum - 8);
--v21;
}
while ( v21 );
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 )
{
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;
*(_QWORD *)(pgContext + 0x900) = pgContext - 0x5C5FC0A76E374B18LL;
*(_QWORD *)(pgContext + 0x910) = 0x109;
*(_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) )
{
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 )
{
verificationRoundIndex = HIDWORD(v106);
kicd = (_KICD *)(v29 + verificationRound_2);
}
if ( verificationRoundIndex != verificationRound_1 )
break;
LABEL_57:
base_ptr = kicd->Base;
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 )
{
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 );
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编辑
,原因: 补充内容