VOID
NTAPI
PgCheckAllWorkerThread(
__inout PPGBLOCK PgBlock
)
{
NTSTATUS Status = STATUS_SUCCESS;
PSYSTEM_PROCESS_INFORMATION ProcessInfo = NULL;
PSYSTEM_EXTENDED_THREAD_INFORMATION ThreadInfo = NULL;
PVOID Buffer = NULL;
ULONG BufferSize = PAGE_SIZE;
ULONG ReturnLength = 0;
ULONG Index = 0;
PULONG64 InitialStack = 0;
DISPATCHER_HEADER * Header = NULL;
/*
if (os build >= 9600){
PgBlock->WorkerContext = struct _DISPATCHER_HEADER
Header->Type = 0x15
Header->Hand = 0xac
}
else {
PgBlock->WorkerContext = enum _WORK_QUEUE_TYPE
CriticalWorkQueue = 0
DelayedWorkQueue = 1
}
*/
InitialStack = IoGetInitialStack();
if (GetGpBlock(PgBlock)->BuildNumber >= 9600) {
while ((ULONG64)InitialStack != (ULONG64)&PgBlock) {
Header = *(PVOID *)InitialStack;
if (FALSE != MmIsAddressValid(Header)) {
if (FALSE != MmIsAddressValid((PCHAR)(Header + 1) - 1)) {
if (0x15 == Header->Type &&
0xac == Header->Hand) {
PgBlock->WorkerContext = Header;
break;
}
}
}
InitialStack--;
}
}
else {
PgBlock->WorkerContext = UlongToPtr(CriticalWorkQueue);
}
retry:
Buffer = ExAllocatePool(
NonPagedPool,
BufferSize);
if (NULL != Buffer) {
RtlZeroMemory(
Buffer,
BufferSize);
Status = ZwQuerySystemInformation(
SystemExtendedProcessInformation,
Buffer,
BufferSize,
&ReturnLength);
if (NT_SUCCESS(Status)) {
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
while (TRUE) {
if (PsGetCurrentProcessId() == ProcessInfo->UniqueProcessId) {
ThreadInfo = (PSYSTEM_EXTENDED_THREAD_INFORMATION)
(ProcessInfo + 1);
if (NULL == PgBlock->ExpWorkerThread) {
for (Index = 0;
Index < ProcessInfo->NumberOfThreads;
Index++) {
if ((ULONG64)PsGetCurrentThreadId() ==
(ULONG64)ThreadInfo[Index].ThreadInfo.ClientId.UniqueThread) {
PgBlock->ExpWorkerThread = ThreadInfo[Index].Win32StartAddress;
break;
}
}
}
if (NULL != PgBlock->ExpWorkerThread) {
for (Index = 0;
Index < ProcessInfo->NumberOfThreads;
Index++) {
if ((ULONG64)PsGetCurrentThreadId() !=
(ULONG64)ThreadInfo[Index].ThreadInfo.ClientId.UniqueThread &&
(ULONG64)PgBlock->ExpWorkerThread ==
(ULONG64)ThreadInfo[Index].Win32StartAddress) {
AsyncCall(
ThreadInfo[Index].ThreadInfo.ClientId.UniqueThread,
NULL,
NULL,
(PUSER_THREAD_START_ROUTINE)PgCheckWorkerThread,
PgBlock);
}
}
}
break;
}
if (0 == ProcessInfo->NextEntryOffset) {
break;
}
else {
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
((PCHAR)ProcessInfo + ProcessInfo->NextEntryOffset);
}
}
}
ExFreePool(Buffer);
Buffer = NULL;
if (STATUS_INFO_LENGTH_MISMATCH == Status) {
BufferSize = ReturnLength;
goto retry;
}
}
}
VOID
NTAPI
PgLocatePoolObject(
__inout PPGBLOCK PgBlock,
__in PPGOBJECT Object
)
{
PFN_NUMBER Index = 0;
PVOID Establisher = NULL;
GetCounterBody(&Object->Establisher, &Establisher);
for (Index = 0;
Index < PgBlock->PoolBigPageTableSize;
Index++) {
if (POOL_BIG_TABLE_ENTRY_FREE !=
((ULONG64)PgBlock->PoolBigPageTable[Index].Va & POOL_BIG_TABLE_ENTRY_FREE)) {
if (NonPagedPool == PgBlock->MmDeterminePoolType(PgBlock->PoolBigPageTable[Index].Va)) {
if (PgBlock->PoolBigPageTable[Index].NumberOfPages > PgBlock->SizeINITKDBG) {
if ((ULONG64)Establisher >= (ULONG64)PgBlock->PoolBigPageTable[Index].Va &&
(ULONG64)Establisher < (ULONG64)PgBlock->PoolBigPageTable[Index].Va +
PgBlock->PoolBigPageTable[Index].NumberOfPages) {
Object->BaseAddress = PgBlock->PoolBigPageTable[Index].Va;
Object->RegionSize = PgBlock->PoolBigPageTable[Index].NumberOfPages;
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > found region in pool < %p - %08x >\n",
Establisher,
Object->BaseAddress,
Object->RegionSize);
#endif // !PUBLIC
Object->Type = PgPoolBigPage;
break;
}
}
}
}
}
}
VOID
NTAPI
PgLocateSystemPtesObject(
__inout PPGBLOCK PgBlock,
__in PPGOBJECT Object
)
{
PRTL_BITMAP BitMap = NULL;
ULONG BitMapSize = 0;
PFN_NUMBER NumberOfPtes = 0;
ULONG HintIndex = 0;
ULONG StartingRunIndex = 0;
PVOID Establisher = NULL;
NumberOfPtes = PgBlock->NumberOfPtes;
GetCounterBody(&Object->Establisher, &Establisher);
BitMapSize =
sizeof(RTL_BITMAP) +
(ULONG)((((NumberOfPtes + 1) + 31) / 32) * 4);
BitMap = ExAllocatePool(NonPagedPool, BitMapSize);
if (NULL != BitMap) {
RtlInitializeBitMap(
BitMap,
(PULONG)(BitMap + 1),
(ULONG)(NumberOfPtes + 1));
RtlClearAllBits(BitMap);
InitializeSystemPtesBitMap(
PgBlock->BasePte,
NumberOfPtes,
BitMap);
do {
HintIndex = RtlFindSetBits(
BitMap,
1,
HintIndex);
if (MAXULONG != HintIndex) {
RtlFindNextForwardRunClear(
BitMap,
HintIndex,
&StartingRunIndex);
RtlClearBits(BitMap, HintIndex, StartingRunIndex - HintIndex);
if ((ULONG64)Establisher >=
(ULONG64)GetVirtualAddressMappedByPte(
PgBlock->BasePte + HintIndex) &&
(ULONG64)Establisher <
(ULONG64)GetVirtualAddressMappedByPte(
PgBlock->BasePte + StartingRunIndex) - PgBlock->SizeCmpAppendDllSection) {
Object->BaseAddress =
GetVirtualAddressMappedByPte(PgBlock->BasePte + HintIndex);
Object->RegionSize =
(SIZE_T)(StartingRunIndex - HintIndex) * PAGE_SIZE;
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > found region in system ptes < %p - %08x >\n",
Establisher,
Object->BaseAddress,
Object->RegionSize);
#endif // !PUBLIC
Object->Type = PgSystemPtes;
break;
}
HintIndex = StartingRunIndex;
}
} while (HintIndex < NumberOfPtes);
ExFreePool(BitMap);
}
}
VOID
NTAPI
PgLocateObject(
__inout PPGBLOCK PgBlock,
__out PPGOBJECT Object
)
{
IpiSingleCall(
(PPS_APC_ROUTINE)NULL,
(PKSYSTEM_ROUTINE)PgLocatePoolObject,
(PUSER_THREAD_START_ROUTINE)PgBlock,
(PVOID)Object);
if (-1 == Object->Type) {
IpiSingleCall(
(PPS_APC_ROUTINE)NULL,
(PKSYSTEM_ROUTINE)PgLocateSystemPtesObject,
(PUSER_THREAD_START_ROUTINE)PgBlock,
(PVOID)Object);
}
}
VOID
NTAPI
PgCheckWorkerThread(
__inout PPGBLOCK PgBlock
)
{
ULONG64 LowLimit = 0;
ULONG64 HighLimit = 0;
PULONG64 InitialStack = 0;
PULONG64 TargetPc = NULL;
ULONG Count = 0;
PCALLERS Callers = NULL;
ULONG Index = 0;
LONG_PTR Reference = 0;
PVOID * Parameters = NULL;
PGOBJECT TempObject = { 0 };
PPGOBJECT Object = NULL;
Callers = ExAllocatePool(
NonPagedPool,
MAX_STACK_DEPTH * sizeof(CALLERS));
if (NULL != Callers) {
Count = WalkFrameChain(
Callers,
MAX_STACK_DEPTH);
if (0 != Count) {
// PrintFrameChain(Callers, 0, Count);
IoGetStackLimits(&LowLimit, &HighLimit);
InitialStack = IoGetInitialStack();
// all worker thread start at KiStartSystemThread and return address == 0
// if null != last return address code is in noimage
if (NULL != Callers[Count - 1].Establisher) {
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > found noimage return address in worker thread\n",
Callers[Count - 1].Establisher);
#endif // !PUBLIC
for (TargetPc = (PULONG64)Callers[Count - 1].EstablisherFrame;
(ULONG64)TargetPc < (ULONG64)InitialStack;
TargetPc++) {
// In most cases, PatchGuard code will wait for a random time.
// set return address in current thread stack to _RevertWorkerToSelf
// than PatchGuard code was not continue
if ((ULONG64)*TargetPc == (ULONG64)Callers[Count - 1].Establisher) {
// restart ExpWorkerThread
// ExFrame->P1Home = WorkerContext;
// ExFrame->P2Home = ExpWorkerThread;
// ExFrame->P3Home = PspSystemThreadStartup;
// ExFrame->Return = KiStartSystemThread; <- jmp this function return address == 0
SetCounterBody(
&TempObject.Establisher,
Callers[Count - 1].Establisher);
TempObject.Type = -1;
PgLocateObject(PgBlock, &TempObject);
if (-1 != TempObject.Type) {
Object = PgCreateObject(
PgDeclassified,
TempObject.Type,
TempObject.BaseAddress,
TempObject.RegionSize,
NULL,
PgBlock,
PgBlock->ClearCallback,
Callers[Count - 1].Establisher,
GetGpBlock(PgBlock)->CaptureContext);
if (NULL != Object) {
SetCounterBody(
&Object->Establisher,
Callers[Count - 1].Establisher);
*TargetPc = (ULONG64)&Object->Establisher;
InterlockedIncrementSizeT(&PgBlock->ReferenceCount);
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > insert worker thread check code\n",
PgBlock->ReferenceCount);
#endif // !PUBLIC
}
}
break;
}
}
}
}
ExFreePool(Callers);
}
}
VOID
NTAPI
PgCheckAllWorkerThread(
__inout PPGBLOCK PgBlock
)
{
NTSTATUS Status = STATUS_SUCCESS;
PSYSTEM_PROCESS_INFORMATION ProcessInfo = NULL;
PSYSTEM_EXTENDED_THREAD_INFORMATION ThreadInfo = NULL;
PVOID Buffer = NULL;
ULONG BufferSize = PAGE_SIZE;
ULONG ReturnLength = 0;
ULONG Index = 0;
PULONG64 InitialStack = 0;
DISPATCHER_HEADER * Header = NULL;
/*
if (os build >= 9600){
PgBlock->WorkerContext = struct _DISPATCHER_HEADER
Header->Type = 0x15
Header->Hand = 0xac
}
else {
PgBlock->WorkerContext = enum _WORK_QUEUE_TYPE
CriticalWorkQueue = 0
DelayedWorkQueue = 1
}
*/
InitialStack = IoGetInitialStack();
if (GetGpBlock(PgBlock)->BuildNumber >= 9600) {
while ((ULONG64)InitialStack != (ULONG64)&PgBlock) {
Header = *(PVOID *)InitialStack;
if (FALSE != MmIsAddressValid(Header)) {
if (FALSE != MmIsAddressValid((PCHAR)(Header + 1) - 1)) {
if (0x15 == Header->Type &&
0xac == Header->Hand) {
PgBlock->WorkerContext = Header;
break;
}
}
}
InitialStack--;
}
}
else {
PgBlock->WorkerContext = UlongToPtr(CriticalWorkQueue);
}
retry:
Buffer = ExAllocatePool(
NonPagedPool,
BufferSize);
if (NULL != Buffer) {
RtlZeroMemory(
Buffer,
BufferSize);
Status = ZwQuerySystemInformation(
SystemExtendedProcessInformation,
Buffer,
BufferSize,
&ReturnLength);
if (NT_SUCCESS(Status)) {
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
while (TRUE) {
if (PsGetCurrentProcessId() == ProcessInfo->UniqueProcessId) {
ThreadInfo = (PSYSTEM_EXTENDED_THREAD_INFORMATION)
(ProcessInfo + 1);
if (NULL == PgBlock->ExpWorkerThread) {
for (Index = 0;
Index < ProcessInfo->NumberOfThreads;
Index++) {
if ((ULONG64)PsGetCurrentThreadId() ==
(ULONG64)ThreadInfo[Index].ThreadInfo.ClientId.UniqueThread) {
PgBlock->ExpWorkerThread = ThreadInfo[Index].Win32StartAddress;
break;
}
}
}
if (NULL != PgBlock->ExpWorkerThread) {
for (Index = 0;
Index < ProcessInfo->NumberOfThreads;
Index++) {
if ((ULONG64)PsGetCurrentThreadId() !=
(ULONG64)ThreadInfo[Index].ThreadInfo.ClientId.UniqueThread &&
(ULONG64)PgBlock->ExpWorkerThread ==
(ULONG64)ThreadInfo[Index].Win32StartAddress) {
AsyncCall(
ThreadInfo[Index].ThreadInfo.ClientId.UniqueThread,
NULL,
NULL,
(PUSER_THREAD_START_ROUTINE)PgCheckWorkerThread,
PgBlock);
}
}
}
break;
}
if (0 == ProcessInfo->NextEntryOffset) {
break;
}
else {
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
((PCHAR)ProcessInfo + ProcessInfo->NextEntryOffset);
}
}
}
ExFreePool(Buffer);
Buffer = NULL;
if (STATUS_INFO_LENGTH_MISMATCH == Status) {
BufferSize = ReturnLength;
goto retry;
}
}
}
VOID
NTAPI
PgLocatePoolObject(
__inout PPGBLOCK PgBlock,
__in PPGOBJECT Object
)
{
PFN_NUMBER Index = 0;
PVOID Establisher = NULL;
GetCounterBody(&Object->Establisher, &Establisher);
for (Index = 0;
Index < PgBlock->PoolBigPageTableSize;
Index++) {
if (POOL_BIG_TABLE_ENTRY_FREE !=
((ULONG64)PgBlock->PoolBigPageTable[Index].Va & POOL_BIG_TABLE_ENTRY_FREE)) {
if (NonPagedPool == PgBlock->MmDeterminePoolType(PgBlock->PoolBigPageTable[Index].Va)) {
if (PgBlock->PoolBigPageTable[Index].NumberOfPages > PgBlock->SizeINITKDBG) {
if ((ULONG64)Establisher >= (ULONG64)PgBlock->PoolBigPageTable[Index].Va &&
(ULONG64)Establisher < (ULONG64)PgBlock->PoolBigPageTable[Index].Va +
PgBlock->PoolBigPageTable[Index].NumberOfPages) {
Object->BaseAddress = PgBlock->PoolBigPageTable[Index].Va;
Object->RegionSize = PgBlock->PoolBigPageTable[Index].NumberOfPages;
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > found region in pool < %p - %08x >\n",
Establisher,
Object->BaseAddress,
Object->RegionSize);
#endif // !PUBLIC
Object->Type = PgPoolBigPage;
break;
}
}
}
}
}
}
VOID
NTAPI
PgLocateSystemPtesObject(
__inout PPGBLOCK PgBlock,
__in PPGOBJECT Object
)
{
PRTL_BITMAP BitMap = NULL;
ULONG BitMapSize = 0;
PFN_NUMBER NumberOfPtes = 0;
ULONG HintIndex = 0;
ULONG StartingRunIndex = 0;
PVOID Establisher = NULL;
NumberOfPtes = PgBlock->NumberOfPtes;
GetCounterBody(&Object->Establisher, &Establisher);
BitMapSize =
sizeof(RTL_BITMAP) +
(ULONG)((((NumberOfPtes + 1) + 31) / 32) * 4);
BitMap = ExAllocatePool(NonPagedPool, BitMapSize);
if (NULL != BitMap) {
RtlInitializeBitMap(
BitMap,
(PULONG)(BitMap + 1),
(ULONG)(NumberOfPtes + 1));
RtlClearAllBits(BitMap);
InitializeSystemPtesBitMap(
PgBlock->BasePte,
NumberOfPtes,
BitMap);
do {
HintIndex = RtlFindSetBits(
BitMap,
1,
HintIndex);
if (MAXULONG != HintIndex) {
RtlFindNextForwardRunClear(
BitMap,
HintIndex,
&StartingRunIndex);
RtlClearBits(BitMap, HintIndex, StartingRunIndex - HintIndex);
if ((ULONG64)Establisher >=
(ULONG64)GetVirtualAddressMappedByPte(
PgBlock->BasePte + HintIndex) &&
(ULONG64)Establisher <
(ULONG64)GetVirtualAddressMappedByPte(
PgBlock->BasePte + StartingRunIndex) - PgBlock->SizeCmpAppendDllSection) {
Object->BaseAddress =
GetVirtualAddressMappedByPte(PgBlock->BasePte + HintIndex);
Object->RegionSize =
(SIZE_T)(StartingRunIndex - HintIndex) * PAGE_SIZE;
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > found region in system ptes < %p - %08x >\n",
Establisher,
Object->BaseAddress,
Object->RegionSize);
#endif // !PUBLIC
Object->Type = PgSystemPtes;
break;
}
HintIndex = StartingRunIndex;
}
} while (HintIndex < NumberOfPtes);
ExFreePool(BitMap);
}
}
VOID
NTAPI
PgLocateObject(
__inout PPGBLOCK PgBlock,
__out PPGOBJECT Object
)
{
IpiSingleCall(
(PPS_APC_ROUTINE)NULL,
(PKSYSTEM_ROUTINE)PgLocatePoolObject,
(PUSER_THREAD_START_ROUTINE)PgBlock,
(PVOID)Object);
if (-1 == Object->Type) {
IpiSingleCall(
(PPS_APC_ROUTINE)NULL,
(PKSYSTEM_ROUTINE)PgLocateSystemPtesObject,
(PUSER_THREAD_START_ROUTINE)PgBlock,
(PVOID)Object);
}
}
VOID
NTAPI
PgCheckWorkerThread(
__inout PPGBLOCK PgBlock
)
{
ULONG64 LowLimit = 0;
ULONG64 HighLimit = 0;
PULONG64 InitialStack = 0;
PULONG64 TargetPc = NULL;
ULONG Count = 0;
PCALLERS Callers = NULL;
ULONG Index = 0;
LONG_PTR Reference = 0;
PVOID * Parameters = NULL;
PGOBJECT TempObject = { 0 };
PPGOBJECT Object = NULL;
Callers = ExAllocatePool(
NonPagedPool,
MAX_STACK_DEPTH * sizeof(CALLERS));
if (NULL != Callers) {
Count = WalkFrameChain(
Callers,
MAX_STACK_DEPTH);
if (0 != Count) {
// PrintFrameChain(Callers, 0, Count);
IoGetStackLimits(&LowLimit, &HighLimit);
InitialStack = IoGetInitialStack();
// all worker thread start at KiStartSystemThread and return address == 0
// if null != last return address code is in noimage
if (NULL != Callers[Count - 1].Establisher) {
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > found noimage return address in worker thread\n",
Callers[Count - 1].Establisher);
#endif // !PUBLIC
for (TargetPc = (PULONG64)Callers[Count - 1].EstablisherFrame;
(ULONG64)TargetPc < (ULONG64)InitialStack;
TargetPc++) {
// In most cases, PatchGuard code will wait for a random time.
// set return address in current thread stack to _RevertWorkerToSelf
// than PatchGuard code was not continue
if ((ULONG64)*TargetPc == (ULONG64)Callers[Count - 1].Establisher) {
// restart ExpWorkerThread
// ExFrame->P1Home = WorkerContext;
// ExFrame->P2Home = ExpWorkerThread;
// ExFrame->P3Home = PspSystemThreadStartup;
// ExFrame->Return = KiStartSystemThread; <- jmp this function return address == 0
SetCounterBody(
&TempObject.Establisher,
Callers[Count - 1].Establisher);
TempObject.Type = -1;
PgLocateObject(PgBlock, &TempObject);
if (-1 != TempObject.Type) {
Object = PgCreateObject(
PgDeclassified,
TempObject.Type,
TempObject.BaseAddress,
TempObject.RegionSize,
NULL,
PgBlock,
PgBlock->ClearCallback,
Callers[Count - 1].Establisher,
GetGpBlock(PgBlock)->CaptureContext);
if (NULL != Object) {
SetCounterBody(
&Object->Establisher,
Callers[Count - 1].Establisher);
*TargetPc = (ULONG64)&Object->Establisher;
InterlockedIncrementSizeT(&PgBlock->ReferenceCount);
#ifndef PUBLIC
DbgPrint(
"[Sefirot] [PatchGuard] < %p > insert worker thread check code\n",
PgBlock->ReferenceCount);
#endif // !PUBLIC
}
}
break;
}
}
}
}
ExFreePool(Callers);
}
}
最近微软更新了 1903 忙着更新了一下代码, 顺便把文章补全, 主要是解释一下如何检测的.
当 PatchGuad 处于执行状态时, 首先解密头部的CmpAppendDllSection, 然后在
CmpAppendDllSection内部完整解密整个Context, 进入PatchGuardEntryPointer, 替换IDT, 关闭DR中断, 自检, 插入WORKER(自捡成功的话), 清空栈, 进入FsRtlUninitializeSmallMcb, 这里FsRtlUninitializeSmallMcb 就是
PatchGuad
的执行主逻辑, 在这个逻辑中大部分时间
PatchGuad 都是处于延时状态以减少CPU 占用.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-6-1 15:15
被blindtiger编辑
,原因: