360晶核防护,第二弹

360晶核

Baklib
狐白 最后一次编辑 接近 3 年前
365
在上篇文章讲到了利用TF的方式来检测是否存在MsrHook,这一篇继续完善一些其他的检测方式
NewIDT[1] = PgCtx->IdtEntryIdx1; NewIDT[2] = PgCtx->IdtEntryIdx2; NewIDT[0x12] = PgCtx->IdtEntryIdx18h; NewIdtr.Size = 303; NewIdtr.Base = NewIDT; NewIDT[1].OffsetLow = &PgCtx->NewIdtDescriptor1; NewIDT[1].OffsetMiddle = &PgCtx->NewIdtDescriptor1 >> 16; NewIDT[1].OffsetHigh = &PgCtx->NewIdtDescriptor1 >> 32; _disable(); __sidt(OriginalIdt); __lidt(&NewIdtr); __writedr(7u, 0i64); NewIDT[1].OffsetLow = &PgCtx->NewIdtDescriptor2; // unclear why this is done again? NewIDT[1].OffsetMiddle = &PgCtx->NewIdtDescriptor2 >> 16; NewIDT[1].OffsetHigh = &PgCtx->NewIdtDescriptor2 >> 32; if ( PgCtx->FeaturesActiveFlags & 0x20 ) { PgCtx->StackSegmentReg = KiGetSs(); __writedr(0, &PgCtx->StackSegmentReg); __writedr(7u, 0x70001ui64); PgCtx->pSyscall = KiErrataSkx55Present(&PgCtx->StackSegmentReg); __writedr(7u, 0i64); __writedr(0, 0i64); } else { PgCtx->pSyscall = KiErrata704Present(); } PgCtx->PrcbNumber = KeGetPcr()->Prcb.Number; __lidt(OriginalIdt); _enable();
_disable(); pNewIdt[1] = PgCtx->IdtEntryIdx1; pNewIdt[2] = PgCtx->IdtEntryIdx2; pNewIdt[0x12] = PgCtx->IdtEntryIdx18h; NewIdtr.Size = 303; NewIdtr.Base = pNewIdt; pNewIdt[1].OffsetLow = &PgCtx->NewIdtDescriptor1; pNewIdt[1].OffsetMiddle = &PgCtx->NewIdtDescriptor1 >> 16; pNewIdt[1].OffsetHigh = &PgCtx->NewIdtDescriptor1 >> 32; __sidt(OriginalIdtr); __lidt(&NewIdtr); if ( !(PgCtx->ChecksStatusFlags & 0x20000) ) { CurrentPcrb = KeGetCurrentPrcb(); *PgCtx->qword_FFFFF80629E0F0C0 = &PgCtx + A3A03F5891C8B4E8h; *PgCtx->qword_FFFFF80629E12DE8 = CurrentPcrb; *PgCtx->qword_FFFFF80629E12DF0 = 0i64; *PgCtx->qword_FFFFF80629E12DF8 = 0x115i64; } KiErrata361Present(); if ( !(PgCtx->ChecksStatusFlags & 0x20000) ) { *PgCtx->qword_FFFFF80629E0F0C0 = 0xA3A03F5891C8B4E8ui64; *PgCtx->qword_FFFFF80629E12DE8 = 0i64; *PgCtx->qword_FFFFF80629E12DF0 = 0i64; *PgCtx->qword_FFFFF80629E12DF8 = 0i64; } __lidt(OriginalIdtr); _enable();
if ( PgCtx->FeaturesActiveFlags & 1 ) { _disable(); IA32MSR = 0xC0000082i64; // IA32_LSTAR_MSR pKiSyscall64 = __readmsr(0xC0000082); __writemsr(0xC0000082, &PgCtx->PgSyscallHook); // 0xC3 -> ret if ( !(PgCtx->ChecksStatusFlags & 0x20000) ) // (1) { Prcb = KeGetCurrentPrcb(); *PgCtx->qword_FFFFF80629E0F0C0 = &PgCtx + 0xA3A03F5891C8B4E8; *PgCtx->qword_FFFFF80629E12DE8 = Prcb; *PgCtx->qword_FFFFF80629E12DF0 = 0xC0000082i64; Temp = PgCtx->qword_FFFFF80629E12DF8; *Temp = 0x112i64; // (1) } KeGuardDispatchICall(&PgCtx->SyscallOpcode1); // 0F 05 -> syscall if ( !(PgCtx->ChecksStatusFlags & 0x20000) ) // (2) { *PgCtx->qword_FFFFF80629E0F0C0 = 0xA3A03F5891C8B4E8ui64; *PgCtx->qword_FFFFF80629E12DE8 = 0i64; *PgCtx->qword_FFFFF80629E12DF0 = 0i64; *PgCtx->qword_FFFFF80629E12DF8 = 0i64; // (2) } __writemsr(0xC0000082, pKiSyscall64); _enable(); }
另外还有一种方法,对比上面的方法,只能监视到SystemCallNumber,并推断出Hook的函数地址,以360晶核为例
不过这种方法 对地址进行检测 对性能是有影响的。
只能监视SSDT,因为我发现高版本win10 SSSDT  SystemCallNumber与函数地址不对等。 比如NtGdiExtEscape变成stub_GdiExtEscape
并且需要过滤NtCallbackReturn这个SystemCallNumber,否则函数地址是SSSDT的
.text:0000000140408418 89 83 80 00 00 00 mov [rbx+80h], eax .text:000000014040841E 66 90 xchg ax, ax .text:0000000140408420 .text:0000000140408420 KiSystemServiceStart: ; DATA XREF: KiServiceInternal+5A↑o .text:0000000140408420 ; .data:0000000140C00340↓o .text:0000000140408420 48 89 A3 90 00 00 00 mov [rbx+90h], rsp .text:0000000140408427 8B F8 mov edi, eax .text:0000000140408429 C1 EF 07 shr edi, 7 .text:000000014040842C 83 E7 20 and edi, 20h .text:000000014040842F 25 FF 0F 00 00 and eax, 0FFFh
(SystemCallNumber >> 7) & 0x20 = 服务表的索引,也是判断是否是SSSDT
函数地址=KeServiceDescriptorTable + 服务表的索引[SystemCallNumber & 0xFFF] >> 4
至于这种方法原理是什么,请参考别人实现KiSystemCall64的ASM