From 18e0fc7cfa3178e8ff11ccbb8f778b25a19fca4f Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Fri, 27 Jan 2023 03:52:37 +0100 Subject: [PATCH] use hooking logic from AngriestSCV's fork --- OpenVR-SpaceCalibratorDriver/Hooking.h | 69 ++++++++++++------- .../InterfaceHookInjector.cpp | 6 +- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/OpenVR-SpaceCalibratorDriver/Hooking.h b/OpenVR-SpaceCalibratorDriver/Hooking.h index da116ca..7d7a773 100644 --- a/OpenVR-SpaceCalibratorDriver/Hooking.h +++ b/OpenVR-SpaceCalibratorDriver/Hooking.h @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include class IHook { @@ -24,46 +27,66 @@ class IHook static std::map hooks; }; -template +template class Hook : public IHook { + void * obj = nullptr; + int offset = 0; + public: + FuncType originalFunc = nullptr; Hook(const std::string &name) : IHook(name) { } - - bool CreateHookInObjectVTable(void *object, int vtableOffset, R(*detourFunction)(Args...)) + + template + bool CreateHookInObjectVTable(void *object, int vtableOffset, T* detourFunction) { - // For virtual objects, VC++ adds a pointer to the vtable as the first member. + long pageSize = sysconf(_SC_PAGESIZE); + + obj = object; + offset = vtableOffset; + // For virtual objects, VC++ (and from what I can tell gcc) adds a pointer to the vtable as the first member. // To access the vtable, we simply dereference the object. - vFunc = *((void ***)object) + vtableOffset; + void **vtable = *((void ***)object); // The vtable itself is an array of pointers to member functions, // in the order they were declared in. - originalFunc = reinterpret_cast(*vFunc); - uintptr_t startPage = reinterpret_cast(vFunc) & ~0xFFF; - uintptr_t endPage = reinterpret_cast(vFunc + sizeof(detourFunction)) & ~0xFFF; - mprotect(reinterpret_cast(reinterpret_cast(vFunc) & ~0xFFF), endPage - startPage + 4096, PROT_READ | PROT_WRITE | PROT_EXEC); - *vFunc = reinterpret_cast(detourFunction); - mprotect(reinterpret_cast(reinterpret_cast(vFunc) & ~0xFFF), endPage - startPage + 4096, PROT_EXEC); - LOG("Enabled hook for %s", name.c_str()); + originalFunc = (FuncType) vtable[vtableOffset]; + targetFunc = (void*) vtable[vtableOffset]; + + if((uintptr_t) vtable % 8 != 0 ) + { + obj = nullptr; + originalFunc = nullptr; + throw std::runtime_error("vtable entry not aligned to 8 byte pointer"); + } + + uintptr_t otherPage = (uintptr_t) vtable & ~(uintptr_t) (pageSize - 1); + int err = mprotect((void*) otherPage, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + if(err){ + LOG("Failed to set memory protection %d", err); + } + else { + //LOG("%s", "Setting vtable value"); + vtable[vtableOffset] = (void*) detourFunction; + //LOG("%s", "Resetting permissions vtable value"); + mprotect((void*) otherPage, pageSize, PROT_READ | PROT_EXEC); + } + + LOG("Enabled Linux hook for %s", name.c_str()); enabled = true; return true; } void Destroy() { - if (enabled) - { - uintptr_t startPage = reinterpret_cast(vFunc) & ~0xFFF; - uintptr_t endPage = reinterpret_cast(vFunc + sizeof(originalFunc)) & ~0xFFF; - mprotect(reinterpret_cast(reinterpret_cast(vFunc) & ~0xFFF), endPage - startPage + 4096, PROT_READ | PROT_WRITE | PROT_EXEC); - *vFunc = reinterpret_cast(originalFunc); - mprotect(reinterpret_cast(reinterpret_cast(vFunc) & ~0xFFF), endPage - startPage + 4096, PROT_EXEC); - enabled = false; - } + + //redoing it is enough if it was done the first time. + if(obj && originalFunc) CreateHookInObjectVTable(obj, offset, originalFunc); + obj = nullptr; + originalFunc = nullptr; } - R(*originalFunc)(Args...) = nullptr; private: bool enabled = false; - void **vFunc; + void* targetFunc = nullptr; }; diff --git a/OpenVR-SpaceCalibratorDriver/InterfaceHookInjector.cpp b/OpenVR-SpaceCalibratorDriver/InterfaceHookInjector.cpp index ee6988c..b74014d 100644 --- a/OpenVR-SpaceCalibratorDriver/InterfaceHookInjector.cpp +++ b/OpenVR-SpaceCalibratorDriver/InterfaceHookInjector.cpp @@ -5,13 +5,13 @@ static ServerTrackedDeviceProvider *Driver = nullptr; -static Hook +static Hook GetGenericInterfaceHook("IVRDriverContext::GetGenericInterface"); -static Hook +static Hook TrackedDevicePoseUpdatedHook005("IVRServerDriverHost005::TrackedDevicePoseUpdated"); -static Hook +static Hook TrackedDevicePoseUpdatedHook006("IVRServerDriverHost006::TrackedDevicePoseUpdated"); static void DetourTrackedDevicePoseUpdated005(vr::IVRServerDriverHost *_this, uint32_t unWhichDevice, const vr::DriverPose_t &newPose, uint32_t unPoseStructSize)