diff --git a/include/safetyhook/easy.hpp b/include/safetyhook/easy.hpp index 5379340..dab67d2 100644 --- a/include/safetyhook/easy.hpp +++ b/include/safetyhook/easy.hpp @@ -38,4 +38,12 @@ namespace safetyhook { } [[nodiscard]] VmtHook create_vmt(void* object); +[[nodiscard]] VmHook create_vm(VmtHook& vmt, size_t index, FnPtr auto destination) { + if (auto hook = vmt.hook_method(index, destination)) { + return std::move(*hook); + } else { + return {}; + } +} + } // namespace safetyhook \ No newline at end of file diff --git a/unittest/vmt_hook.cpp b/unittest/vmt_hook.cpp index e4c658a..3365ebe 100644 --- a/unittest/vmt_hook.cpp +++ b/unittest/vmt_hook.cpp @@ -297,4 +297,35 @@ TEST_CASE("Can remove an object that was previously VMT hooked", "[vmt_hook]") { REQUIRE(target0->add_42(2) == 44); REQUIRE(target1->add_42(2) == 44); REQUIRE(target2->add_42(2) == 44); -} \ No newline at end of file +} + +TEST_CASE("VMT hook an object instance with easy API", "[vmt_hook]") { + struct Interface { + virtual ~Interface() = default; + virtual int add_42(int a) = 0; + }; + + struct Target : Interface { + __declspec(noinline) int add_42(int a) override { return a + 42; } + }; + + std::unique_ptr target = std::make_unique(); + + REQUIRE(target->add_42(0) == 42); + + static SafetyHookVmt target_hook{}; + static SafetyHookVm add_42_hook{}; + + struct Hook : Target { + int hooked_add_42(int a) { return add_42_hook.thiscall(this, a) + 1337; } + }; + + target_hook = safetyhook::create_vmt(target.get()); + add_42_hook = safetyhook::create_vm(target_hook, 1, &Hook::hooked_add_42); + + REQUIRE(target->add_42(1) == 1380); + + add_42_hook.reset(); + + REQUIRE(target->add_42(2) == 44); +}