调用 PluginBase / Call

Call / CallDyn / Method / VMT 选型与基址

shared/PluginBase.h · 命名空间 plugin

优先顺序:已有 C++ 封装 → Command → Call → 最后才 patch

场景选用
编译期已知地址、cdeclCall / CallAndReturn
thiscallCallMethod / CallMethodAndReturn
运行时才有地址(Pattern / 重定位)CallDyn*
地址已是绝对、不要再加基址*DynGlobal
虚表槽CallVirtualMethod*

编译期地址 → Call*
运行时地址 → CallDyn*(多数配合 GetGlobalAddress / Pattern)
*DynGlobal 不做重定位

不要在这些时机 Call 游戏逻辑

静态构造 / DllMain / 对象池尚未建立 / 设备 Lost 之后继续画或调渲染相关逻辑。

无返回 cdecl

Call
编译期地址 · cdecl

无返回的 cdecl 调用。addressvoid(__cdecl*)(Args...) 解释。调用约定错误会破坏栈。固定 RVA 换游戏版本通常要更新,或改用 Pattern + CallDyn

template <uintptr_t address, typename... Args>
void Call(Args... args);

有返回 cdecl

CallAndReturn
编译期地址 · cdecl

Ret 写在模板参数最前。

template <typename Ret, uintptr_t address, typename... Args>
Ret CallAndReturn(Args... args);

stdcall

CallStd / CallStdAndReturn
编译期地址 · stdcall

游戏内多数并不是 stdcall,确认约定后再用。

template <uintptr_t address, typename... Args>
void CallStd(Args... args);

template <typename Ret, uintptr_t address, typename... Args>
Ret CallStdAndReturn(Args... args);

thiscall 方法

CallMethod / CallMethodAndReturn
编译期地址 · thiscall

第一个参数是 this,必须有效。

template <uintptr_t address, typename C, typename... Args>
void CallMethod(C _this, Args... args);

template <typename Ret, uintptr_t address, typename C, typename... Args>
Ret CallMethodAndReturn(C _this, Args... args);

虚表方法

CallVirtualMethod / CallVirtualMethodAndReturn
虚表下标

模板参数是虚表 下标,不是函数地址。下标错误几乎必崩。

template <uintptr_t tableIndex, typename C, typename... Args>
void CallVirtualMethod(C _this, Args... args);

template <typename Ret, uintptr_t tableIndex, typename C, typename... Args>
Ret CallVirtualMethodAndReturn(C _this, Args... args);

运行时地址 cdecl

CallDyn / CallAndReturnDyn
运行时 · cdecl · 重定位

内部会做重定位。地址为 0 时不要调用。

template <typename... Args>
void CallDyn(uintptr_t address, Args... args);

template <typename Ret, typename... Args>
Ret CallAndReturnDyn(uintptr_t address, Args... args);

运行时地址 stdcall

CallStdDyn / CallStdAndReturnDyn
template <typename... Args>
void CallStdDyn(uintptr_t address, Args... args);

template <typename Ret, typename... Args>
Ret CallStdAndReturnDyn(uintptr_t address, Args... args);

运行时地址 thiscall

CallMethodDyn / CallMethodAndReturnDyn
template <typename C, typename... Args>
void CallMethodDyn(uintptr_t address, C _this, Args... args);

template <typename Ret, typename C, typename... Args>
Ret CallMethodAndReturnDyn(uintptr_t address, C _this, Args... args);

绝对地址 cdecl

CallDynGlobal / CallAndReturnDynGlobal
绝对地址 · 不重定位
template <typename... Args>
void CallDynGlobal(uintptr_t address, Args... args);

template <typename Ret, typename... Args>
Ret CallAndReturnDynGlobal(uintptr_t address, Args... args);

绝对地址 thiscall

CallMethodDynGlobal / CallMethodAndReturnDynGlobal
template <typename C, typename... Args>
void CallMethodDynGlobal(uintptr_t address, C _this, Args... args);

template <typename Ret, typename C, typename... Args>
Ret CallMethodAndReturnDynGlobal(uintptr_t address, C _this, Args... args);

取虚表

GetVMT

取虚表指针,或某一槽位。

inline void** GetVMT(const void* self);
inline void* GetVMT(const void* self, size_t index);

基址与绝对地址

GetBaseAddress / GetGlobalAddress
DynAddress.h

模块基址;RVA → 绝对地址。

uintptr_t GetBaseAddress();
uintptr_t GetGlobalAddress(uintptr_t address);

分配与释放

operator_new / operator_delete 族

等价于 new / delete,必须成对使用。

template <typename ClassType, typename... ArgTypes>
ClassType* operator_new(ArgTypes... args);

template <typename ClassType>
ClassType* operator_new_array(size_t size);

template <typename ClassType>
void operator_delete(ClassType* data);

template <typename ClassType>
void operator_delete_array(ClassType* data);

栈上临时对象

stack_object
template <typename T>
struct stack_object {
    template <typename... ArgTypes>
    stack_object(ArgTypes... args);
    T* operator->();
    T& get_object();
};

SDK 版本

Core::GetVersion
namespace Core {
    PLUGIN_API unsigned int GetVersion();
}

跨游戏取值

BY_GAME

按当前工程宏取三端之一。

BY_GAME(iii_val, vc_val, sa_val)

On this page