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

如何用C++模板实现Detours钩子的宏序列逻辑?

用C++模板替代Detours钩子宏实现方案

现有宏实现代码

钩子函数定义

SETUP_ORIG_FUNC(string_copy_n);
char* __cdecl HOOK(string_copy_n)(char* dst, const char* src, size_t size)
{
  if (src && dst && size && !convert_ulong_lock && Config::Setting::enable_translation) {
    auto tstr = Dictionary::GetSingleton()->Get(src);
    if (tstr) {
      return ORIGINAL(string_copy_n)(dst, tstr.value().c_str(), tstr.value().size());
    }
  }
  return ORIGINAL(string_copy_n)(dst, src, size);
}

宏定义与类型别名

#define SETUP_ORIG_FUNC(fn_name) fn_name fn_name##_orig = (fn_name)(module_handle + Config::Offset::fn_name);
#define HOOK(fn_name) fn_name##_hook
#define ORIGINAL(fn_name) fn_name##_orig

typedef char*(__cdecl* string_copy_n)(char* dst, const char* src, size_t size);

模板化解决方案

核心模板类实现

这个模板类封装了原始函数指针的初始化与调用,兼顾类型安全与效率:

#include <utility> // 用于std::forward

template<typename FuncType, uintptr_t Offset>
struct OriginalFunction {
    // 静态存储原始函数指针,仅初始化一次
    static inline FuncType ptr = nullptr;

    // 初始化函数:从模块基址+偏移量获取函数指针
    static void Init(void* module_handle) {
        if (!ptr) {
            uintptr_t module_base = reinterpret_cast<uintptr_t>(module_handle);
            ptr = reinterpret_cast<FuncType>(module_base + Offset);
        }
    }

    // 调用原始函数,完美转发参数
    template<typename... Args>
    static auto Call(Args&&... args) -> decltype(ptr(std::forward<Args>(args)...)) {
        return ptr(std::forward<Args>(args)...);
    }
};

使用方式

  1. 定义函数类型(替代原typedef):
using string_copy_n = char*(__cdecl*)(char* dst, const char* src, size_t size);
  1. 初始化原始函数指针:
    在模块加载完成后调用Init:
OriginalFunction<string_copy_n, Config::Offset::string_copy_n>::Init(module_handle);
  1. 编写钩子函数:
char* __cdecl string_copy_n_hook(char* dst, const char* src, size_t size) {
    if (src && dst && size && !convert_ulong_lock && Config::Setting::enable_translation) {
        auto tstr = Dictionary::GetSingleton()->Get(src);
        if (tstr) {
            return OriginalFunction<string_copy_n, Config::Offset::string_copy_n>::Call(
                dst, tstr.value().c_str(), tstr.value().size()
            );
        }
    }
    return OriginalFunction<string_copy_n, Config::Offset::string_copy_n>::Call(dst, src, size);
}

简化调用的优化

如果觉得OriginalFunction<...>::Call太长,可以用一个简洁的宏辅助(仅用于简化书写,不破坏类型安全):

#define CALL_ORIGINAL(FuncType, Offset) OriginalFunction<FuncType, Offset>::Call

钩子函数里的调用就可以简化为:

return CALL_ORIGINAL(string_copy_n, Config::Offset::string_copy_n)(dst, src, size);

原模板尝试的问题分析

你之前的模板代码错误在于:直接将module_handle + offset转换为返回值类型Ret,而非函数指针类型。函数调用需要的是对应签名的函数指针,而非返回值类型的实例,因此会导致编译错误。

模板实现的优势

  • 类型安全:编译时就能检查函数签名是否匹配,避免宏拼接带来的拼写错误或类型不匹配问题
  • 可维护性:模板逻辑集中,修改时只需调整模板类,无需逐个修改宏调用
  • 效率:静态指针仅初始化一次,调用时无额外开销,和原宏实现效率一致

内容的提问来源于stack exchange,提问作者shevernitskiy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 05:45:38