bool PLH::VEHHook::Hook() { //Lock the TargetMutex for thread safe vector operations std::lock_guard<std::mutex> m_Lock(m_TargetMutex); if (m_ThisCtx.m_Type == VEHMethod::INT3_BP) { //Write INT3 BreakPoint MemoryProtect Protector(m_ThisCtx.m_Src, 1, PAGE_EXECUTE_READWRITE); m_ThisCtx.m_OriginalByte = *m_ThisCtx.m_Src; *m_ThisCtx.m_Src = 0xCC; m_HookTargets.push_back(m_ThisCtx); }else if (m_ThisCtx.m_Type == VEHMethod::GUARD_PAGE){ //Read current page protection MEMORY_BASIC_INFORMATION mbi; VirtualQuery(m_ThisCtx.m_Src, &mbi, sizeof(mbi)); //can't use Page Guards with NO_ACCESS flag if (mbi.Protect & PAGE_NOACCESS) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook VEH: Cannot hook page with NOACCESS Flag")); return false; } if (AreInSamePage((BYTE*)&PLH::VEHHook::VEHHandler, m_ThisCtx.m_Src)) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook VEH: Cannot hook page on same page as the VEH")); return false; } //!!!!COMPILER SPECIFIC HACK HERE!!!!! bool(PLH::VEHHook::* pHookFunc)(void) = &PLH::VEHHook::Hook; if (AreInSamePage((BYTE*&)pHookFunc, m_ThisCtx.m_Src)) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook VEH: Cannot hook page on same page as the hooking function")); return false; } m_HookTargets.push_back(m_ThisCtx); //Write Page Guard protection DWORD OldProtection; VirtualProtect(m_ThisCtx.m_Src, 1 ,PAGE_EXECUTE_READWRITE | PAGE_GUARD, &OldProtection); } return true; }
LONG CALLBACK PLH::VEHHook::VEHHandler(EXCEPTION_POINTERS* ExceptionInfo) { #ifdef _WIN64 #define XIP Rip #else #define XIP Eip #endif // _WIN64 std::lock_guard<std::mutex> m_Lock(m_TargetMutex); DWORD ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode; if (ExceptionCode == EXCEPTION_BREAKPOINT) { for (HookCtx& Ctx : m_HookTargets) { if(Ctx.m_Type != VEHMethod::INT3_BP) continue; //Are we at a breakpoint that we placed? if (ExceptionInfo->ContextRecord->XIP != (DWORD_PTR)Ctx.m_Src) continue; //Remove Int3 Breakpoint MemoryProtect Protector(Ctx.m_Src, 1, PAGE_EXECUTE_READWRITE); *Ctx.m_Src = Ctx.m_OriginalByte; //Set instruction pointer to our callback ExceptionInfo->ContextRecord->XIP = (DWORD_PTR) Ctx.m_Dest; return EXCEPTION_CONTINUE_EXECUTION; } }else if (ExceptionCode == EXCEPTION_GUARD_PAGE) { for (HookCtx& Ctx : m_HookTargets) { //still need to check if exception is in our page if (Ctx.m_Type != VEHMethod::GUARD_PAGE) continue; if(!AreInSamePage((BYTE*)ExceptionInfo->ContextRecord->XIP,Ctx.m_Src)) continue; if (ExceptionInfo->ContextRecord->XIP == (DWORD_PTR)Ctx.m_Src) ExceptionInfo->ContextRecord->XIP = (DWORD_PTR)Ctx.m_Dest; return EXCEPTION_CONTINUE_EXECUTION; } } return EXCEPTION_CONTINUE_SEARCH; }
bool PLH::VEHHook::Hook() { //Lock the TargetMutex for thread safe vector operations std::lock_guard<std::mutex> m_Lock(m_TargetMutex); if (m_ThisCtx.m_Type == VEHMethod::INT3_BP) { //Write INT3 BreakPoint MemoryProtect Protector(m_ThisCtx.m_Src, 1, PAGE_EXECUTE_READWRITE); m_ThisCtx.m_StorageByte = *m_ThisCtx.m_Src; *m_ThisCtx.m_Src = 0xCC; m_HookTargets.push_back(m_ThisCtx); }else if (m_ThisCtx.m_Type == VEHMethod::HARDWARE_BP) { CONTEXT Ctx; Ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; if (!GetThreadContext(GetCurrentThread(), &Ctx)) { PostError(PLH::RuntimeError(RuntimeError::Severity::Critical, "Failed to get context")); return false; } uint8_t RegIndex = 0; bool FoundReg = false; for (; RegIndex < 4; RegIndex++) { if ((Ctx.Dr7 & (1 << (RegIndex * 2))) == 0) { FoundReg = true; break; } } if (!FoundReg) { PostError(PLH::RuntimeError(RuntimeError::Severity::Critical, "Failed to find free Reg")); return false; } switch (RegIndex) { case 0: Ctx.Dr0 = (DWORD_PTR)m_ThisCtx.m_Src; break; case 1: Ctx.Dr1 = (DWORD_PTR)m_ThisCtx.m_Src; break; case 2: Ctx.Dr2 = (DWORD_PTR)m_ThisCtx.m_Src; break; case 3: Ctx.Dr3 = (DWORD_PTR)m_ThisCtx.m_Src; break; default: PostError(PLH::RuntimeError(RuntimeError::Severity::Critical, "PolyHook VEH: Invalid Debug Register Index")); return false; } //Turn a local register on Ctx.Dr7 |= 1 << (2*RegIndex); m_ThisCtx.m_StorageByte = RegIndex; //Still need to call suspend thread *TODO* if (!SetThreadContext(GetCurrentThread(), &Ctx)) { PostError(PLH::RuntimeError(RuntimeError::Severity::Critical, "PolyHook VEH: Failed to set thread context")); return false; } m_HookTargets.push_back(m_ThisCtx); }else if (m_ThisCtx.m_Type == VEHMethod::GUARD_PAGE){ //Read current page protection MEMORY_BASIC_INFORMATION mbi; VirtualQuery(m_ThisCtx.m_Src, &mbi, sizeof(mbi)); //can't use Page Guards with NO_ACCESS flag if (mbi.Protect & PAGE_NOACCESS) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook VEH: Cannot hook page with NOACCESS Flag")); return false; } if (AreInSamePage((BYTE*)&PLH::VEHHook::VEHHandler, m_ThisCtx.m_Src)) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook VEH: Cannot hook page on same page as the VEH")); return false; } //!!!!COMPILER SPECIFIC HACK HERE!!!!! bool(PLH::VEHHook::* pHookFunc)(void) = &PLH::VEHHook::Hook; if (AreInSamePage((BYTE*&)pHookFunc, m_ThisCtx.m_Src)) { PostError(RuntimeError(RuntimeError::Severity::UnRecoverable, "PolyHook VEH: Cannot hook page on same page as the hooking function")); return false; } m_HookTargets.push_back(m_ThisCtx); //Write Page Guard protection DWORD OldProtection; VirtualProtect(m_ThisCtx.m_Src, 1 ,PAGE_EXECUTE_READWRITE | PAGE_GUARD, &OldProtection); } return true; }