Last active
October 29, 2018 10:09
-
-
Save Midi12/734b9e6e2cc5ed02f0ffa95458d27ba3 to your computer and use it in GitHub Desktop.
Quick x64 virtual function hook class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include "VMTHook.h" | |
class Test { | |
public: | |
virtual int Add(int a, int b); | |
}; | |
int Test::Add(int a, int b) { | |
return a + b; | |
} | |
int hook(int a, int b) { | |
std::cout << "hook called !! "; | |
return 42; | |
} | |
int main() { | |
Test *test = new Test(); | |
Detour::VMTHook *hk = new Detour::VMTHook(reinterpret_cast<std::uintptr_t **>(test), 0, reinterpret_cast<std::uintptr_t>(&hook)); | |
std::cout << "orig result " << std::to_string(test->Add(12, 9)) << std::endl; | |
hk->Apply(); | |
std::cout << "hooked result " << std::to_string(test->Add(12, 9)) << std::endl; | |
std::cout << "orig result (call original) " << std::to_string(hk->CallOriginal<int>(12, 9)) << std::endl; | |
hk->Restore(); | |
std::cout << "restored result " << std::to_string(test->Add(12, 9)) << std::endl; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "VMTHook.h" | |
namespace Detour { | |
/* | |
* Constructor | |
*/ | |
VMTHook::VMTHook(std::uintptr_t** vtable, const std::uint16_t index, std::uintptr_t hook) | |
: _vtable(vtable), _index(index), _ptr(hook), _orig(0) { | |
assert(vtable != nullptr); | |
assert(index >= 0); | |
assert(hook != 0); | |
} | |
/* | |
* Apply hook in memory if not already applied | |
*/ | |
bool VMTHook::Apply(void) { | |
if (!IsApplied()) { | |
DWORD old; | |
_orig = (*_vtable)[_index]; | |
VirtualProtect(&((*_vtable)[_index]), sizeof(std::uintptr_t), PAGE_READWRITE, &old); | |
(*_vtable)[_index] = _ptr; | |
VirtualProtect(&((*_vtable)[_index]), sizeof(std::uintptr_t), old, &old); | |
return true; | |
} | |
return false; | |
} | |
/* | |
* Restore original function pointer in memory if applied | |
*/ | |
bool VMTHook::Restore(void) { | |
if (IsApplied()) { | |
DWORD old; | |
VirtualProtect(&((*_vtable)[_index]), sizeof(std::uintptr_t), PAGE_READWRITE, &old); | |
(*_vtable)[_index] = _orig; | |
VirtualProtect(&((*_vtable)[_index]), sizeof(std::uintptr_t), old, &old); | |
return true; | |
} | |
return false; | |
} | |
/* | |
* Returns true if the hook is applied in memory | |
*/ | |
bool VMTHook::IsApplied(void) { | |
return IsValid() && (*_vtable)[_index] == _ptr; | |
} | |
/* | |
* Returns true if hook data are valid | |
*/ | |
bool VMTHook::IsValid(void) { | |
return _vtable != nullptr && (*_vtable) != nullptr && _index >= 0; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include <cassert> | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
namespace Detour { | |
/* | |
* Virtual function table hooking class | |
* Only designed to works on x64 (passing `this` as first argument) | |
*/ | |
class VMTHook { | |
public: | |
VMTHook() = delete; | |
VMTHook(std::uintptr_t** vtable, const std::uint16_t index, std::uintptr_t hook); | |
VMTHook(const VMTHook& other) = delete; | |
VMTHook& operator=(const VMTHook& other) = delete; | |
VMTHook(VMTHook&& other) = default; | |
VMTHook& operator=(VMTHook&& other) = default; | |
~VMTHook() = default; | |
bool Apply(void); | |
bool Restore(void); | |
bool IsApplied(void); | |
bool IsValid(void); | |
/* | |
* Call the original function pointer with parameters | |
* Automatically pass `this` pointer as first argument | |
*/ | |
template <typename ReturnType, typename ...ArgsType> | |
ReturnType CallOriginal(ArgsType&&... args) const { | |
return reinterpret_cast<ReturnType(*)(std::uintptr_t **, ArgsType ...)>(_orig)(_vtable, std::forward<ArgsType>(args)...); | |
} | |
private: | |
std::uintptr_t _ptr; | |
std::uintptr_t _orig; | |
std::uintptr_t **_vtable; | |
std::uint16_t _index; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment