pg3 bypass源码阅读 —— 学习x64内核hook跳板技术
2012-07-28 06:52
423 查看
如之前描述的 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后面的代码就可以随便改了,不需要原子操作,这是一个技巧。
fake dpc的处理非常简单,判断dpc context即可
2.hook ExpWorkerThread 工作线程也有可能触发pg,hook方法同上,fake函数如下
过滤了所有内核的work thread,工作线程是non-seh mode,无法过滤非传统地址,所以过滤了所有的nt工作线程。。总是系统跑起来之后也不会再排新的工作线程就是了。
3.这样还不够,hook KeBugcheckEx作为补充,KeBugcheckEx是被PG循环恢复的,但是分析代码KeBugcheckEx一开始就调用到RtlCaptureContext,所以转去hook RtlCaptureContext,还是用跳板函数,用到了栈回溯
fake函数将pg进入死循环
先来看看都要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; }
相关文章推荐
- PG2 BYPASS源码阅读 学习x64解密定时器、特征码定位
- 谈C程序员修养及大型项目源码阅读与学习
- 内核源码学习:LILO的运行分析
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)
- FLV学习(四)FlvParser源码阅读(2)相关的数据结构
- Halide学习笔记----Halide tutorial源码阅读16
- [Android阅读代码]android-async-http源码学习一
- Linux内核源码学习之 基本知识
- Halide学习笔记----Halide tutorial源码阅读5
- sled11下cscope工具用于阅读内核源码
- pg源码阅读五
- KVM内核源码学习之源码组成
- Redux 学习笔记 - 源码阅读
- 使用vim+ctags+cscope阅读内核源码
- memcached源码阅读学习
- Java三大集合类源码阅读笔记【包含超类Collection】提供学习源码
- 开始阅读YAFFS源码 2.6.18以上需要打补丁 yaffs2 内核 kernel的ecc布局
- MP4学习(六)ts-mp4源码阅读(4)moov box的解析
- Linux网管笔记(17)阅读Linux的内核源码