ur::vmt_hook 提供了一种专门用于 Hook C++ 对象虚函数表(VMT/VTable)的机制。通过替换虚函数表中的函数指针,可以重定向一个或多个虚函数的调用,同时仍然能够调用原始的虚函数实现。
这对于修改或扩展一个类的特定虚函数行为非常有用,尤其是在处理复杂的类继承体系时。
- 面向对象: API 设计直观,直接对类实例进行操作。
- 多重 Hook: 支持对同一个虚函数表中的多个不同虚函数进行 Hook。
- Hook 链: 与
inline_hook类似,对同一个虚函数进行多次 Hook 会形成一个调用链。 - RAII 管理:
VmtHook管理整个虚函数表的 Hook 会话,而VmHook管理单个虚函数的 Hook。它们的生命周期决定了 Hook 的安装与卸载。 - 调用原始函数:
VmHook提供了get_original方法来获取并调用原始的虚函数。
管理一个对象实例的整个虚函数表 Hook 的主类。
explicit VmtHook(void* instance);instance: 指向要 Hook 的类实例的指针。
explicit VmtHook(void** vmt_address);vmt_address: 指向虚函数表(VMT)的指针。这为直接通过虚函数表地址进行 Hook 提供了另一种方式。
Hook 虚函数表中的一个特定函数。
index: 虚函数在虚函数表中的索引(从 0 开始)。hook_function: 用于替换原始虚函数的新的函数指针。- 返回值: 返回一个
std::unique_ptr<VmHook>,代表这个特定的 Hook。如果 Hook 失败,则返回nullptr。
代表一个被 Hook 的单个虚函数。
获取原始虚函数的函数指针,以便在 Hook 函数中调用它。
T: 原始虚函数的函数指针类型。
与 inline_hook 中的方法功能相同,用于控制单个虚函数 Hook 的状态。
这个例子展示了如何 Hook 一个类的虚函数,并在 Hook 函数中调用原始实现。
#include <ur/vmt_hook.h>
#include <iostream>
#include <memory>
// 目标类
class Calculator {
public:
virtual int calculate(int a, int b) {
return a + b;
}
};
// 全局的 VmHook 句柄,以便在 Hook 函数中访问
std::unique_ptr<ur::VmHook> g_vm_hook;
// Hook 函数,签名需要匹配原始函数(并额外接收一个 this 指针)
int hooked_calculate(Calculator* self, int a, int b) {
std::cout << "Hooked calculate called." << std::endl;
// 获取原始函数指针
auto original_func = g_vm_hook->get_original<int (*)(Calculator*, int, int)>();
// 调用原始函数
int original_result = original_func(self, a, b);
// 修改结果
return original_result * 10;
}
void vmt_hook_example() {
Calculator calc;
Calculator* calc_ptr = &calc; // 必须使用指针以确保虚函数调用
ur::VmtHook vmt_hook(calc_ptr);
// Hook `calculate` 函数,它在虚函数表中的索引为 0
g_vm_hook = vmt_hook.hook_method(0, reinterpret_cast<void*>(&hooked_calculate));
if (g_vm_hook) {
std::cout << "VMT Hook successful." << std::endl;
// 原始结果: 5 + 3 = 8
// Hook 后结果: 8 * 10 = 80
int result = calc_ptr->calculate(5, 3);
std::cout << "Result: " << result << std::endl;
}
// 当 g_vm_hook 和 vmt_hook 离开作用域时,Hook 会被自动移除
}与 inline_hook 类似,对同一个虚函数进行多次 Hook 会形成一个调用链。
#include <ur/vmt_hook.h>
#include <iostream>
#include <memory>
// ... (Calculator 类定义同上)
std::unique_ptr<ur::VmHook> g_hook_a, g_hook_b;
// Hook A: 加法
int hook_a(Calculator* self, int a, int b) {
auto original = g_hook_a->get_original<int (*)(Calculator*, int, int)>();
return original(self, a, b) + 10;
}
// Hook B: 乘法
int hook_b(Calculator* self, int a, int b) {
auto original = g_hook_b->get_original<int (*)(Calculator*, int, int)>();
return original(self, a, b) * 2;
}
void vmt_chain_hook_example() {
Calculator calc;
ur::VmtHook vmt_hook(&calc);
// 先安装 Hook A
g_hook_a = vmt_hook.hook_method(0, reinterpret_cast<void*>(&hook_a));
// 再安装 Hook B
g_hook_b = vmt_hook.hook_method(0, reinterpret_cast<void*>(&hook_b));
// 调用顺序: hook_b -> hook_a -> original_calculate
// 计算过程: ((5 + 3) + 10) * 2 = 36
int result = calc.calculate(5, 3);
std::cout << "Chained VMT hook result: " << result << std::endl;
// 卸载 Hook B
g_hook_b.reset();
// 剩下 Hook A
// 计算过程: (5 + 3) + 10 = 18
result = calc.calculate(5, 3);
std::cout << "After unhooking B: " << result << std::endl;
}