如何使用subhook替换C++类成员函数?(传递类函数指针)
使用subhook替换C++类成员函数的问题
我已经成功用subhook替换独立函数,示例代码如下:
#include <iostream> #include "subhook/subhook.h" std::string TestFx() {return "TEST";} std::string ReplaceFx() {return "REPLACED";} subhook_t testHook; subhook_flags_t testHookFlags; int main() { std::cout << "Normal: " << TestFx() << "\n"; testHook = subhook_new(&TestFx, &ReplaceFx, testHookFlags); subhook_install(testHook); std::cout << "Replaced: " << TestFx() << "\n"; subhook_remove(testHook); std::cout << "Reverted: " << TestFx() << "\n"; return 0; }
运行结果正常:
Normal: TEST Replaced: REPLACED Reverted: TEST
但替换类成员函数时遇到困难,无法直接将类函数传入subhook_install。尝试的示例代码:
#include <iostream> #include "subhook/subhook.h" class TestClass { public: std::string TestFx() {return "TEST";} }; std::string ReplaceFx() {return "REPLACED";} subhook_t testHook; subhook_flags_t testHookFlags; int main() { TestClass* tc = new TestClass(); std::cout << "Normal: " << tc->TestFx() << "\n"; testHook = subhook_new(&TestClass::TestFx, &ReplaceFx, testHookFlags); subhook_install(testHook); std::cout << "Replaced: " << tc->TestFx() << "\n"; subhook_remove(testHook); std::cout << "Reverted: " << tc->TestFx() << "\n"; delete tc; return 0; }
出现错误:
E0167 argument of type "std::string (TestClass::*)()" is incompatible with parameter of type "void *"
尝试用reinterpret_cast转换时:
E0171 invalid type conversion
我理解原因是类成员函数指针通常比普通函数指针更大,无法放入void*类型,但subhook仅接受void*参数。请问使用subhook替换类成员函数的正确方法是什么?是否有其他类似库可完成此任务?
解决方法
1. 处理非虚成员函数
对于非虚成员函数,需先将成员函数指针转换为匹配的原始函数指针类型(成员函数会隐式接收this指针作为第一个参数),再转为void*传入subhook:
#include <iostream> #include "subhook/subhook.h" class TestClass { public: std::string TestFx() {return "TEST";} }; // 替换函数需匹配成员函数的实际调用签名:第一个参数为this指针 std::string ReplaceFx(TestClass* this_ptr) {return "REPLACED";} // 定义匹配成员函数的指针类型 using MemberFuncPtr = std::string (TestClass::*)(); using RawFuncPtr = std::string (*)(TestClass*); subhook_t testHook; subhook_flags_t testHookFlags = 0; int main() { TestClass* tc = new TestClass(); std::cout << "Normal: " << tc->TestFx() << "\n"; // 转换成员函数指针为原始函数指针,再转为void* RawFuncPtr raw_func = reinterpret_cast<RawFuncPtr>(&TestClass::TestFx); testHook = subhook_new(reinterpret_cast<void*>(raw_func), reinterpret_cast<void*>(&ReplaceFx), testHookFlags); subhook_install(testHook); std::cout << "Replaced: " << tc->TestFx() << "\n"; subhook_remove(testHook); std::cout << "Reverted: " << tc->TestFx() << "\n"; delete tc; return 0; }
注:这种转换依赖编译器实现,主流编译器(GCC、Clang、MSVC)均支持,但属于C++标准未定义行为的边缘场景,需自行验证兼容性。
2. 处理虚成员函数
如果是虚成员函数,需通过修改类的虚表实现挂钩:
#include <iostream> #include "subhook/subhook.h" class TestClass { public: virtual std::string TestFx() {return "TEST";} }; std::string ReplaceFx(TestClass* this_ptr) {return "REPLACED";} subhook_t testHook; int main() { TestClass* tc = new TestClass(); std::cout << "Normal: " << tc->TestFx() << "\n"; // 获取虚表指针(主流编译器中虚表是对象的第一个成员) void** vtable = *reinterpret_cast<void***>(tc); // 虚表中第一个条目对应TestFx(需根据实际虚函数顺序调整索引) void* target_func = vtable[0]; testHook = subhook_new(target_func, reinterpret_cast<void*>(&ReplaceFx), 0); subhook_install(testHook); std::cout << "Replaced: " << tc->TestFx() << "\n"; subhook_remove(testHook); std::cout << "Reverted: " << tc->TestFx() << "\n"; delete tc; return 0; }
注:虚表布局依赖编译器实现,需根据类的虚函数顺序调整索引值。
3. 替代库
若subhook的使用限制较多,可考虑以下更适配C++成员函数挂钩的库:
- MinHook:轻量级跨平台挂钩库,社区案例丰富,处理成员函数时同样需指针转换,但文档更完善。
- Detours:微软官方挂钩库,对Windows平台支持最优,专门针对API和成员函数设计,使用更规范。
- Frida:动态插桩工具,支持多平台,无需编译时修改代码,适合动态分析场景。
内容的提问来源于stack exchange,提问作者Runsva
相关产品推荐
相关产品推荐

