pg3 bypass源码阅读 —— 学习x64内核hook跳板技术
如之前描述的 pg3复杂了许多
先来看看都要hook哪些点
1、hook dpc和定时器分发器,防止seh路线触发pg
KiTimerListExpire,KiRetireDpcList
看一下hook点
hook的就是call的位置。
这里有两种方案:一种是直接jmp + 64bit addr,显然有同步问题,需要暂停所有cpu然后把irql提升到HIGH_LEVEL去操作。
另一种是 call 32bit 跳板 addr,如下图,操作8byte符合原子操作
e8 xxxxxxxx是32位转移,我们需要一个nt范围内的跳板,作者是这样处理的。把KiCustomAccessRoutine4跳转到KiCustomAccessRoutine0,那么KiCustomAccessRoutine4后面的代码就可以随便改了,不需要原子操作,这是一个技巧。
-
void VistaAll_DpcInterceptor(
-
PKDPC InDpc,
-
PVOID InDeferredContext,
-
PVOID InSystemArgument1,
-
PVOID InSystemArgument2)
-
{
-
ULONGLONG Routine = (ULONGLONG)InDpc->DeferredRoutine;
-
-
__try
-
{
-
if((Routine >= 0xFFFFFA8000000000) && (Routine <= 0xFFFFFAA000000000))
-
{
-
}
-
else
-
if(KeContainsSymbol((void*)Routine))
-
{
-
if(!PgIsPatchGuardContext(InDeferredContext))
-
InDpc->DeferredRoutine(InDpc, InDeferredContext, InSystemArgument1, InSystemArgument2);
-
}
-
else
-
InDpc->DeferredRoutine(InDpc, InDeferredContext, InSystemArgument1, InSystemArgument2);
-
}
-
__except(EXCEPTION_EXECUTE_HANDLER)
-
{
-
}
-
}
fake dpc的处理非常简单,判断dpc context即可
2.hook ExpWorkerThread 工作线程也有可能触发pg,hook方法同上,fake函数如下
-
VOID VistaAll_ExpWorkerThreadInterceptor(PWORKER_THREAD_ROUTINE InRoutine, VOID* InContext, VOID* InRSP)
-
{
-
ULONGLONG Val = (ULONGLONG)InRoutine;
-
-
if((Val >= 0xfffffa8000000000) && (Val <= 0xfffffaa000000000))
-
return;
-
-
__try
-
{
-
InRoutine(InContext);
-
}
-
__except(EXCEPTION_EXECUTE_HANDLER)
-
{
-
}
-
}
过滤了所有内核的work thread,工作线程是non-seh mode,无法过滤非传统地址,所以过滤了所有的nt工作线程。。总是系统跑起来之后也不会再排新的工作线程就是了。
3.这样还不够,hook KeBugcheckEx作为补充,KeBugcheckEx是被PG循环恢复的,但是分析代码KeBugcheckEx一开始就调用到RtlCaptureContext,所以转去hook RtlCaptureContext,还是用跳板函数,用到了栈回溯
-
RtlCaptureContext_Hook PROC
-
-
; call high level handler without messing up the context structure...
-
push rcx
-
push rdx
-
push r8
-
push r9
-
push r10
-
push r11
-
mov rcx, qword ptr[rsp + 128]
-
mov rdx, qword ptr[rsp + 7 * 8]
-
sub rsp, 32
-
call KeBugCheck_Hook
-
mov qword ptr [rsp], rax
-
add rsp, 32
-
pop r11
-
pop r10
-
pop r9
-
pop r8
-
pop rdx
-
pop rcx
-
pop rax
-
-
; recover destroyed bytes of RtlCaptureContext
-
pushfq
-
mov word ptr [rcx+38h],cs
-
mov word ptr [rcx+3Ah],ds
-
mov word ptr [rcx+3Ch],es
-
mov word ptr [rcx+42h],ss
-
-
; jump behind destroyed bytes... (RetVal of RtlCaptureContext_HookEx)
-
jmp qword ptr[rsp - 32 - 8 * 7 + 8]
-
-
RtlCaptureContext_Hook ENDP
fake函数将pg进入死循环
-
ULONGLONG KeBugCheck_Hook(ULONGLONG InBugCode, ULONGLONG InCaller)
-
{
-
FAST_MUTEX WaitAlways;
-
-
//判断调用者
-
if((InCaller >= KeBugCheckEx_Sym) && (InCaller <= KeBugCheckEx_Sym + 100))
-
{
-
if(InBugCode == CRITICAL_STRUCTURE_CORRUPTION)
-
{
-
// KeBugCheckEx disables interrupts before calling RtlCaptureContext()
-
EnableInterrupts();
-
-
//进入死循环
-
ExInitializeFastMutex(&WaitAlways);
-
ExAcquireFastMutex(&WaitAlways);
-
ExAcquireFastMutex(&WaitAlways);
-
}
-
}
-
-
//返回跳转地址
-
return RtlCaptureContext_Sym + 14;
-
}
jpg 改 rar