此代码测试环境win10 1909物理机上被动打开10个进程,HOOK Nt!NtOpenPorcess 60个小时未触发PG为前提写成,因为我未触发PG,样本测试过少,所以只能以我的实验确认未触发PG,不代表100%过了PG,仅仅做为方向向大家提供,可以分为被动和主动,主动需要另外的细节处理,这个是被动HOOK。仅以此提供方向,希望大家都能干掉PG,测试过程中如果出现1A或者7E的异常,请自行修改,这是1903和1909特有的检测产生,我目前暂未出现此种异常。
#include <ntddk.h>
#define KERNEL_CR3_OFFSET 0x28
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define SYSTEMID 4
enum
{
AllocPTE,
AllocPTESHADOW,
AllocPDE,
AllocPDESHADOW,
AllocPPE,
AllocPPESHADOW,
AllocPXE,
AllocPXESHADOW,
AllocCR3,
};
typedef struct _KLDR_DATA_TABLE_ENTRY
{
struct _LIST_ENTRY InLoadOrderLinks; //0x0
VOID* ExceptionTable; //0x10
ULONG ExceptionTableSize; //0x18
VOID* GpValue; //0x20
struct _NON_PAGED_DEBUG_INFO* NonPagedDebugInfo; //0x28
VOID* DllBase; //0x30
VOID* EntryPoint; //0x38
ULONG SizeOfImage; //0x40
struct _UNICODE_STRING FullDllName; //0x48
struct _UNICODE_STRING BaseDllName; //0x58
ULONG Flags; //0x68
USHORT LoadCount; //0x6c
union
{
USHORT SignatureLevel : 4; //0x6e
USHORT SignatureType : 3; //0x6e
USHORT Unused : 9; //0x6e
USHORT EntireField; //0x6e
} u1; //0x6e
VOID* SectionPointer; //0x70
ULONG CheckSum; //0x78
ULONG CoverageSectionSize; //0x7c
VOID* CoverageSection; //0x80
VOID* LoadedImports; //0x88
VOID* Spare; //0x90
ULONG SizeOfImageNotRounded; //0x98
ULONG TimeDateStamp; //0x9c
}KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
NTSTATUS RtlMappingAddress(ULONG64 VirtualAddress, ULONG64 pid);
PVOID MiGetXXXAddress(ULONG64 VirtualAddress, PVOID PteBase);
void MySleep(long mesc);
PVOID pPageArray[9];
PVOID PteBase;
ULONG64 PxeShadowPhy;
ULONG PXEIndex;
ULONG FuncOffset;
ULONG64 PxePhyAddr;
VOID ProcessNotifyRoutine(
_In_ HANDLE ParentId,
_In_ HANDLE ProcessId,
_In_ BOOLEAN Create
);
EXTERN_C NTSTATUS PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS *Process
);
EXTERN_C NTSTATUS PsSuspendProcess(PEPROCESS Process);
EXTERN_C NTSTATUS PsResumeProcess(PEPROCESS Process);
EXTERN_C PUCHAR PsGetProcessImageFileName(
PEPROCESS Process
);
PVOID FindBase();
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
KdPrint(("退出驱动\n"));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
NTSTATUS status = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
RtlMappingAddress(NtOpenProcess, SYSTEMID);
PKLDR_DATA_TABLE_ENTRY pKldr = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
pKldr->Flags |= 0x20;
status = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, FALSE);
if (!NT_SUCCESS(status))
{
KdPrint(("创建回调失败\n"));
return status;
}
return status;
}
PVOID MiGetXXXAddress(ULONG64 VirtualAddress, PVOID PteBase)
{
return ((VirtualAddress >> 9) & 0x7FFFFFFFF8) + (ULONG64)PteBase;
}
PVOID FindBase()
{
PUCHAR BaseAddr = MmGetVirtualForPhysical;
return *(PUINT64)(BaseAddr + 0x22);
}
NTSTATUS RtlMappingAddress(ULONG64 VirtualAddress, ULONG64 pid)
{
NTSTATUS status = STATUS_SUCCESS;
PEPROCESS Process;
status = PsLookupProcessByProcessId(pid, &Process);
if (!NT_SUCCESS(status))
{
KdPrint(("Don't Find Process.\n"));
return status;
}
PVOID pDirectoryTableBase = (ULONG64)Process + KERNEL_CR3_OFFSET;
PXEIndex = (VirtualAddress >> 0x27) & 0x1FF;
ULONG PPEIndex = (VirtualAddress >> 0x1E) & 0x1FF;
ULONG PDEIndex = (VirtualAddress >> 0x15) & 0x1FF;
ULONG PTEIndex = (VirtualAddress >> 0xC) & 0x1FF;
FuncOffset = VirtualAddress & 0xFFF;
PteBase = FindBase();
PULONG64 Pte = (PULONG64)MiGetXXXAddress(VirtualAddress, PteBase);
PULONG64 Pde = (PULONG64)MiGetXXXAddress(Pte, PteBase);
PULONG64 Ppe = (PULONG64)MiGetXXXAddress(Pde, PteBase);
PULONG64 Pxe = (PULONG64)MiGetXXXAddress(Ppe, PteBase);
ULONG64 PtePhyAddr = *Pte;
ULONG64 PdePhyAddr = *Pde;
ULONG64 PpePhyAddr = *Ppe;
PxePhyAddr = *Pxe;
ULONG64 Cr3PhyAddr = (*(PULONG64)pDirectoryTableBase) & (~0xFFF) | 0x063;
PHYSICAL_ADDRESS Low = { 0 };
PHYSICAL_ADDRESS High = { MAXULONG64 };
for (int i = 0; i < 9; i++)
{
pPageArray[i] = MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached);
if (!pPageArray[i])
{
KdPrint(("Alloc Memory Fail\n"));
return STATUS_NO_MEMORY;
}
RtlZeroMemory(pPageArray[i], PAGE_SIZE);
}
PVOID AllocPteAddress = MiGetXXXAddress(pPageArray[AllocPTE], PteBase);
ULONG64 OldAllocPTE = *(PULONG64)AllocPteAddress;
*(PULONG64)AllocPteAddress = PtePhyAddr;
RtlCopyMemory(pPageArray[AllocPTESHADOW], pPageArray[AllocPTE], PAGE_SIZE);
ULONG64 PteShadowPhy = *(PULONG64)(MiGetXXXAddress(pPageArray[AllocPTESHADOW], PteBase));
*(PULONG64)AllocPteAddress = OldAllocPTE;
PVOID AllocPdeAddress = MiGetXXXAddress(pPageArray[AllocPDE], PteBase);
ULONG64 OldAllocPde = *(PULONG64)AllocPdeAddress;
*(PULONG64)AllocPdeAddress = PdePhyAddr;
RtlCopyMemory(pPageArray[AllocPDESHADOW], pPageArray[AllocPDE], PAGE_SIZE);
ULONG64 PdeShadowPhy = *(PULONG64)(MiGetXXXAddress(pPageArray[AllocPDESHADOW], PteBase));
*(PULONG64)AllocPdeAddress = OldAllocPde;
PVOID AllocPpeAddress = MiGetXXXAddress(pPageArray[AllocPPE], PteBase);
ULONG64 OldAllocPpe = *(PULONG64)AllocPpeAddress;
*(PULONG64)AllocPpeAddress = PpePhyAddr;
RtlCopyMemory(pPageArray[AllocPPESHADOW], pPageArray[AllocPPE], PAGE_SIZE);
ULONG64 PpeShadowPhy = *(PULONG64)(MiGetXXXAddress(pPageArray[AllocPPESHADOW], PteBase));
*(PULONG64)AllocPpeAddress = OldAllocPpe;
PVOID AllocPxeAddress = MiGetXXXAddress(pPageArray[AllocPXE], PteBase);
ULONG64 OldAllocPxe = *(PULONG64)AllocPxeAddress;
*(PULONG64)AllocPxeAddress = PxePhyAddr;
RtlCopyMemory(pPageArray[AllocPXESHADOW], pPageArray[AllocPXE], PAGE_SIZE);
PxeShadowPhy = *(PULONG64)(MiGetXXXAddress(pPageArray[AllocPXESHADOW], PteBase));
*(PULONG64)AllocPxeAddress = OldAllocPxe;
//这里和下面注
/*PVOID AllocCR3Address = MiGetXXXAddress(pPageArray[AllocCR3], PteBase);
ULONG64 OldAllocCR3 = *(PULONG64)AllocCR3Address;
*(PULONG64)AllocCR3Address = Cr3PhyAddr;*/
*(PULONG)((ULONG64)pPageArray[AllocPDESHADOW] + PTEIndex * 8) = (PteShadowPhy & 0xFFFFFFFFF000) | (PtePhyAddr & ~(0xFFFFFFFFF000));
*(PULONG)((ULONG64)pPageArray[AllocPPESHADOW] + PDEIndex * 8) = (PdeShadowPhy & 0xFFFFFFFFF000) | (PdePhyAddr & ~(0xFFFFFFFFF000));
*(PULONG)((ULONG64)pPageArray[AllocPXESHADOW] + PPEIndex * 8) = (PpeShadowPhy & 0xFFFFFFFFF000) | (PpePhyAddr & ~(0xFFFFFFFFF000));
////关键一换
//PsSuspendProcess(Process);
//MySleep(100);
//*(PULONG)((ULONG64)pPageArray[AllocCR3] + PXEIndex * 8) = (PxeShadowPhy & 0xFFFFFFFFF000) | (PxePhyAddr & ~(0xFFFFFFFFF000));
//PsResumeProcess(Process);
ObDereferenceObject(Process);
//修改NTOPENPROCESS的值
/**(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x27) = 0x90;
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x28) = 0x90;
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x29) = 0x90;
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x2A) = 0xc3;
*(PULONG64)AllocCR3Address = OldAllocCR3;*/
return status;
}
void MySleep(long mesc)
{
LARGE_INTEGER my_interval;
my_interval.QuadPart = DELAY_ONE_MILLISECOND;
my_interval.QuadPart *= mesc;
KeDelayExecutionThread(KernelMode, 0, &my_interval);
}
VOID ProcessNotifyRoutine(
_In_ HANDLE ParentId,
_In_ HANDLE ProcessId,
_In_ BOOLEAN Create
)
{
//挂10个winobj.exe来测试pg
if (Create)
{
NTSTATUS status = STATUS_SUCCESS;
PEPROCESS Process;
status = PsLookupProcessByProcessId(ProcessId, &Process);
PUCHAR pFileName = PsGetProcessImageFileName(Process);
char buf[] = "Winobj.exe";
if (strcmp(pFileName, buf) == 0)
{
PVOID pDirectoryTableBase = (ULONG64)Process + KERNEL_CR3_OFFSET;
PVOID AllocCR3Address = MiGetXXXAddress(pPageArray[AllocCR3], PteBase);
ULONG64 OldAllocCR3 = *(PULONG64)AllocCR3Address;
ULONG64 Cr3PhyAddr = (*(PULONG64)pDirectoryTableBase) & (~0xFFF) | 0x063;
*(PULONG64)AllocCR3Address = Cr3PhyAddr;
*(PULONG)((ULONG64)pPageArray[AllocCR3] + PXEIndex * 8) = (PxeShadowPhy & 0xFFFFFFFFF000) | (PxePhyAddr & ~(0xFFFFFFFFF000));
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x27) = 0x90;
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x28) = 0x90;
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x29) = 0x90;
*(PCHAR)((ULONG64)pPageArray[AllocPTESHADOW] + FuncOffset + 0x2A) = 0xc3;
*(PULONG64)AllocCR3Address = OldAllocCR3;
KdPrint(("HOOK Finish\n"));
}
ObDereferenceObject(Process);
}
}
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界