#include <ntifs.h>
#include <ntddk.h>
#include <intrin.h>
#include "ptehook.h"
#define CR0_WP (1 << 16)
#define DRIVER_TAG 'HKOB'
#define MAX_G_BIT_RECORDS 128
#define MAX_HOOK_COUNT 64
#define PAGE_ALIGN(va) ((PVOID)((ULONG_PTR)(va) & ~0xFFF))
#define PTE_NX_BIT (1ULL << 63)
// 调试打印宏
#define LOG_ERROR(fmt, ...) \
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] ERROR: " fmt "\n", ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) \
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] INFO: " fmt "\n", ##__VA_ARGS__)
#define LOG_TRACE(fmt, ...) \
DbgPrintEx(DPFLTR极IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "[PTE_HOOK] TRACE: " fmt "\n", ##__VA_ARGS__)
// 修正的跳板指令结构
#pragma pack(push, 1)
typedef struct _JMP_ABS {
UINT8 opcode[6]; // FF 25 00 00 00 00 = jmp [rip+0]
ULONG64 address; // 目标地址 (紧跟在指令后)
} JMP_ABS, * PJMP_ABS;
#pragma pack(pop)
static_assert(sizeof(JMP_ABS) == 14, "JMP_ABS size must be 14 bytes");
// 声明PsGetProcessImageFileName
extern "C" NTSYSAPI CHAR* NTAPI PsGetProcessImageFileName(PEPROCESS Process);
// 页表结构定义
typedef struct _PAGE_TABLE {
UINT64 LineAddress;
union {
struct {
UINT64 present : 1;
UINT64 write : 1;
UINT64 user : 1;
UINT64 write_through : 1;
UINT64 cache_disable : 1;
UINT64 accessed : 1;
UINT64 dirty : 1;
UINT64 pat : 1;
UINT64 global : 1;
UINT64 ignored_1 : 3;
UINT64 page_frame_number : 36;
UINT64 reserved_1 : 极;
UINT64 ignored_2 : 7;
UINT64 protection_key : 4;
UINT64 execute_disable : 1;
} flags;
UINT64 value;
}*PteAddress;
union {
struct {
UINT64 present : 1;
UINT64 write : 1;
UINT64 user : 1;
UINT64 write_through : 1;
UINT64 cache_disable : 1;
UINT64 accessed : 1;
UINT64 dirty : 1;
UINT64 large_page : 1;
UINT64 global : 1;
UINT64 ignored_2 : 3;
UINT64 page_frame_number : 36;
UINT64 reserved_1 : 4;
UINT64 ignored_3 : 7;
UINT64 protection_key : 4;
UINT64 execute_disable : 1;
} flags;
UINT64 value;
}*PdeAddress;
union {
struct {
UINT64 present : 1;
UINT64 write : 1;
UINT64 user : 1;
UINT64 write_through : 1;
UINT64 cache_disable : 1;
UINT64 accessed : 1;
UINT64 ignored_1 : 1;
UINT64 page_size : 1;
UINT64 ignored_2 : 4;
UINT64 page_frame_number : 36;
UINT64 reserved_1 : 4;
UINT64 ignored_3 : 7;
UINT64 protection_key : 4;
UINT64 execute_disable : 1;
} flags;
UINT64 value;
}*PdpteAddress;
UINT64* Pml4Address;
BOOLEAN IsLargePage;
BOOLEAN Is1GBPage;
UINT64 OriginalPte;
UINT64 OriginalPde;
UINT64 OriginalPdpte;
UINT64 OriginalPml4e;
HANDLE ProcessId;
} PAGE_TABLE, * PPAGE_TABLE;
// G位信息记录结构体
typedef struct _G_BIT_INFO {
void* AlignAddress;
union {
struct {
UINT64 present : 1;
UINT64 write : 1;
UINT64 user : 1;
UINT64 write_through : 1;
UINT64 cache_disable : 1;
UINT64 accessed : 1;
UINT64 dirty : 1;
UINT64 large_page : 1;
UINT64 global : 1;
UINT64 ignored_2 : 3;
UINT64 page_frame_number : 36;
UINT64 reserved_1 : 4;
UINT64 ignored_3 : 7;
UINT64 protection_key : 4;
UINT64 execute_disable : 1;
} flags;
UINT64 value;
}*PdeAddress;
union {
struct {
UINT64 present : 1;
UINT64 write : 1;
UINT64 user : 1;
UINT64 write_through : 1;
UINT64 cache_disable : 1;
UINT64 accessed : 1;
UINT64 dirty : 1;
UINT64 pat : 1;
UINT64 global : 1;
UINT64 ignored_1 : 3;
UINT64 page_frame_number : 36;
UINT64 reserved_1 : 4;
UINT64 ignored_2 : 7;
UINT64 protection_key : 4;
UINT64 execute_disable : 1;
} flags;
UINT64 value;
}*PteAddress;
BOOLEAN IsLargePage;
} G_BIT_INFO, * PG_BIT_INFO;
typedef struct _HOOK_INFO {
void* OriginalAddress;
void* HookAddress;
UINT8 OriginalBytes[20];
UINT8 HookBytes[20];
UINT32 HookLength;
BOOLEAN IsHooked;
HANDLE ProcessId;
UINT64 OriginalPteValue;
UINT64 HookedPteValue;
} HOOK_INFO;
class PteHookManager {
public:
bool fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr);
bool fn_remove_hook(HANDLE process_id, void* hook_addr);
static PteHookManager* GetInstance();
HOOK_INFO* GetHookInfo() { return m_HookInfo; }
char* GetTrampLinePool() { return m_TrampLinePool; }
UINT32 GetHookCount() { return m_HookCount; }
bool fn_resume_global_bits(void* align_addr);
~PteHookManager();
private:
bool WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd);
bool SetPageExecution(void* address, bool executable);
void fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address);
bool fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde);
bool fn_isolation_pages(HANDLE process_id, void* ori_addr);
bool fn_split_large_pages(void* in_pde, void* out_pde);
NTSTATUS get_page_table(UINT64 cr3, PAGE_TABLE& table);
void* fn_pa_to_va(UINT64 pa);
UINT64 fn_va_to_pa(void* va);
__forceinline KIRQL DisableWriteProtection();
__forceinline void EnableWriteProtection(KIRQL oldIrql);
void FlushCacheAndTlb(void* address);
G_BIT_INFO m_GbitRecords[MAX_G_BIT_RECORDS];
UINT32 m_GbitCount = 0;
void* m_PteBase = 0;
HOOK_INFO m_HookInfo[MAX_HOOK_COUNT] = { 0 };
UINT32 m_HookCount = 0;
char* m_TrampLinePool = nullptr;
UINT32 m_PoolUsed = 0;
static PteHookManager* m_Instance;
};
PteHookManager* PteHookManager::m_Instance = nullptr;
// 实现部分
__forceinline KIRQL P极HookManager::DisableWriteProtection() {
KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
__writecr0(cr0 & ~CR0_WP); // 清除CR0.WP位
_mm_mfence();
return oldIrql;
}
__forceinline void PteHookManager::EnableWriteProtection(KIRQL oldIrql) {
_mm_mfence();
UINT64 cr0 = __readcr0();
__writecr0(cr0 | CR0_WP); // 设置CR0.WP位
KeLowerIrql(oldIrql);
}
void* PteHookManager::fn_pa_to_va(UINT64 pa) {
PHYSICAL_ADDRESS physAddr;
physAddr.QuadPart = pa;
return MmGetVirtualForPhysical(physAddr);
}
UINT64 PteHookManager::fn_va_to_pa(void* va) {
PHYSICAL_ADDRESS physAddr = MmGetPhysicalAddress(va);
return physAddr.QuadPart;
}
NTSTATUS PteHookManager::get_page_table(UINT64 cr3_val, PAGE_TABLE& table) {
UINT64 va = table.LineAddress;
UINT64 pml4e_index = (va >> 39) & 0x1FF;
UINT64 pdpte_index = (va >> 30) & 0x1FF;
UINT64 pde_index = (va >> 21) & 0x1FF;
UINT64 pte_index = (va >> 12) & 0x1FF;
// PML4
UINT64 pml4_pa = cr3_val & ~0xFFF;
UINT64* pml4_va = (UINT64*)fn_pa_to_va(pml4_pa);
if (!pml4_va) return STATUS_INVALID_ADDRESS;
table.Pml4Address = &pml4_va[pml4e_index];
table.OriginalPml4e = *table.Pml4Address;
if (!(table.OriginalPml4e & 1)) return STATUS_ACCESS_VIOLATION;
// PDPTE
UINT64 pdpte_pa = table.OriginalPml4e & ~0xFFF;
UINT64* pdpte_va = (UINT64*)fn_pa_to_va(pdpte_pa);
if (!pdpte_va) return STATUS_INVALID_ADDRESS;
table.PdpteAddress = (decltype(table.PdpteAddress))&pdpte_va[pdpte_index];
table.OriginalPdpte = table.PdpteAddress->value;
table.Is1GBPage = (table.PdpteAddress->flags.page_size) ? TRUE : FALSE;
if (!(table.OriginalPdpte & 1)) return STATUS_ACCESS_VIOLATION;
if (table.Is1GBPage) return STATUS_SUCCESS;
// PDE
UINT64 pde_pa = table.OriginalPdpte & ~0xFFF;
UINT64* pde_va = (UINT64*)fn_pa_to_va(pde_pa);
if (!pde_va) return STATUS_INVALID_ADDRESS;
table.PdeAddress = (decltype(table.PdeAddress))&pde_va[pde_index];
table.OriginalPde = table.PdeAddress->value;
table.IsLargePage = (table.PdeAddress->flags.large_page) ? TRUE : FALSE;
if (!(table.OriginalPde & 1)) return STATUS_ACCESS_VIOLATION;
if (table.IsLargePage) return STATUS_SUCCESS;
// PTE
UINT64 pte_pa = table.OriginalPde & ~0xFFF;
UINT64* pte_va = (UINT64*)fn_pa_to_va(pte_pa);
if (!pte_va) return STATUS_INVALID_ADDRESS;
table.PteAddress = (decltype(table.PteAddress))&pte_va[pte_index];
table.OriginalPte = table.PteAddress->value;
if (!(table.OriginalPte & 1)) return STATUS_ACCESS_VIOLATION;
LOG_TRACE("Page Table Info: VA=0x%p, PTE=0x%llX", (void*)table.LineAddress, table.OriginalPte);
return STATUS_SUCCESS;
}
bool PteHookManager::fn_split_large_pages(void* in_pde_ptr, void* out_pde_ptr) {
auto in_pde = (decltype(PAGE_TABLE::PdeAddress))in_pde_ptr;
auto out_pde = (decltype(PAGE_TABLE::PdeAddress))out_pde_ptr;
LOG_INFO("Splitting large page: Input PDE=0x%llx", in_pde->value);
PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 };
HighAddr.QuadPart = MAXULONG64;
auto pt = (decltype(PAGE_TABLE::PteAddress))MmAllocateContiguousMemorySpecifyCache(
PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached);
if (!pt) {
LOG_ERROR("Failed to allocate contiguous memory for page splitting");
return false;
}
UINT64 start_pfn = in_pde->flags.page_frame_number;
for (int i = 0; i < 512; i++) {
pt[i].value = 0;
pt[i].flags.present = 1;
pt[i].flags.write = in_pde->flags.write;
pt[i].flags.user = in_pde->flags.user;
pt[i].flags.write_through = in_pde->flags.write_through;
pt[i].flags.cache_disable = in_pde->flags.cache_disable;
pt[i].flags.accessed = in_pde->flags.accessed;
pt[i].flags.dirty = in_pde->flags.dirty;
pt[i].flags.global = 0;
pt[i].flags.page_frame_number = start_pfn + i;
}
out_pde->value = in_pde->value;
out_pde->flags.large_page = 0;
out_pde->flags.page_frame_number = fn_va_to_pa(pt) >> 12;
LOG_INFO("Large page split complete: New PTE table at PA=0x%llx", fn_va_to_pa(pt));
return true;
}
bool PteHookManager::SetPageExecution(void* address, bool executable) {
// 使用页表遍历函数修改NX位
PAGE_TABLE table = { 0 };
table.LineAddress = (UINT64)address;
NTSTATUS status = get_page_table(__readcr3(), table);
if (!NT_SUCCESS(status)) {
LOG_ERROR("Failed to get page table for address 0x%p", address);
return false;
}
KIRQL oldIrql = DisableWriteProtection();
UINT64 oldPte = table.PteAddress->value;
UINT64 newPte = oldPte;
// 设置或清除NX位
if (executable) {
newPte &= ~PTE_NX_BIT;
}
else {
newPte |= PTE_NX_BIT;
}
table.PteAddress->value = newPte;
// 刷新TLB
__invlpg(address);
_mm_mfence();
EnableWriteProtection(oldIrql);
LOG_TRACE("PTE modified for 0x%p: Old=0x%llX, New=0x%llX", address, oldPte, newPte);
return true;
}
bool PteHookManager::fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde_ptr) {
PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 };
HighAddr.QuadPart = MAXULONG64;
LOG_INFO("Isolating page table: CR3=0x%llx, Address=0x%p", cr3_val, replace_align_addr);
auto Va4kb = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached);
auto VaPt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, Low极, MmNonCached);
auto VaPdt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached);
auto VaPdpt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached);
if (!VaPt || !Va4kb || !VaPdt || !VaPdpt) {
if (VaPt) MmFreeContiguousMemory(VaPt);
if (Va4kb) MmFreeContiguousMemory(Va4kb);
if (VaPdt) MmFreeContiguousMemory(VaPdt);
if (VaPdpt) MmFreeContiguousMemory(VaPd极);
LOG_ERROR("Failed to allocate contiguous memory for isolation");
return false;
}
PAGE_TABLE Table = { 0 };
Table.LineAddress = (UINT64)replace_align_addr;
NTSTATUS status = get_page_table(cr3_val, Table);
if (!NT_SUCCESS(status)) {
MmFreeContiguousMemory(VaPt);
MmFreeContiguousMemory(Va4kb);
MmFreeContiguousMemory(VaPdt);
MmFreeContiguousMemory(VaPdpt);
LOG_ERROR("get_page_table failed with status 0x%X", status);
return false;
}
UINT64 pte_index = (Table.LineAddress >> 12) & 0x1FF;
UINT64 pde_index = (Table.LineAddress >> 21) & 0x1FF;
UINT64 pdpte_index = (Table.LineAddress >> 30) & 0x1FF;
UINT64 pml4e_index = (Table.LineAddress >> 39) & 0x1FF;
memcpy(Va4kb, replace_align_addr, PAGE_SIZE);
if (Table.IsLargePage && split_pde_ptr) {
auto split_pde = (decltype(PAGE_TABLE::PdeAddress))split_pde_ptr;
memcpy(VaPt, (void*)(split_pde->flags.page_frame_number << 12), PAGE_SIZE);
}
else {
memcpy(VaPt, (void*)(Table.PdeAddress->flags.page_frame_number << 12), PAGE_SIZE);
}
memcpy(VaPdt, (void*)(Table.PdpteAddress->flags.page_frame_number << 12), PAGE_SIZE);
memcpy(VaPdpt, (void*)(Table.Pml4Address[pml4e_index] & ~0xFFF), PAGE_SIZE);
auto new_pte = (decltype(PAGE_TABLE::PteAddress))VaPt;
new_pte[pte_index].flags.page_frame_number = fn_va_to_pa(Va4kb) >> 12;
auto new_pde = (decltype(PAGE_TABLE::PdeAddress))VaPdt;
new_pde[pde_index].value = Table.OriginalPde;
new_pde[pde_index].flags.large_page = 0;
new_pde[pde_index].flags.page_frame_number = fn_va_to_pa(VaPt) >> 12;
auto new_pdpte = (decltype(PAGE_TABLE::PdpteAddress))VaPdpt;
new_pdpte[pdpte_index].flags.page_frame_number = fn_va_to_pa(VaPdt) >> 12;
auto new_pml4 = (UINT64*)fn_pa_to_va(cr3_val & ~0xFFF);
new_pml4[pml4e_index] = (new_pml4[pml4e_index] & 0xFFF) | (fn_va_to_pa(VaPdpt) & ~0xFFF);
__invlpg(replace_align_addr);
LOG_INFO("Page table isolation complete: New PFN=0x%llx", fn_va_to_pa(Va4kb) >> 12);
return true;
}
bool PteHookManager::fn_isolation_pages(HANDLE process_id, void* ori_addr) {
PEPROCESS Process;
if (!NT_SUCCESS(PsLookupProcessByProcessId(process_id, &Process))) {
LOG_ERROR("PsLookupProcessByProcessId failed");
return false;
}
LOG_INFO("Isolating pages: PID=%d, Address=0x%p", HandleToUlong(process_id), ori_addr);
KAPC_STATE ApcState;
KeStackAttachProcess(Process, &ApcState);
void* AlignAddr = PAGE_ALIGN(ori_addr);
PAGE_TABLE Table = { 0 };
Table.LineAddress = (UINT64)AlignAddr;
UINT64 target_cr3 = *(UINT64*)((UCHAR*)Process + 0x28);
if (!NT_SUCCESS(get_page_table(target_cr3, Table))) {
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
LOG_ERROR("get_page_table failed");
return false;
}
bool success = false;
decltype(PAGE_TABLE::PdeAddress) split_pde = nullptr;
if (Table.IsLargePage) {
split_pde = (decltype(PAGE_TABLE::PdeAddress))ExAllocatePoolWithTag(NonPagedPool, sizeof(*split_pde), 'pdeS');
if (!split_pde || !fn_split_large_pages(Table.PdeAddress, split_pde)) {
if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS');
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
LOG_ERROR("Splitting large page failed");
return false;
}
if (Table.PdeAddress->flags.global) {
Table.PdeAddress->flags.global = 0;
fn_add_g_bit_info(AlignAddr, Table.PdeAddress, nullptr);
LOG_INFO("Cleared G-bit for large page PDE: 0x%llx", Table.PdeAddress->value);
}
}
else if (Table.PteAddress && Table.PteAddress->flags.global) {
Table.PteAddress->flags.global = 0;
fn_add_g_bit_info(AlignAddr, nullptr, Table.PteAddress);
LOG_INFO("Cleared G-bit for PTE: 0x%llx", Table.PteAddress->value);
}
success = fn_isolation_pagetable(__readcr3(), AlignAddr, split_pde);
if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS');
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject(Process);
if (success) {
LOG_INFO("Page isolation successful");
}
else {
LOG_ERROR("Page isolation failed");
}
return success;
}
bool PteHookManager::WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd) {
// 确保8字节对齐
if (reinterpret_cast<ULONG_PTR>(trampoline) & 0x7) {
LOG_ERROR("Trampoline address not aligned: 0x%p", trampoline);
return false;
}
// 禁用写保护
KIRQL oldIrql = DisableWriteProtection();
// 直接写入内存
RtlCopyMemory(trampoline, &jmpCmd, sizeof(JMP_ABS));
// 刷新缓存
__invlpg(trampoline);
_mm_mfence();
// 恢复写保护
EnableWriteProtection(oldIrql);
LOG_TRACE("Trampoline instruction written at 0x%p", trampoline);
return true;
}
void PteHookManager::fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address) {
if (m_GbitCount >= MAX_G_BIT_RECORDS) {
LOG_ERROR("Max G-bit records reached");
return;
}
PG_BIT_INFO record = &m_GbitRecords[m_GbitCount++];
record->AlignAddress = align_addr;
record->PdeAddress = (decltype(G_BIT_INFO::PdeAddress))pde_address;
record->PteAddress = (decltype(G_BIT_INFO::PteAddress))pte_address;
record->IsLargePage = (pde_address != nullptr);
LOG_TRACE("Added G-bit record: Address=0x%p, PDE=0x%p, PTE=0x%p",
align_addr, pde_address, pte_address);
}
bool PteHookManager::fn_resume_global_bits(void* align_addr) {
KIRQL oldIrql = DisableWriteProtection();
bool found = false;
LOG_INFO("Restoring G-bits for address: 0x%p", align_addr);
for (UINT32 i = 0; i < m_GbitCount; i++) {
PG_BIT_INFO record = &m_GbitRecords[i];
if (align_addr && record->AlignAddress != align_addr) continue;
if (record->PteAddress) {
record->PteAddress->flags.global = 1;
__invlpg(record->AlignAddress);
LOG_TRACE("Restored G-bit for PTE: 0x%p", record->AlignAddress);
}
if (record->PdeAddress) {
record->PdeAddress->flags.global = 1;
if (record->IsLargePage) {
__invlpg(record->AlignAddress);
}
LOG_TRACE("Restored G-bit for PDE: 0x%p", record->AlignAddress);
}
found = true;
if (align_addr) break;
}
EnableWriteProtection(oldIrql);
if (found) {
LOG_INFO("G-bits restoration complete");
}
else {
LOG_ERROR("No matching G-bit record found");
}
return found;
}
bool PteHookManager::fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr) {
if (!ori_addr || !hk_addr || !*ori_addr) {
LOG_ERROR("Invalid parameters: ori_addr=%p, hk_addr=%p", ori_addr, hk_addr);
return false;
}
// 分配跳板池(如果尚未分配)
if (!m_TrampLinePool) {
PHYSICAL_ADDRESS LowAddr;
LowAddr.QuadPart = 0x100000;
PHYSICAL_ADDRESS HighAddr;
HighAddr.QuadPart = ~0ull;
m_TrampLinePool = (char*)MmAllocateContiguousMemorySpecifyCache(
PAGE_SIZE * 8, LowAddr, HighAddr, LowAddr, MmNonCached);
if (!m_TrampLinePool) {
LOG_ERROR("Failed to allocate trampoline pool");
return false;
}
// 设置跳板池可执行
if (!SetPageExecution(m_TrampLinePool, true)) {
MmFreeContiguousMemory(m_TrampLinePool);
m_TrampLinePool = nullptr;
LOG_ERROR("Failed to set trampoline pool executable");
return false;
}
LOG_INFO("Trampoline pool allocated: Address=0x%p, Size=%d bytes",
m_TrampLinePool, PAGE_SIZE * 8);
}
// 计算跳板位置(16字节对齐确保RIP相对寻址)
void* trampoline = (void*)((ULONG_PTR)(m_TrampLinePool + m_PoolUsed + 15) & ~15);
SIZE_T requiredSize = ((char*)trampoline - m_TrampLinePool) + sizeof(JMP_ABS);
// 检查跳板池空间
if (requiredSize > PAGE_SIZE * 8) {
LOG_ERROR("Trampoline pool out of space: Used=%d, Required=%d", m_PoolUsed, requiredSize);
return false;
}
// 构造跳转指令
JMP_ABS jmpCmd;
memcpy(jmpCmd.opcode, "\xFF\x25\x00\x00\x00\x00", 6); // jmp [rip+0]
jmpCmd.address = reinterpret_cast<ULONG64>(hk_addr);
LOG_INFO("Constructing jump instruction: Target=0x%p, Trampoline=0x%p", hk_addr, trampoline);
// 写入跳板指令
if (!WriteTrampolineInstruction(trampoline, jmpCmd)) {
return false;
}
// 设置目标函数不可执行(触发页错误)
if (!SetPageExecution(*ori_addr, false)) {
LOG_ERROR("Failed to set target function non-executable");
return false;
}
// 记录Hook信息
bool hookRecorded = false;
for (UINT32 i = 0; i < MAX_HOOK_COUNT; i++) {
if (!m_HookInfo[i].IsHooked) {
m_HookInfo[i].OriginalAddress = *ori_addr;
m_HookInfo[i].HookAddress = trampoline;
m_HookInfo[i].ProcessId = process_id;
m_HookInfo极i].IsHooked = TRUE;
m_HookInfo[i].HookLength = sizeof(JMP_ABS);
RtlCopyMemory(m_HookInfo[i].HookBytes, &jmpCmd, sizeof(jmpCmd));
// 保存原始PTE值
PAGE_TABLE table = { 0 };
table.LineAddress = (UINT64)*ori_addr;
if (NT_SUCCESS(get_page_table(__readcr3(), table))) {
m_HookInfo[i].OriginalPteValue = table.OriginalPte;
}
m_HookCount++;
hookRecorded = true;
LOG_INFO("Hook recorded #%d: Original=0x%p, Trampoline=0x%p", i, *ori_addr, trampoline);
break;
}
}
if (!hookRecorded) {
LOG_ERROR("Exceeded max hook count (%d)", MAX_HOOK_COUNT);
return false;
}
// 更新原始地址为跳板地址
*ori_addr = trampoline;
m_PoolUsed = (UINT32)requiredSize;
LOG_INFO("Hook installed successfully: Trampoline=0x%p -> Hook=0x%p", trampoline, hk_addr);
return true;
}
bool PteHookManager::fn_remove_hook(HANDLE process_id, void* hook_addr) {
LOG_INFO("Removing hook: HookAddr=0x%p", hook_addr);
for (UINT32 i = 0; i < m_HookCount; i++) {
if (m_HookInfo[i].HookAddress == hook_addr && m_HookInfo[i].IsHooked) {
LOG_INFO("Found matching hook: OriginalAddr=0x%p", m_HookInfo[i].OriginalAddress);
// 恢复目标函数执行权限
SetPageExecution(m_HookInfo[i].OriginalAddress, true);
// 恢复原始PTE值
if (m_HookInfo[i].OriginalPteValue) {
PAGE_TABLE table = { 0 };
table.LineAddress = (UINT64)m_HookInfo[i].OriginalAddress;
if (NT_SUCCESS(get_page_table(__readcr3(), table))) {
KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
table.PteAddress->value = m_HookInfo[i].OriginalPteValue;
__invlpg(m_HookInfo[i].OriginalAddress);
KeLowerIrql(oldIrql);
LOG_TRACE("Restored PTE for 0x%p: 0x%llX",
m_HookInfo[i].OriginalAddress, m_HookInfo[i].OriginalPteValue);
}
}
m_HookInfo[i].IsHooked = FALSE;
LOG_INFO("Hook removed successfully");
return true;
}
}
LOG_ERROR("No matching hook found");
return false;
}
PteHookManager::~PteHookManager() {
if (m_TrampLinePool) {
MmFreeContiguousMemory(m_TrampLinePool);
m_TrampLinePool = nullptr;
LOG_INFO("Trampoline pool freed");
}
}
PteHookManager* PteHookManager::GetInstance() {
if (!m_Instance) {
m_Instance = static_cast<PteHookManager*>(
ExAllocatePoolWithTag(NonPagedPool, sizeof(PteHookManager), 'tpHk'));
if (m_Instance) {
RtlZeroMemory(m_Instance, sizeof(PteHookManager));
LOG_INFO("PTE Hook Manager instance created: 0x%p", m_Instance);
}
else {
LOG_ERROR("Failed to create PTE Hook Manager instance");
}
}
return m_Instance;
}
// 全局PTE Hook管理器实例
PteHookManager* g_PteHookManager = nullptr;
// 目标进程名称
const char target_process_name[] = "oxygen.exe";
// 辅助函数:检查是否为目标进程
BOOLEAN IsTargetProcess(CHAR* imageName) {
CHAR currentName[16];
RtlZeroMemory(currentName, sizeof(currentName));
strncpy(currentName, imageName, sizeof(currentName) - 1);
return (_stricmp(currentName, target_process_name) == 0);
}
// 函数类型定义
typedef NTSTATUS(*fn_ObReferenceObjectByHandleWithTag)(
HANDLE Handle,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
ULONG Tag,
PVOID* Object,
POBJECT_HANDLE_INFORMATION HandleInformation
);
fn_ObReferenceObjectByHandleWithTag g_OriginalObReferenceObjectByHandleWithTag = nullptr;
// Hook 函数
NTSTATUS MyObReferenceObjectByHandleWithTag(
HANDLE Handle,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
ULONG Tag,
PVOID* Object,
POBJECT_HANDLE_INFORMATION HandleInformation
) {
PEPROCESS currentProcess = PsGetCurrentProcess();
CHAR* imageName = PsGetProcessImageFileName(currentProcess);
LOG_INFO("Hook function called by process: %s", imageName);
if (IsTargetProcess(imageName)) {
LOG_INFO("Access denied for target process: %s", imageName);
return STATUS_ACCESS_DENIED;
}
return g_OriginalObReferenceObjectByHandleWithTag(
Handle,
DesiredAccess,
ObjectType,
AccessMode,
Tag,
Object,
HandleInformation
);
}
NTSTATUS InstallHook(HANDLE targetProcessId) {
UNICODE_STRING funcName;
RtlInitUnicodeString(&funcName, L"ObReferenceObjectByHandleWithTag");
g_OriginalObReferenceObjectByHandleWithTag =
(fn_ObReferenceObjectByHandleWithTag)MmGetSystemRoutineAddress(&funcName);
if (!g_OriginalObReferenceObjectByHandleWithTag) {
LOG_ERROR("ObReferenceObjectByHandleWithTag not found");
return STATUS_NOT_FOUND;
}
LOG_INFO("Target function found: 0x%p", g_OriginalObReferenceObjectByHandleWithTag);
void* targetFunc = (void*)g_OriginalObReferenceObjectByHandleWithTag;
void* hookFunc = (void*)MyObReferenceObjectByHandleWithTag;
if (!g_PteHookManager->fn_pte_inline_hook_bp_pg(targetProcessId, &targetFunc, hookFunc)) {
LOG_ERROR("PTE Hook installation failed");
return STATUS_UNSUCCESSFUL;
}
g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)targetFunc;
LOG_INFO("Hook installed successfully. Trampoline: 0x%p", targetFunc);
return STATUS_SUCCESS;
}
// 移除 Hook
VOID RemoveHook() {
if (g_OriginalObReferenceObjectByHandleWithTag && g_PteHookManager) {
g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(),
(void*)MyObReferenceObjectByHandleWithTag);
}
}
// 工作线程上下文
typedef struct _HOOK_THREAD_CONTEXT {
HANDLE TargetProcessId;
} HOOK_THREAD_CONTEXT, * PHOOK_THREAD_CONTEXT;
// 工作线程函数
VOID InstallHookWorker(PVOID Context) {
PHOOK_THREAD_CONTEXT ctx = (PHOOK_THREAD_CONTEXT)Context;
if (ctx) {
LOG_INFO("Installing hook for PID: %d", HandleToUlong(ctx->TargetProcessId));
InstallHook(ctx->TargetProcessId);
ExFreePoolWithTag(ctx, 'CtxH');
}
PsTerminateSystemThread(STATUS_SUCCESS);
}
// 进程创建回调 - 修正后的签名
VOID ProcessNotifyCallback(
_In_ PEPROCESS Process,
_In_ HANDLE ProcessId,
_In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
) {
if (CreateInfo != NULL) { // 进程创建
CHAR* imageName = PsGetProcessImageFileName(Process);
if (IsTargetProcess(imageName)) {
LOG_INFO("Target process created: %s (PID: %d)",
imageName, HandleToUlong(ProcessId));
// 创建工作线程上下文
PHOOK_THREAD_CONTEXT ctx =
(PHOOK_THREAD_CONTEXT)ExAllocatePoolWithTag(NonPagedPool, sizeof(HOOK_THREAD_CONTEXT), 'CtxH');
if (ctx) {
ctx->TargetProcessId = ProcessId;
HANDLE threadHandle;
NTSTATUS status = PsCreateSystemThread(
&threadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
InstallHookWorker,
ctx
);
if (NT_SUCCESS(status)) {
ZwClose(threadHandle);
LOG_INFO("Worker thread created for hook installation");
}
else {
ExFreePoolWithTag(ctx, 'CtxH');
LOG_ERROR("Failed to create worker thread: 0x%X", status);
}
}
else {
LOG_ERROR("Failed to allocate thread context");
}
}
}
}
// 驱动卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
LOG_INFO("Driver unloading...");
// 移除进程通知回调
PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallback, TRUE);
// 移除Hook
RemoveHook();
// 清理PTE Hook资源
if (g_PteHookManager) {
LOG_INFO("Cleaning up PTE Hook Manager");
// 恢复所有被修改的G位
g_PteHookManager->fn_resume_global_bits(nullptr);
// 移除所有活动的Hook
HOOK_INFO* hookInfo = g_PteHookManager->GetHookInfo();
UINT32 hookCount = g_PteHookManager->GetHookCount();
for (UINT32 i = 0; i < hookCount; i++) {
if (hookInfo[i].IsHooked) {
g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), hookInfo[i].HookAddress);
}
}
// 释放管理器实例
ExFreePoolWithTag(g_PteHookManager, 'tpHk');
g_PteHookManager = nullptr;
}
LOG_INFO("Driver unloaded successfully");
}
extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
LOG_INFO("Driver loading...");
DriverObject->DriverUnload = DriverUnload;
g_PteHookManager = PteHookManager::GetInstance();
if (!g_PteHookManager) {
LOG_ERROR("Failed to initialize PteHookManager");
return STATUS_INSUFFICIENT_RESOURCES;
}
NTSTATUS status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallback, FALSE);
if (!NT_SUCCESS(status)) {
LOG_ERROR("Failed to register process callback: 0x%X", status);
return status;
}
LOG_INFO("Driver loaded successfully");
return STATUS_SUCCESS;
}
严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息
错误(活动) E0020 未定义标识符 "极" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 51
错误(活动) E0276 后面有“::”的名称一定是类名或命名空间名 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 203
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 276
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 349
错误(活动) E0020 未定义标识符 "Low极" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 360
错误(活动) E0020 未定义标识符 "VaPd极" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 368
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 508
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 524
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 541
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 549
错误(活动) E0020 未定义标识符 "m_HookInfo极i" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636
错误(活动) E0065 应输入“;” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636
错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 687
错误 C2065 “极”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 51
错误 C2653 “P极HookManager”: 不是类或命名空间名称 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 203
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 276
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 349
错误 C2065 “Low极”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 360
错误 C3536 “VaPt”: 初始化之前无法使用 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 364
错误 C2664 “void MmFreeContiguousMemory(PVOID)”: 无法将参数 1 从“int”转换为“PVOID” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 365
错误 C2065 “VaPd极”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 368
错误 C2664 “void MmFreeContiguousMemory(PVOID)”: 无法将参数 1 从“int”转换为“PVOID” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 377
错误 C2664 “void *memcpy(void *,const void *,size_t)”: 无法将参数 1 从“int”转换为“void *” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 394
错误 C2664 “void *memcpy(void *,const void *,size_t)”: 无法将参数 1 从“int”转换为“void *” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 397
错误 C2664 “UINT64 PteHookManager::fn_va_to_pa(void *)”: 无法将参数 1 从“int”转换为“void *” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 409
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 508
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 524
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 541
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 549
错误 C2065 “m_HookInfo极i”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636
错误 C2143 语法错误: 缺少“;”(在“]”的前面) obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636
错误 C2059 语法错误:“]” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636
错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 687
最新发布