You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:07:33